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
Hopefully an easy one but I need help.
I have two queries looking at the same data but with different where statements.
The data shows value of different card brands from the days trading. however, each total is on a separate line so id like to see all on one line for a store
so [LOCATION], [TRADE DATE], [VISA],[AMEX],[# RECORDS].
I have limited the query to a single location for now.
Any help would be most appreciated
Query A (Visa records)
SELECT
TILLREADREQUEST.STRTRADECODE AS [LOCATION]
,TILLREADREQUEST.DTMTRADEDATE AS [TRADE DATE]
,SUM(TILLREADDETAIL.CURVALUE) AS [VISA]
,COUNT(TILLREADREQUEST.ctrcode) AS [# RECORDS],
FROM
TILLREADDETAIL INNER JOIN
TILLREADREQUEST ON TILLREADDETAIL.LINTREQUESTCODE = TILLREADREQUEST.CTRCODE
WHERE (TILLREADDETAIL.INTTENDERCODE IN ('3')) and TILLREADREQUEST.DTMTRADEDATE > getdate()-2 AND STRTRADECODE = 'SHEFFIELD'
group by TILLREADREQUEST.STRTRADECODE,TILLREADREQUEST.DTMTRADEDATE*
Query B (Amex Records)
SELECT
TILLREADREQUEST.STRTRADECODE AS [LOCATION]
,TILLREADREQUEST.DTMTRADEDATE AS [TRADE DATE]
,SUM(TILLREADDETAIL.CURVALUE) AS [AMEX]
FROM
TILLREADDETAIL INNER JOIN
TILLREADREQUEST ON TILLREADDETAIL.LINTREQUESTCODE = TILLREADREQUEST.CTRCODE
WHERE (TILLREADDETAIL.INTTENDERCODE IN ('4')) and TILLREADREQUEST.DTMTRADEDATE > getdate()-2 AND STRTRADECODE = 'SHEFFIELD'
group by TILLREADREQUEST.STRTRADECODE,TILLREADREQUEST.DTMTRADEDATE*
Use CASEin your query for the particular condition:
SELECT
TILLREADREQUEST.STRTRADECODE AS [LOCATION]
,TILLREADREQUEST.DTMTRADEDATE AS [TRADE DATE]
,SUM(CASE WHEN TILLREADDETAIL.INTTENDERCODE IN ('3')
THEN TILLREADDETAIL.CURVALUE
ELSE 0
END
) AS [VISA]
,SUM(CASE WHEN TILLREADDETAIL.INTTENDERCODE IN ('4')
THEN TILLREADDETAIL.CURVALUE
ELSE 0
END
) AS [AMEX]
,COUNT(TILLREADREQUEST.ctrcode) AS [# RECORDS],
FROM
TILLREADDETAIL INNER JOIN
TILLREADREQUEST ON TILLREADDETAIL.LINTREQUESTCODE = TILLREADREQUEST.CTRCODE
WHERE (TILLREADDETAIL.INTTENDERCODE IN ('3', '4')) and TILLREADREQUEST.DTMTRADEDATE > getdate()-2 AND STRTRADECODE = 'SHEFFIELD'
group by TILLREADREQUEST.STRTRADECODE,TILLREADREQUEST.DTMTRADEDATE*
If you also want to count records separately for VISA/AMEX then you'll have to add case there as well.
SELECT
TILLREADREQUEST.STRTRADECODE AS [LOCATION]
,TILLREADREQUEST.DTMTRADEDATE AS [TRADE DATE]
,SUM(CASE WHEN TILLREADDETAIL.INTTENDERCODE IN ('3') THEN TILLREADDETAIL.CURVALUE ELSE 0 END) AS [VISA]
,SUM(CASE WHEN TILLREADDETAIL.INTTENDERCODE IN ('4') THEN TILLREADDETAIL.CURVALUE ELSE 0 END) AS [AMEX]
,COUNT(CASE WHEN TILLREADREQUEST.ctrcode = '3' THEN 1 ELSE NULL END) AS [# RECORDS],
,COUNT(CASE WHEN TILLREADREQUEST.ctrcode = '4' THEN 1 ELSE NULL END) AS [# RECORDS]
FROM
TILLREADDETAIL INNER JOIN
TILLREADREQUEST ON TILLREADDETAIL.LINTREQUESTCODE = TILLREADREQUEST.CTRCODE
WHERE (TILLREADDETAIL.INTTENDERCODE IN ('3','4')) and TILLREADREQUEST.DTMTRADEDATE > getdate()-2 AND STRTRADECODE = 'SHEFFIELD'
group by TILLREADREQUEST.STRTRADECODE,TILLREADREQUEST.DTMTRADEDATE*
I am using Microsoft Sql Server management studio.
I have had mixed success creating a tax report for a particular type of invoice that I have.
I have amounts under 6%, other amounts under 13.5% and the last amount has a complete total of both 6% and 13.5%.
I have got my answer in the results, but two different rows for each invoice are displayed. One is for 6% values and the other for 13.5% values.
I need to somehow merge these two rows into one single row for each invoice.
My Sql query is as follows:
SELECT tran_no ,
tran_date ,
( SELECT SUM(edetail_amt)
WHERE edetail_taxid = '6008U_='
) AS '6% amt' ,
( SELECT SUM(edetail_per)
WHERE edetail_taxid = '6008U_='
) AS '6% vat' ,
( SELECT SUM(edetail_amt)
WHERE edetail_taxid = '6008U_>'
) AS '13.5% amt' ,
( SELECT SUM(edetail_per)
WHERE edetail_taxid = '6008U_>'
) AS '13.5% vat' ,
( SELECT SUM(edetail_amt + edetail_per)
WHERE edetail_taxid IN ( '6008U_=', '6008U_>' )
) AS 'Net Total'
FROM h_edetail
INNER JOIN h_tran ON edetail_tranid = tran_kid
WHERE tran_trantype = 'PI'
AND tran_date = '2016-11-03 00:00:00.000'
GROUP BY tran_no ,
tran_date ,
edetail_taxid
ORDER BY tran_no;
A screenshot of the query along with the results are as follows:
If am not wrong you are looking for this
SELECT tran_no,
tran_date,
Sum(case when edetail_taxid = '6008U_=' then edetail_amt else 0 end) AS '6% amt',
Sum(case when edetail_taxid = '6008U_=' then edetail_per else 0 end) AS '6% vat',
Sum(case when edetail_taxid = '6008U_>' then edetail_amt else 0 end) AS '13.5% amt',
Sum(case when edetail_taxid = '6008U_>' then edetail_per else 0 end) AS '13.5% vat',
Sum(case when edetail_taxid IN ( '6008U_=', '6008U_>' ) then edetail_amt + edetail_per else 0 end) AS 'Net Total'
FROM h_edetail
INNER JOIN h_tran
ON edetail_tranid = tran_kid
WHERE tran_trantype = 'PI'
AND tran_date = '2016-11-03 00:00:00.000'
GROUP BY tran_no,
tran_date
ORDER BY tran_no
Because of select sum(edetail_amt) where edetail_taxid='6008U_=' you are forced to add edetail_taxid in group by that is the reason for duplicate records. You can do that by adding case inside SUM aggregate
The first three items from table ProviderValueCard add their respective amount if = 1. I'm also trying to add 50 to my TotalScore if the ProviderID exists in table SubscriptionsTV. GroupID is also from SubscriptionsTV in which the condition needs to be met. I beleive I need to have a left outer join in the 2nd query on ProviderID columns from both tables.
DECLARE #ProviderID int = '1717';
WITH cte as(
SELECT TOP 1 ProviderID, Time_Stamp,
SUM(CASE WHEN [AdditionalReports] = '1' THEN 5 ELSE 0 END) as AdditionalReports,
SUM(CASE WHEN [UniqueReportRequests] = '1' THEN 15 ELSE 0 END) as UniqueReportsRequests,
SUM(CASE WHEN [SurveyCompleted] = '1' THEN 30 ELSE 0 END) as SurveyCompleted
--IF #ProviderID EXISTS SUM(THEN 50 ELSE 0 END)
FROM ProviderValueCard
WHERE ProviderID = #ProviderID
GROUP BY Time_Stamp, ProviderID
ORDER BY Time_Stamp DESC
)
SELECT ProviderID, Time_Stamp, (AdditionalReports + UniqueReportsRequests + SurveyCompleted) AS TotalScore
FROM cte
--WHERE GroupID = 2
returns
ProviderID Time_Stamp TotalScore
----------- ----------------------- -----------
1717 2014-08-28 13:03:30.593 45
ProviderValueCard table
ProviderID AdditionalReports UniqueReportRequests SurveyCompleted Time_Stamp
----------- ----------------- -------------------- --------------- -----------------------
1717 0 1 1 2014-08-28 13:03:30.593
SubscriptionsTV table
ProviderID GroupID
----------- -----------
1717 2
My final result is this:
DECLARE #ProviderID int = '1717';
WITH cte as(
SELECT TOP 1 a.ProviderID, Time_Stamp,
SUM(CASE WHEN [AdditionalReports] = '1' THEN 5 ELSE 0 END) as AdditionalReports,
SUM(CASE WHEN [UniqueReportRequests] = '1' THEN 15 ELSE 0 END) as UniqueReportsRequests,
SUM(CASE WHEN [SurveyCompleted] = '1' THEN 30 ELSE 0 END) as SurveyCompleted,
MAX(CASE WHEN b.ProviderID IS NULL THEN 0 ELSE 50 END) as SubscriptionExists
FROM ProviderValueCard a
LEFT JOIN SubscriptionsTV b
ON a.ProviderID = b.ProviderID
WHERE a.ProviderID = #ProviderID AND GroupID = 2
GROUP BY Time_Stamp, a.ProviderID, event
ORDER BY event DESC, Time_Stamp DESC
)
SELECT ProviderID, Time_Stamp, (AdditionalReports + UniqueReportsRequests + SurveyCompleted + SubscriptionExists) AS TotalScore
FROM cte
You are correct that this can be accomplished with a LEFT JOIN, and I'd use MAX() with a CASE statement:
DECLARE #ProviderID int = '1717';
WITH Subs AS (SELECT DISTINCT ProviderID
FROM SubscriptionsTV
)
,cte AS (SELECT TOP 1 a.ProviderID, Time_Stamp,
SUM(CASE WHEN [AdditionalReports] = '1' THEN 5 ELSE 0 END) as AdditionalReports,
SUM(CASE WHEN [UniqueReportRequests] = '1' THEN 15 ELSE 0 END) as UniqueReportsRequests,
SUM(CASE WHEN [SurveyCompleted] = '1' THEN 30 ELSE 0 END) as SurveyCompleted,
MAX(CASE WHEN b.ProviderID IS NULL THEN 0 ELSE 50 END) as SubscriptionExists
FROM ProviderValueCard a
LEFT JOIN Subs b
ON a.ProviderID = b.ProviderID
WHERE a.ProviderID = #ProviderID
GROUP BY Time_Stamp, ProviderID
ORDER BY Time_Stamp DESC
)
SELECT ProviderID, Time_Stamp, (AdditionalReports + UniqueReportsRequests + SurveyCompleted + SubscriptionExists) AS TotalScore
FROM cte
Update: Since multiple providerID's can exist, need DISTINCT, used a 2nd cte above, could also use a correlated sub-select inside the CASE statement.
Wasn't paying attention, ORDER BY is fine in a cte when TOP is used.
I'm having to re-write a project that was done using a combination of SQL queries and Query-of-Queries in ColdFusion. There were dozens of queries referencing the original SQL Query results set, but it wasn't abstracted to work for different events. So I would like to improve it by moving most of the counting into SQL. I got the first 6 counts they need working (not sure if in the most optimal way). But, in addition to those, I need to be able to do a break down not just on the overall date range, but also for each individual day in that date range for the unique counts.
So far the query is:
SELECT Count(CASE
WHEN type IN ( 1, 3, 4, 5, 9 ) THEN barcode
ELSE NULL
END) AS total_scans,
Count(CASE
WHEN type IN ( 2, 8 ) THEN barcode
ELSE NULL
END) AS total_creds,
Count(barcode) AS total_scans,
Count(DISTINCT CASE
WHEN type IN ( 1, 3, 4, 5, 9 ) THEN barcode
ELSE NULL
END) AS unique_scans,
Count(DISTINCT CASE
WHEN type IN ( 2, 8 ) THEN barcode
ELSE NULL
END) AS unique_creds,
Count(DISTINCT barcode) AS unique_scans
FROM (SELECT c.id,
a.barcode,
d.type,
c.location,
Datepart(mm, a.scan_time) AS scan_month,
Datepart(dd, a.scan_time) AS scan_day,
Datepart(hour, a.scan_time) AS scan_hour,
Datepart(minute, a.scan_time) AS scan_min
FROM [scan_11pc_gate_entries] AS a
INNER JOIN scan_units AS b
ON a.scanner = b.id
INNER JOIN scan_gates AS c
ON b.gate = c.id
INNER JOIN [scan_11pc_gate_allbarcodes] AS d
ON a.barcode = d.barcode
WHERE ( c.id IN (SELECT id
FROM scan_gates
WHERE ( event_id = 21 )) )
AND ( a.valid IN ( 1, 8 ) )
AND a.scan_time >= '20110808'
AND a.scan_time <= '20110814') data
Well I see plenty of other room for improvement / optimization here, but to satisfy the immediate requirement:
SELECT d, Count(CASE WHEN type IN ( 1, 3, 4, 5, 9 ) THEN barcode
ELSE NULL END) AS total_scans,
Count(CASE WHEN type IN ( 2, 8 ) THEN barcode
ELSE NULL END) AS total_creds,
Count(barcode) AS total_scans,
Count(DISTINCT CASE WHEN type IN ( 1, 3, 4, 5, 9 ) THEN barcode
ELSE NULL END) AS unique_scans,
Count(DISTINCT CASE WHEN type IN ( 2, 8 ) THEN barcode
ELSE NULL END) AS unique_creds,
Count(DISTINCT barcode) AS unique_scans
FROM (SELECT c.id, -- is this column necessary?
a.barcode,
d.type,
c.location, -- is this column necessary?
d = DATEADD(DAY, DATEDIFF(DAY, 0, a.scan_time), 0)
FROM [scan_11pc_gate_entries] AS a
INNER JOIN scan_units AS b
ON a.scanner = b.id
INNER JOIN scan_gates AS c
ON b.gate = c.id
AND c.event_id = 21 -- join criteria,
-- shouldn't be an extra IN clause
INNER JOIN [scan_11pc_gate_allbarcodes] AS d
ON a.barcode = d.barcode
WHERE ( a.valid IN ( 1, 8 ) )
AND a.scan_time >= '20110808'
AND a.scan_time <= '20110814') data
GROUP BY d
ORDER BY d;
Note that >= and <= is the same as BETWEEN, and unless scan_time is a DATE column (or guaranteed to always be at midnight), the approach you're using isn't safe. Better to say:
AND a.scan_time >= '20110808'
AND a.scan_time < '20110815'
More info here:
What do BETWEEN and the devil have in common?
EDIT
Understanding that this is based on the information I've pieced together from comments and questions, which is far from a complete picture of your environment and workload, an indexed view you may find useful would be:
CREATE VIEW dbo.myview
WITH SCHEMABINDING
AS
SELECT c.event_id,
a.barcode,
[type] = CASE WHEN d.[type] IN (2,8) THEN 'c' ELSE 's' END,
scan_date = DATEADD(DAY, DATEDIFF(DAY, 0, a.scan_time), 0),
total = COUNT_BIG(*)
FROM dbo.scan_11pc_gate_entries AS a
INNER JOIN dbo.can_units AS b
ON a.scanner = b.id
INNER JOIN dbo.scan_gates AS c
ON b.gate = c.id
INNER JOIN dbo.scan_11pc_gate_allbarcodes AS d
ON a.barcode = d.barcode
WHERE (a.valid IN (1,8))
AND d.[type] IN (2,3,4,5,8,9)
GROUP BY
c.event_id,
a.barcode,
CASE WHEN d.[type] IN (2,8) THEN 'c' ELSE 's' END,
DATEADD(DAY, DATEDIFF(DAY, 0, a.scan_time), 0);
GO
CREATE UNIQUE CLUSTERED INDEX x
ON dbo.myview(event_id, barcode, [type], scan_date);
Now you can write a query that does something like this:
SELECT [date] = CONVERT(CHAR(8), scan_date, 112),
SUM(CASE WHEN [type] = 's' THEN total ELSE 0 END) AS total_scans,
SUM(CASE WHEN [type] = 'c' THEN total ELSE 0 END) AS total_creds,
COUNT(CASE WHEN [type] = 's' THEN 1 END) AS unique_scans,
COUNT(CASE WHEN [type] = 'c' THEN 1 END) AS unique_creds
FROM dbo.myview WITH (NOEXPAND) -- in case STD Edition
WHERE event_id = 21
AND scan_date BETWEEN '20110808' AND '20110814'
GROUP BY scan_date
UNION ALL
SELECT [date] = 'weekly',
SUM(CASE WHEN [type] = 's' THEN total ELSE 0 END) AS total_scans,
SUM(CASE WHEN [type] = 'c' THEN total ELSE 0 END) AS total_creds,
COUNT(DISTINCT CASE WHEN [type] = 's' THEN barcode END) AS unique_scans,
COUNT(DISTINCT CASE WHEN [type] = 'c' THEN barcode END) AS unique_creds
FROM dbo.myview WITH (NOEXPAND) -- in case STD Edition
WHERE event_id = 21
AND scan_date BETWEEN '20110808' AND '20110814'
ORDER BY [date];
This is all completely untested as your schema is a little bit cumbersome to try and create a complete repro of your system, but hopefully this gives you a general idea to work from...