I'm having trouble with this query
CREATE VIEW qryMonthlyFeesToCollectSummary1
AS
SELECT ContractID,
Round(Sum([CreditAmount] * ( ( 1
+ COALESCE((SELECT Max(MonthlyRate)
FROM tblCases
WHERE LEFT(CaseID, 4) = [ContractID] AND CaseStatus = 'Open Case'),
0.0199) ) / 30 ) * Exp(30 - 1)), 2) AS InterestCredit
FROM tblCredits
GROUP BY tblCredits.ContractID,
(SELECT Count(*)
FROM tblInterestPayments
WHERE ContractMainID = [ContractID]
AND ( PaymentDate IS NULL
OR ( PaymentDate IS NOT NULL
AND Bounced <> 0
AND RetrySuccessful IS NULL ) ))
HAVING (SELECT Count(*)
FROM tblInterestPayments
WHERE ContractMainID = [ContractID]
AND ( PaymentDate IS NULL
OR ( PaymentDate IS NOT NULL
AND Bounced <> 0
AND RetrySuccessful IS NULL ) )) = 0;
it errors out as shown below even though it parses fine. Please help! Thanks so much!
Msg 144, Level 15, State 1, Procedure qryMonthlyFeesToCollectSummary1,
Line 11 Cannot use an aggregate or a subquery in an expression used
for the group by list of a GROUP BY clause.
Msg 130, Level 15, State 1, Procedure qryMonthlyFeesToCollectSummary1,
Line 5 Cannot perform an aggregate function on an expression
containing an aggregate or a subquery.
I think this is what you are looking for:
CREATE VIEW qryMonthlyFeesToCollectSummary1
AS
SELECT ContractID,
Round(Sum([CreditAmount] * ( ( 1
+ COALESCE((SELECT Max(MonthlyRate)
FROM tblCases
WHERE LEFT(CaseID, 4) = [ContractID] AND CaseStatus = 'Open Case'),
0.0199) ) / 30 ) * Exp(30 - 1)), 2) AS InterestCredit
FROM tblCredits
WHERE (SELECT Count(*)
FROM tblInterestPayments
WHERE ContractMainID = tblCredits.[ContractID]
AND ( PaymentDate IS NULL
OR ( PaymentDate IS NOT NULL
AND Bounced <> 0
AND RetrySuccessful IS NULL ) )) = 0
GROUP BY tblCredits.ContractID;
I think I have got it right. Try to properly alias the table names and each column used in the query.
CREATE VIEW qryMonthlyFeesToCollectSummary1
AS
SELECT tblCredits.ContractID
, Round(Sum([CreditAmount] * ( ( 1
+ COALESCE(Max(MonthlyRate) , 0.0199) ) / 30 )
* Exp(30 - 1)), 2) AS InterestCredit
FROM tblCredits
INNER JOIN tblCases ON LEFT(CaseID, 4) = [ContractID]
AND CaseStatus = 'Open Case'
INNER JOIN tblInterestPayments ON ContractMainID = [ContractID]
WHERE PaymentDate IS NULL
OR ( PaymentDate IS NOT NULL
AND Bounced <> 0
AND RetrySuccessful IS NULL )
GROUP BY tblCredits.ContractID
HAVING Count(*) = 0;
You may try the following:
SELECT
Credits.ContractID,
ROUND(SUM(Credits.CreditAmount * ( ( 1 + COALESCE(Cases.MaxMonthlyRate,0.0199) ) / 30 ) * Exp(30 - 1)), 2) AS InterestCredit
FROM
tblCredits Credits
OUTER APPLY(
SELECT
Max(Cases.MonthlyRate) MaxMonthlyRate
FROM
tblCases Cases
WHERE
LEFT(Cases.CaseID, 4) = Credits.ContractID
AND Cases.CaseStatus = 'Open Case'
)Cases
WHERE
NOT EXISTS(
SELECT NULL
FROM tblInterestPayments Payments
WHERE
Payments.ContractMainID = Credits.ContractID
AND (
Payments.PaymentDate IS NULL
OR (
Payments.PaymentDate IS NOT NULL
AND Payments.Bounced <> 0
AND Payments.RetrySuccessful IS NULL
)
)
)
GROUP BY
Credits.ContractID
The errors you are experienced are encountered when you try to use an aggregate function (MAX, MIN, AVG, etc.) inside a subquery that is inside an expression that is already using an aggregate function. The remove them, I moved that subquery out of the select clause and into an outer apply. I used a Outer apply because you tagged the questions as SQL server and the subquery is performing an aggregate. In other databases you would use a left join.
Also, I moved the tblInterestPayments subquery into a NOT EXISTS clause. Since you are checking for the non existence of rows in the table matching a criteria, this makes more sense.
try something like:
CREATE VIEW qryMonthlyFeesToCollectSummary1
AS
SELECT
ContractID,
ROUND(SUM([CreditAmount] * ( ( 1 + COALESCE(max_monthlyRate, 0.0199) ) / 30 ) *
EXP(30 - 1)), 2) AS InterestCredit
FROM
tblCredits c LEFT OUTER JOIN
(SELECT
ContractMainID
FROM
tblInterestPayments
WHERE
PaymentDate IS NULL OR
( Bounced <> 0 AND RetrySuccessful IS NULL )) i ON
c.ContractID = i.ContractMainID LEFT OUTER JOIN
(SELECT
LEFT(CaseID, 4) AS left_caseID4,
MAX(MonthlyRate) AS max_monthlyRate
FROM
tblCases
WHERE
CaseStatus = 'Open Case'
GROUP BY
LEFT(caseid,4)) s ON
c.contractID = s.left_caseID4
WHERE
i.ContractMainID IS NULL
GROUP BY
ContractID
Related
So I have a query for a report that never finishes. I've allowed it to run for upwards of 20+ mins without completing. Here is the query:
DECLARE #start DATE, #end DATE
SET #start = '7-1-2019'
SET #end = '8-20-2019'
SELECT cg.*
,ba.std_StandardAcctNo AS bonus_acct
FROM [CustSalesTrend_Growth] cg
LEFT JOIN (
SELECT DISTINCT std_standardacctno
FROM [CustSalesTrend_Growth]
WHERE eleph_Period_Date BETWEEN #Start
AND #End
OR ideal_Period_Date BETWEEN #Start
AND #End
) ba ON ba.std_StandardAcctNo = cg.std_StandardAcctNo
AND cg.Period_Date >= #Start
AND cg.Period_Date <= #End
WHERE [Appearance_Count] <> 0
AND Period_gp <> 0
ORDER BY cg.std_StandardAcctNo
One of my first steps in diagnosing this is doing a simple select * on the view being referenced (CustSalesTrend_Growth) and it will finish running in about 30 seconds on average, pulling 12k records. Given this, I'm a little perplexed as to how the preceding query could add so much complexity to the execution, to the point that it never finishes. In my mind, the query above is relatively simple, so any ideas as to why this is happening?
EDIT: query for the view CustSalesTrend_Growth
CREATE VIEW [dbo].[CustSalesTrend_Growth]
AS
WITH basedata
AS (
SELECT DISTINCT a.order_num
,a.Period_Date
,a.year AS std_the_year
,a.Month AS std_the_month
,a.customer_alias AS std_StandardAcctNo
,b.SalesPerson_name
,isnull(ac.counter, 0) [Appearance_Count]
,isnull(b.[Year], 0) [The_Year]
,isnull(b.[Month], 0) [The_Month]
,isnull(b.Customer_Alias, 0) [CustomerName]
,sum(isnull(b.Gallons, 0)) [Gallon_Qty]
,sum(isnull(b.[Total Sale], 0)) [Total_Sale]
,sum(isnull(b.[Gross Profit], 0)) [Total_Gross_Profit]
FROM (
SELECT DISTINCT a.year
,a.month
,b.Customer_Alias
,convert(INTEGER, convert(VARCHAR(4), a.Year) + right('00' + convert(VARCHAR(2), a.month), 2)) AS order_num
,convert(DATE, convert(VARCHAR(2), a.Month) + '/01/' + convert(VARCHAR(4), a.Year)) AS Period_Date
FROM Complete_Sales_V2 a
JOIN (
SELECT DISTINCT Customer_Alias
FROM Complete_Sales_V2
) b ON 1 = 1
) a
JOIN PDI_Warehouse_2049_01.dbo.Appearance_Count ac ON a.Customer_Alias = ac.customer_alias
LEFT JOIN Complete_Sales_V2 b ON a.Customer_Alias = b.Customer_Alias
AND a.Month = b.Month
AND a.Year = b.Year
GROUP BY a.order_num
,a.Period_Date
,a.year
,a.Month
,a.Customer_Alias
,b.SalesPerson_Name
,ac.counter
,b.[Year]
,b.[Month]
,b.Customer_Alias
)
,saleslist
AS (
SELECT DISTINCT SalesPerson_Name
,Appearance_Count
,Period_Date
,std_the_month
,std_the_year
,std_StandardAcctNo
,isnull(sum(Total_Gross_Profit), 0) Period_GP
FROM basedata
GROUP BY SalesPerson_Name
,Appearance_Count
,Period_Date
,std_StandardAcctNo
,std_the_month
,std_the_year
)
,core_GP
AS (
SELECT DISTINCT a.Customer_Alias
,convert(DATE, convert(VARCHAR(2), a.month) + '/01/' + convert(VARCHAR(4), a.year)) AS Period_Date
,sum(a.[Gross Profit]) AS Period_GP
FROM Complete_Sales_V2 a
JOIN PDI_Warehouse_2049_01.dbo.appearance_count ac ON ac.customer_alias = a.Customer_Alias
GROUP BY counter
,convert(DATE, convert(VARCHAR(2), a.month) + '/01/' + convert(VARCHAR(4), a.year))
,a.Customer_Alias
)
,GroupedData
AS (
SELECT DISTINCT cgp.std_StandardAcctNo
,cgp.Period_Date
,sum(cgp.[Total_Gross_Profit]) AS Period_GP
,Appearance_Count
FROM basedata cgp
GROUP BY cgp.std_StandardAcctNo
,cgp.Period_Date
,Appearance_Count
)
,GP_Grouping
AS (
SELECT std_StandardAcctNo
,min(Period_Date) AS range_start
,max(Period_Date) AS range_end
,count(*) AS range_count
,GP_group
FROM (
SELECT std_StandardAcctNo
,Period_Date
,CASE
WHEN Period_GP = 0
THEN 0
ELSE 1
END AS GP_Group
,row_number() OVER (
PARTITION BY std_StandardAcctNo
,CASE
WHEN Period_GP = 0
THEN 0
ELSE 1
END ORDER BY Period_Date
) AS rn
,row_number() OVER (
PARTITION BY std_StandardAcctNo
,CASE
WHEN Period_GP = 0
THEN 0
ELSE 1
END ORDER BY Period_Date
) - row_number() OVER (
PARTITION BY std_StandardAcctNo ORDER BY Period_Date
) AS grp
,row_number() OVER (
PARTITION BY std_StandardAcctNo ORDER BY Period_Date
) AS grp2
FROM GroupedData
) a
GROUP BY std_StandardAcctNo
,grp
,GP_Group
)
,GP_Group2
AS (
SELECT gd.*
,max(gpg_prev.range_end) AS last_zero_group -- , gpg.range_count
FROM GroupedData gd
LEFT JOIN GP_Grouping gpg ON gd.std_StandardAcctNo = gpg.std_StandardAcctNo
AND gd.Period_Date BETWEEN gpg.range_start
AND gpg.range_end
LEFT JOIN (
SELECT *
FROM GP_Grouping
WHERE GP_Group = 0
AND range_count >= 12
) gpg_prev ON gpg_prev.std_StandardAcctNo = gd.std_StandardAcctNo
AND gpg.range_start > gpg_prev.range_end
GROUP BY gd.std_StandardAcctNo
,Period_Date
,Period_GP
,Appearance_Count
,gpg.range_count
)
,GP_Group3
AS (
SELECT gd.*
,Appearance_Cnt_Rel = CASE
WHEN gd.last_zero_group IS NULL
THEN Appearance_Count
ELSE ROW_NUMBER() OVER (
PARTITION BY gd.std_StandardAcctNo
,gd.last_zero_group ORDER BY gd.Period_Date
)
END
FROM GP_Group2 gd
)
,almost_done
AS (
SELECT DISTINCT bd.order_num
,bd.Period_Date
,bd.std_the_year
,bd.std_the_month
,bd.std_StandardAcctNo
,CASE
WHEN bd.[Appearance_Count] > 0
THEN bd.[Appearance_Count]
WHEN isnull(c.Appearance_Count, 0) > 0
THEN c.Appearance_Count + 1
WHEN isnull(d.Appearance_Count, 0) > 0
THEN d.Appearance_Count + 2
WHEN isnull(e.Appearance_Count, 0) > 0
THEN e.Appearance_Count + 3
ELSE 0
END AS Appearance_Count
,bd.[The_Year]
,bd.[The_Month]
,bd.[CustomerName]
,bd.[Gallon_Qty]
,bd.[Total_Sale]
,isnull(c.Appearance_Count, 0) AS Prev_Count
,isnull(d.Appearance_Count, 0) AS month2_Count
,isnull(e.Appearance_Count, 0) AS month3_Count
,CASE
WHEN bd.SalesPerson_Name IS NOT NULL
THEN bd.SalesPerson_Name
WHEN c.SalesPerson_Name IS NOT NULL
THEN c.SalesPerson_Name
WHEN d.SalesPerson_Name IS NOT NULL
THEN d.SalesPerson_Name
WHEN e.SalesPerson_Name IS NOT NULL
THEN e.SalesPerson_Name
ELSE 'NA'
END [SalesPerson]
,CASE
WHEN bd.[Appearance_Count] IS NULL
AND c.[Appearance_Count] IS NULL
AND d.[Appearance_Count] IS NULL
THEN e.Period_GP
ELSE 0
END [Lost_Gross_Profit]
,CASE
WHEN bd.Appearance_Count = 1
THEN bd.Total_Gross_Profit
ELSE 0
END AS 'New_Cust_GP'
,CASE
WHEN bd.Appearance_Count <= 12
THEN bd.Total_Gross_Profit
ELSE 0
END AS 'Young_Cust_GP'
,CASE
WHEN bd.Appearance_Count > 12
THEN bd.Total_Gross_Profit
ELSE 0
END AS 'Old_Cust_GP'
,ROW_NUMBER() OVER (
PARTITION BY bd.std_StandardAcctNo
,bd.std_The_Year
,bd.std_The_Month ORDER BY (bd.std_StandardAcctNo) DESC
) AS UNI_Period
,bd.Total_Gross_Profit AS SalesP_GP
,isnull(cg.Period_gp, 0) AS Period_gp
,CASE
WHEN isnull(b_prev.Period_gp, 0) > 0
THEN isnull(b_prev.Period_gp, 0)
WHEN isnull(d.Period_gp, 0) > 0
THEN isnull(d.Period_gp, 0)
WHEN isnull(e.Period_gp, 0) > 0
THEN isnull(e.Period_gp, 0)
ELSE 0
END AS Prev_Period_GP
,h.Mat_MoM_Shift
,CASE
WHEN isnull(b_prev.Period_gp, 0) > 0
THEN isnull(b_prev.Period_gp, 0)
WHEN isnull(d.Period_gp, 0) > 0
THEN isnull(d.Period_gp, 0)
WHEN isnull(e.Period_gp, 0) > 0
THEN isnull(e.Period_gp, 0)
ELSE 0
END * h.Mat_MoM_Shift AS Expected_GP
,isnull(c.Period_gp, 0) AS True_Prev_GP
,isnull(d.Period_gp, 0) AS True_2month_GP
,isnull(e.Period_gp, 0) AS True_3month_GP
,ideal_candidate = CASE
WHEN ((isnull(c.Period_gp, 0) + isnull(d.Period_gp, 0) + isnull(bd.Total_Gross_Profit, 0)) / 3 >= 800)
AND isnull(c.Period_gp, 0) >= 150
AND isnull(d.Period_gp, 0) >= 150
AND isnull(bd.Total_Gross_Profit, 0) >= 150
THEN 'Y'
ELSE 'N'
END
,eleph_candidate = CASE
WHEN ((isnull(c.Period_gp, 0) + isnull(d.Period_gp, 0) + isnull(bd.Total_Gross_Profit, 0)) / 3 >= 5000)
AND isnull(c.Period_gp, 0) >= 1000
AND isnull(d.Period_gp, 0) >= 1000
AND isnull(bd.Total_Gross_Profit, 0) >= 1000
THEN 'Y'
ELSE 'N
'
END
FROM basedata bd
LEFT JOIN core_GP b_prev ON bd.std_StandardAcctNo = b_prev.Customer_Alias
AND b_prev.Period_Date = dateadd(month, - 1, bd.Period_Date)
LEFT JOIN saleslist c ON c.std_StandardAcctNo = bd.std_StandardAcctNo
AND c.Period_Date = dateadd(month, - 1, bd.Period_Date)
AND CASE
WHEN bd.SalesPerson_Name IS NOT NULL
THEN bd.SalesPerson_Name
ELSE c.SalesPerson_Name
END = c.SalesPerson_Name
LEFT JOIN saleslist d ON d.std_StandardAcctNo = bd.std_StandardAcctNo
AND d.Period_Date = dateadd(month, - 2, bd.Period_Date)
AND CASE
WHEN bd.SalesPerson_Name IS NOT NULL
THEN bd.SalesPerson_Name
WHEN c.SalesPerson_Name IS NOT NULL
THEN c.SalesPerson_Name
ELSE d.SalesPerson_Name
END = d.SalesPerson_Name
LEFT JOIN saleslist e ON e.std_StandardAcctNo = bd.std_StandardAcctNo
AND e.Period_Date = dateadd(month, - 3, bd.Period_Date)
AND CASE
WHEN bd.SalesPerson_Name IS NOT NULL
THEN bd.SalesPerson_Name
WHEN c.SalesPerson_Name IS NOT NULL
THEN c.SalesPerson_Name
WHEN d.SalesPerson_Name IS NOT NULL
THEN d.SalesPerson_Name
ELSE e.SalesPerson_Name
END = e.SalesPerson_Name
LEFT JOIN RicoCustom.dbo.[Rico_Global_Monthly] h ON h.month = bd.std_the_month
LEFT JOIN core_GP cg ON bd.std_StandardAcctNo = cg.Customer_Alias
AND cg.Period_Date = bd.Period_Date
)
,get_ideal
AS (
SELECT DISTINCT min(ad.Period_Date) AS ideal_Period_Date
,ad.std_StandardAcctNo
,rc.last_zero_group
FROM almost_done ad
LEFT JOIN GP_Group3 rc ON rc.Period_Date = ad.Period_Date
AND rc.std_StandardAcctNo = ad.std_StandardAcctNo
AND rc.Period_GP = ad.Period_gp
WHERE ideal_candidate = 'Y'
AND (
rc.Appearance_Cnt_Rel BETWEEN 3
AND 6
)
GROUP BY ad.std_StandardAcctNo
,rc.last_zero_group
)
,get_elephant
AS (
SELECT DISTINCT min(ad.Period_Date) AS eleph_Period_Date
,ad.std_StandardAcctNo
,rc.last_zero_group
FROM almost_done ad
LEFT JOIN GP_Group3 rc ON rc.Period_Date = ad.Period_Date
AND rc.std_StandardAcctNo = ad.std_StandardAcctNo
AND rc.Period_GP = ad.Period_gp
WHERE eleph_candidate = 'Y'
AND (
rc.Appearance_Cnt_Rel BETWEEN 3
AND 36
)
GROUP BY ad.std_StandardAcctNo
,rc.last_zero_group
)
SELECT rc.Appearance_Cnt_Rel
,gi.ideal_Period_Date
,ge.eleph_Period_Date
,ad.*
FROM almost_done ad
LEFT JOIN GP_Group3 rc ON rc.Period_Date = ad.Period_Date
AND rc.std_StandardAcctNo = ad.std_StandardAcctNo
AND rc.Period_GP = ad.Period_gp
LEFT JOIN get_ideal gi ON ad.std_StandardAcctNo = gi.std_StandardAcctNo
AND ad.Period_Date = gi.ideal_Period_Date
LEFT JOIN get_elephant ge ON ad.std_StandardAcctNo = ge.std_StandardAcctNo
AND ad.Period_Date = ge.eleph_Period_Date
WHERE order_num > 201001
The indexing I have exists on the source table, Complete_Sales_V2. It is as follows:
index desc:
clustered, unique, primary key located on PRIMARY
index keys:
Customer_Alias, SalesPerson_Name, year, month, Invoice_Number
Since you say you can query the view I suggest selecting your view into a temp table prior to performing the query. This will simplify the query plan, allowing you to inspect it. And may hopefully speed it up.
I note in your original query you are filtering you main table against #Start and #End in the join condition. I don't think you want to do that. I think it should be in the where clause.
Also you can probably pre-filter the temp table so long as you can work out which records may be required (I couldn't because you compare to 3 different dates).
DECLARE #start DATE = '7-1-2019', #end DATE = '8-20-2019';
-- Best practice is to list the actual columns required
-- You may also be able to pre-filter here based on #start and #end
-- But as you compare them to 3 different columns in the query I don't know enough about your logic to know if this is possible or not
-- You can also add indexes to the temp table if they would speed things up
select *
into #cg
from [CustSalesTrend_Growth];
SELECT cg.*
, ba.std_StandardAcctNo AS bonus_acct
FROM #cg cg
LEFT JOIN (
SELECT DISTINCT std_standardacctno
FROM #cg
WHERE eleph_Period_Date BETWEEN #Start AND #End
OR ideal_Period_Date BETWEEN #Start AND #End
) ba ON ba.std_StandardAcctNo = cg.std_StandardAcctNo
WHERE [Appearance_Count] <> 0
AND Period_gp <> 0
AND cg.Period_Date >= #Start
AND cg.Period_Date <= #End
ORDER BY cg.std_StandardAcctNo;
drop table #cg;
Try this query that uses CTEs. I do not have the schema so some of my assumptions may not be correct. Please verify the query before you execute.
WITH t1 AS
(
SELECT *
FROM CustSalesTrend_Growth
WHERE Appearance_Count <> 0
AND Period_gp <> 0
AND Period_Date between #Start and #End
),
t2 AS
(
SELECT DISTINCT std_StandardAcctNo
FROM CustSalesTrend_Growth
WHERE eleph_Period_Date BETWEEN #Start AND #End
OR ideal_Period_Date BETWEEN #Start AND #End
)
select t1.*, t2.std_StandardAcctNo AS bonus_acct
FROM t1
LEFT JOIN t2 ON t2.std_StandardAcctNo = t1.std_StandardAcctNo
ORDER BY t2.std_StandardAcctNo
I am looking to find a solution to this problem. I have a table called LogEntry that stores information used by multiple offices, where they have to log any visitors that come in to their office on any given day. If no visitors come in, they are still required to log "No Visitors" for the day. How do I run a query that pulls all dates where an office failed to create even a "No Visitors" log?
I've looked at this question (and the article linked within), but even adapting that query, I'm only able to create a blank row for a date where an office is missing an entry for a date, not specify the actual office that did not create an entry. Is there a way to do what I'm trying to do?
declare #temp table (
CDate datetime,
loc_id varchar(50)
)
insert into #temp SELECT DISTINCT entryDate, locationID FROM LogEntry WHERE entryDate >= '05/01/2017' AND entryDate <= '07-31-2017'
;with d(date) as (
select cast('05/01/2017' as datetime)
union all
select date+1
from d
where date < '07/31/2017'
)
select DISTINCT t.loc_id, CONVERT(date, d.date)
FROM d LEFT OUTER JOIN #temp t ON d.date = t.CDate
GROUP BY t.loc_id, d.date
ORDER BY t.loc_id
As I said, this query returns me a list of dates in the date range, and all locations that submitted entries on that date, but I'd like to find a way to extract essentially the opposite information: if an office (specified by locationID) did not submit an entry on a given day, return only those locationIDs and the dates that they missed.
Sample data
EntryID | locationID | entryDate
=================================
1 1 07-01-2017
2 1 07-02-2017
3 2 07-02-2017
4 1 07-04-2017
Expected Result (for date range of 07-01 to 07-04)
locationID | missedEntryDate
============================
1 07-03-2017
2 07-01-2017
2 07-03-2017
2 07-04-2017
Your first step was good, you create a list of all dates, but you also need a list of all locations. Then you create a cross join to have all combinations and then you perform the left join to find out what is missing.
;with allDates(date) as (
select cast('05/01/2017' as datetime)
union all
select date+1
from d
where date < '07/31/2017'
), allLocations as (
SELECT DISTINCT loc_id
FROM #temp
), allCombinations as (
SELECT date, loc_id
FROM allDates
CROSS JOIN allLocations
)
SELECT AC.loc_id, AC.date
FROM allCombinations AC
LEFT JOIN #temp t
ON AC.date = t.CDate
AND AC.loc_id = t.loc_id
WHERE t.loc_id IS NULL -- didnt find a match on #temp
If your dataset is not too large you can try this:
select t.loc_id, CONVERT(date, d.date)
FROM d
-- Cross join dates to all available locs
CROSS JOIN (SELECT DISTINCT loc_id FROM #temp ) AS Locs
LEFT JOIN
( SELECT loc_id, t.CDate
FROM #temp
GROUP BY loc_id, d.date ) AS t ON d.date = t.CDate AND Locs.loc_id = t.loc_id
ORDER BY Locs.loc_id
This should be a bit faster:
;WITH cte AS (
SELECT a.LocID, RangeStart.CDate, ( CASE WHEN Input.LocID IS NULL THEN 1 ELSE 0 END ) AS IsMissing
FROM ( SELECT DISTINCT LocID FROM #temp ) AS a
CROSS JOIN ( SELECT CONVERT( DATETIME, '2017-05-01' ) AS CDate ) AS RangeStart
LEFT JOIN
( SELECT LocID, MIN( CDate ) AS CDate
FROM #temp
WHERE CDate = '2017-05-01'
GROUP BY LocID ) AS Input ON a.LocID = Input.LocID AND RangeStart.CDate = Input.CDate
UNION ALL
SELECT a.LocID, a.CDate + 1 AS CDate,
ISNULL( ItExists, 0 ) AS IsMissing
FROM cte AS a
OUTER APPLY( SELECT LocID, 1 AS ItExists FROM #temp AS b WHERE a.LocID = b.LocID AND a.CDate + 1 = b.CDate ) AS c
WHERE a.CDate < '2017-07-01'
)
SELECT * FROM cte OPTION( MAXRECURSION 0 )
You can also add an index:
CREATE INDEX IX_tmp_LocID_CDate ON #temp( LocID, CDate )
Sample data set for the second query:
CREATE TABLE #temp( LocID VARCHAR( 50 ), CDate DATETIME )
INSERT INTO #temp
VALUES
( '1', '2017-05-01' ), ( '1', '2017-05-02' ), ( '1', '2017-05-03' ), ( '1', '2017-05-04' ), ( '1', '2017-05-05' ),
( '2', '2017-05-01' ), ( '2', '2017-05-02' ), ( '2', '2017-05-03' ), ( '2', '2017-05-04' ), ( '2', '2017-05-05' )
;WITH d AS (
SELECT CAST( '05/01/2017' AS DATETIME ) AS date
UNION ALL
SELECT date + 2
FROM d
WHERE date < '2018-07-31'
)
INSERT INTO #temp
SELECT LocID, d.date
FROM ( SELECT DISTINCT LocID FROM #temp ) AS a
CROSS JOIN d
OPTION( MAXRECURSION 0 )
I have below recursive CTE:
DECLARE #T AS TABLE
(
PARENT_TEST_ID int,
TEST_ID int,
VALIDATED int,
ERR int
)
INSERT INTO #T VALUES
(NULL, 1, 0, 0),
(NULL, 2, 0, 0),
(1,3,0, 0),
(1,4,0, 0),
(2,5,0, 0),
(2,6,0, 0),
(2,7,0, 0),
(7,8,0, 1)
;with C as
(
select TEST_ID, PARENT_TEST_ID, (CASE WHEN ERR=1 THEN 0 ELSE 1 END) AS VALIDATED, ERR
from #T
where TEST_ID not in (select PARENT_TEST_ID
from #T
where PARENT_TEST_ID is not null) AND PARENT_TEST_ID IS NOT NULL
union all
select
T.TEST_ID,
T.PARENT_TEST_ID,
(case when t.TEST_ID=c.PARENT_TEST_ID and c.VALIDATED=1 AND T.ERR=0 THEN 1 ELSE 0 END) as VALIDATED,
T.ERR
from #T as T
inner join C
on T.TEST_ID = C.PARENT_TEST_ID
)
SELECT DISTINCT PARENT_TEST_ID, TEST_ID, MIN(VALIDATED) FROM C
GROUP BY TEST_ID
But I cannot include PARENT_TEST_ID column in the result SELECT as it is not part of the group by clause, so I have found this link:
Including column that is not part of the group by
So now I am trying to do the same in my case, I am trying to apply John Woo solution but I do not know how. Any help? Or any other best solution?
iamdave is right, but if you want to implement John Woo's solution from that linked answer, it would look like this:
rextester: http://rextester.com/QQQGM79701
;with C as (
select
test_id
, parent_test_id
, validated=(case when err = 1 then 0 else 1 end)
, err
from #T as t
where t.test_id not in (
select i.parent_test_id
from #T as i
where i.parent_test_id is not null
)
and t.parent_test_id is not null
union all
select
t.test_id
, t.parent_test_id
, validated = case
when t.test_id = c.parent_test_id
and c.validated = 1
and t.err = 0
then 1
else 0
end
, t.err
from #T as T
inner join c on t.test_id = c.parent_test_id
)
, r as (
select
parent_test_id
, test_id
, Validated
, rn = row_number() over (
partition by test_id
order by Validated
)
from C
)
select
parent_test_id
, test_id
, Validated
from r
where rn=1
Just change your last line to GROUP BY PARENT_TEST_ID, TEST_ID
The error you are getting is telling you that you can't add columns to the output if you don't either aggregate on it or group your other aggregates by it. By adding the column to the group by, you are telling SQL Server that you want to do your min by both the parent and the test ID values.
rextester: http://rextester.com/JRF55398
I want to get the last Saturday from today + 21 days.
In order to achieve this, I have written this script shown below. But the problem is that I can't get success to return the value from the result.
I want to create this function in SQL Server and will get this value in a stored procedure where I want.
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
DECLARE #NumOfDays INT
DECLARE #resultDate smalldatetime
SET #StartDate = GETDATE()
SET #EndDate = GETDATE()+21
SET #NumOfDays = DATEDIFF(DD,#StartDate , #EndDate) + 1 ;
WITH Tens AS
(
SELECT 1 N UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1
),
HUNDREDS AS
(
SELECT T1.N FROM TENS T1 CROSS JOIN TENS T2
),
THOUSANDS AS
(
SELECT T1.N FROM HUNDREDS T1 CROSS JOIN HUNDREDS T2
),
Numbers AS
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 0)) RN FROM THOUSANDS
)
SELECT TOP 1
DATEADD(DD, (RN - 1), #StartDate) SaturdayDates
FROM
Numbers
WHERE
RN <= #NumOfDays
AND DATENAME (WEEKDAY, (DATEADD(DD, (RN - 1), #StartDate))) = 'Saturday'
ORDER BY
SaturdayDates DESC
Can you please guide me to achieve my goal? Thanks
Just rewrite it like this table-valued function:
CREATE FUNCTION dbo.Get_NextSaturdayDay()
RETURNS TABLE
AS
RETURN
(
-- Add the SELECT statement with parameter references here
WITH Tens AS
(
SELECT 1 N UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1
),
HUNDREDS AS
(
SELECT T1.N FROM TENS T1 CROSS JOIN TENS T2
),
THOUSANDS AS
(
SELECT T1.N FROM HUNDREDS T1 CROSS JOIN HUNDREDS T2
),
Numbers AS
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 0)) RN FROM THOUSANDS
)
SELECT TOP 1 DATEADD( DD,(RN - 1) , GETDATE() ) as SaturdayDates
FROM
Numbers
WHERE
RN <= (DATEDIFF(DD,GETDATE() , DATEADD(day,21,GETDATE()) ) + 1) AND DATENAME ( WEEKDAY, (DATEADD( DD,(RN - 1) , GETDATE() )) ) = 'Saturday'
ORDER BY SaturdayDates DESC
)
GO
Than do:
SELECT *
FROM dbo.Get_NextSaturdayDay()
Output:
SaturdayDates
2016-10-15 11:02:33.570
If you need scalar-valued function:
CREATE FUNCTION dbo.Get_NextSaturdayDay ()
RETURNS datetime
AS
BEGIN
DECLARE #datetime datetime
;WITH Tens AS
(
SELECT 1 N UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1
),
HUNDREDS AS
(
SELECT T1.N FROM TENS T1 CROSS JOIN TENS T2
),
THOUSANDS AS
(
SELECT T1.N FROM HUNDREDS T1 CROSS JOIN HUNDREDS T2
),
Numbers AS
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 0)) RN FROM THOUSANDS
)
SELECT TOP 1 #datetime = DATEADD( DD,(RN - 1) , GETDATE() )
FROM
Numbers
WHERE
RN <= (DATEDIFF(DD,GETDATE() , DATEADD(day,21,GETDATE()) ) + 1) AND DATENAME ( WEEKDAY, (DATEADD( DD,(RN - 1) , GETDATE() )) ) = 'Saturday'
ORDER BY DATEADD( DD,(RN - 1) , GETDATE() ) DESC
-- Return the result of the function
RETURN #datetime
END
GO
Then run:
SELECT dbo.Get_NextSaturdayDay()
Output:
2016-10-15 11:02:33.570
I have a table like this (SQL Server 2008):
[ATTACHMENTS].[ID]
[ATTACHMENTS].[Name]
[ATTACHMENTS].[DocumentID],
[ATTACHMENTS].[ParentAttachmentID]
If [ParentAttachmentID] is NULL or 0 - then the record is top. Otherwise - the record is a child. Every child can be (and can't be) the parent of some other child elementS.
I need to calculate "path" for every record of the table. Path is:
ParentAttachment.Path + ' > ' + Attachment.Path (ParentAttachment.Path is recursive)
I try something like this:
WITH attachments AS (
SELECT *,
[ATTACHMENTS].[Name] AS Path
FROM [ATTACHMENTS]
WHERE [ATTACHMENTS].[ParentAttachmentID] IS NULL
OR [ATTACHMENTS].[ParentAttachmentID] = 0
UNION ALL
SELECT a.*,
c.Path + ' > ' + a.[Name]
FROM [ATTACHMENTS] a
INNER JOIN attachments c
ON a.[ParentAttachmentID] = c.[ID]
)
But it doesn't work properly (Path is invalid for some elements due to duplicates as I think). Where I made a mistake? Please, help me to fix this problem.
UPD 2: CSV with data from table [ATTACHMENTS] - http://pastebin.com/WMd6HJ7j
CSV with result of recursive query: http://pastebin.com/7pqs0dx1
Thanx!
What is the error you get?
I think that you are not specifying your datatypes explicitly enough. The size of Path is the size of the anchor start point: ATTACHMENTS.Name. Which probably would be a varchar(100) or so.
Then when you keep recursively growing your path, it might run out of space. The CTE itself looks fine. I had a go at it using explicit sizes, then it work fine.
CREATE TABLE #Attachments
(
Id INT PRIMARY KEY
NOT NULL ,
ParentId INT NULL ,
Name VARCHAR(50) NOT NULL
);
-- some sample data:
-------------------------------------
-- 100 top level attachments (lvl0)
INSERT INTO #Attachments
( Id ,
ParentId ,
Name
)
SELECT A.Rnum ,
NULL ,
'A' + CAST(rnum AS VARCHAR(10))
FROM ( SELECT TOP 100
ROW_NUMBER() OVER ( ORDER BY ( SELECT
1
) ) AS Rnum
FROM sys.messages
) A;
-- attachments linked to lvl0
INSERT INTO #Attachments
( Id ,
ParentId ,
Name
)
SELECT 1000 + A.Rnum ,
A.Rnum ,
'A' + CAST(( rnum + 1000 ) AS VARCHAR(10))
FROM ( SELECT TOP 1000
ROW_NUMBER() OVER ( ORDER BY ( SELECT
1
) ) AS Rnum
FROM sys.messages
) A;
-- attachments linked to lvl1
INSERT INTO #Attachments
( Id ,
ParentId ,
Name
)
SELECT 10000 + A.Rnum ,
1000 + A.Rnum ,
'A' + CAST(( rnum + 10000 ) AS VARCHAR(10))
FROM ( SELECT TOP 1000
ROW_NUMBER() OVER ( ORDER BY ( SELECT
1
) ) AS Rnum
FROM sys.messages
) A;
-- Query:
-------------------------------------
WITH Att ( Id, Name, ParentId, Lvl, NamePath, IdPath )
AS ( SELECT P.Id ,
P.Name ,
P.ParentId ,
CAST(0 AS INT) AS Lvl ,
CAST(P.[Name] AS VARCHAR(1000)) AS NamePath ,
CAST(P.[Id] AS VARCHAR(1000)) AS IdPath
FROM #ATTACHMENTS P
WHERE P.[ParentId] IS NULL
OR P.[ParentId] = 0
UNION ALL
SELECT A.Id ,
A.Name ,
A.ParentId ,
P.Lvl + 1 ,
CAST(P.NamePath + ' > ' + A.Name AS VARCHAR(1000)) ,
CAST(P.IdPath + '\' + CAST(A.Id AS VARCHAR(10)) AS VARCHAR(1000))
FROM #ATTACHMENTS A
INNER JOIN Att P ON A.ParentId = P.Id
)
SELECT *
FROM Att;
DROP TABLE #Attachments;
You have to set different names for table and the name after WITH, and use the second name for second part of the join. Consider attachments1 in below code:
WITH attachments1 AS (
-- anchor
SELECT *,
[ATTACHMENTS].[Name] AS [Path]
FROM ATTACHMENTS
WHERE [ATTACHMENTS].[ParentAttachmentID] IS NULL
OR [ATTACHMENTS].ParentAttachmentID = 0
UNION ALL
--recursive member
SELECT a.*,
cast((c.[Path] + N' > ' + a.[Name]) as nvarchar(500)) as [Path]
FROM ATTACHMENTS a
INNER JOIN attachments1 c
ON a.ParentAttachmentID = c.[ID]
)
SELECT * FROM attachments1
You can get the Path from the recursive member.
Your statement seems correct to me:
DECLARE #t TABLE
(
Code NVARCHAR(MAX) ,
ParentCode NVARCHAR(MAX)
)
INSERT INTO #t
VALUES ( '1', NULL ),
( '2', NULL ),
( '1.1', '1' ),
( '1.1.1', '1.1' ),
( '1.1.2', '1.1' ),
( '1.2', '1' ),
( '1.2.1', '1.2' ),
( '2.1', '2' ),
( '2.2', '2' );
WITH cte
AS ( SELECT Code ,
ParentCode ,
ISNULL(Code, '') AS Path
FROM #t
WHERE ParentCode IS NULL
UNION ALL
SELECT t.Code ,
t.ParentCode ,
Path + ISNULL(' > ' + t.Code, '') AS Path
FROM #t t
JOIN cte c ON c.Code = t.ParentCode
)
SELECT * FROM cte
Output:
Code ParentCode Path
1 NULL 1
2 NULL 2
2.1 2 2 > 2.1
2.2 2 2 > 2.2
1.1 1 1 > 1.1
1.2 1 1 > 1.2
1.2.1 1.2 1 > 1.2 > 1.2.1
1.1.1 1.1 1 > 1.1 > 1.1.1
1.1.2 1.1 1 > 1.1 > 1.1.2