Optimizing SQL Server 2012 Query - sql

I have a query that runs for 12 hours.
The query does left joins on 5 tables and reports on a bunch of monthly metrics. Here is the query:
SELECT DATEPART(YYYY,Referral_dt) AS RefYear, DATEPART(MM,Referral_dt) AS RefMonth,
CASE
WHEN CAST(Referral_dt as date) BETWEEN '1/1/2013' AND '4/14/2013' THEN 'Q1'
WHEN CAST(Referral_dt as date) BETWEEN '4/15/2013' AND '7/14/2013' THEN 'Q2'
WHEN CAST(Referral_dt as date) BETWEEN '7/15/2013' AND '9/30/2013' THEN 'Q3'
WHEN CAST(Referral_dt as date) BETWEEN '10/1/2013' AND '12/31/2013' THEN 'Q4'
WHEN CAST(Referral_dt as date) BETWEEN '1/1/2014' AND '4/14/2014' THEN 'Q1'
WHEN CAST(Referral_dt as date) BETWEEN '4/15/2014' AND '7/14/2014' THEN 'Q2'
WHEN CAST(Referral_dt as date) BETWEEN '7/15/2014' AND '9/30/2014' THEN 'Q3'
WHEN CAST(Referral_dt as date) BETWEEN '10/1/2014' AND '12/31/2014' THEN 'Q4'
ELSE 'X' END as RefQtr,
crm.salesstatuscode, crm.Referral_State, crm.lead_source, mp.mcc_desc, mp.mcc_industry, sr.manager_name, sr.payrollname,
sr.region as Sales_Region,sr.market as Sales_Market, sr.saleschannel as SalesChannel, Bk.SuperRegion_Name as Bank_SuperRegion,
Bk.Region_Name as Bank_Region ,Bk.Division_Name as Bank_Division,
sum(case when crm.referral_state = 'Won' then 1 else 0 end) as referrals_won, sum(sv.projected_profit) as prj_profit,
sum(case when mp.proposal_Date is null then 0 else 1 end) as proposals_created, sum(ac.signed_annual_volume) as total_signed_volume,
sum(case when ac.Acct_Act_Date is null then 0 else 1 end) as activated_accounts, COUNT(*) as referral_count
into moagg1
FROM kaiserver.dbKAI.dbo.Referrals_CRM CRM
LEFT JOIN (SELECT p.merchant_id, CAST(p.proposal_create_dt as date) as Proposal_Date, m.mcc_desc, m.mcc_industry
from kaiserver.[dbKAI].[dbo].[proposals] p
left join (SELECT mcc, mcc_desc, mcc_industry from kaiserver.[dbKAI].[dbo].[merchantcategorycode]) m
on p.mcc = m.mcc where datepart(yyyy,proposal_create_dt) in ('2013', '2014')) mp
ON crm.merchant_id = mp.merchant_id
LEFT JOIN (SELECT account_no, CAST(Account_Activate_dt as date) as Acct_Act_Date, signed_annual_volume, average_tkt
from kaiserver.[dbKAI].[dbo].[Account]
where current_ind=1 and datepart(yyyy,account_submit_dt) in ('2013', '2014')) ac
ON crm.account_no = ac.account_no
LEFT JOIN (SELECT e1.repid, e1.repcode, e1.payrollname, e1.salesmanager, e2.payrollname as manager_name,
e1.region,e1.market, e1.saleschannel
FROM [fdserver].fdms.[dbo].[tbl_reps] e1 LEFT JOIN [fdserver].fdms.[dbo].[tbl_reps] e2
ON e1.salesmanager = e2.repid
WHERE e1.market not like ('%TEST%') and e1.payrollname is not null and e1.region is not null and e1.market is not null) SR
ON CRM.Sales_Rep_Cd = SR.Repcode
LEFT JOIN (SELECT [AU_name], [AU_Code] ,[SuperRegion_Name], [Region_Name] ,[Division_Name],
[SubDivision_Name] ,[District_Name] ,[SubDistrict_Name]
FROM kaiserver.[dbKAI].[dbo].[BankAU_Hierarchy]
WHERE [Reporting_Interval_Id] = '201410') BK
ON CRM.referral_au = BK.AU_code
LEFT JOIN (select merchantnumber, projected_profit from kaiserver.[dbKAI].[dbo].[SoldVolumeDetail]) sv
ON crm.account_no = sv.merchantnumber
WHERE DATEPART(YYYY, Referral_dt) in ('2013', '2014')
AND (crm.salesstatuscode <> 'DUPL' or crm.salesstatuscode is null)
AND crm.lead_source not in ('Test Lead', 'Bank Lead Placeholder')
group by DATEPART(YYYY,Referral_dt), DATEPART(MM,Referral_dt), crm.Referral_State, crm.salesstatuscode, crm.lead_source, mp.mcc_desc,
mp.mcc_industry, sr.manager_name, sr.payrollname, sr.region,sr.market, sr.saleschannel, Bk.SuperRegion_Name, Bk.Region_Name ,Bk.Division_Name,
CASE
WHEN CAST(Referral_dt as date) BETWEEN '1/1/2013' AND '4/14/2013' THEN 'Q1'
WHEN CAST(Referral_dt as date) BETWEEN '4/15/2013' AND '7/14/2013' THEN 'Q2'
WHEN CAST(Referral_dt as date) BETWEEN '7/15/2013' AND '9/30/2013' THEN 'Q3'
WHEN CAST(Referral_dt as date) BETWEEN '10/1/2013' AND '12/31/2013' THEN 'Q4'
WHEN CAST(Referral_dt as date) BETWEEN '1/1/2014' AND '4/14/2014' THEN 'Q1'
WHEN CAST(Referral_dt as date) BETWEEN '4/15/2014' AND '7/14/2014' THEN 'Q2'
WHEN CAST(Referral_dt as date) BETWEEN '7/15/2014' AND '9/30/2014' THEN 'Q3'
WHEN CAST(Referral_dt as date) BETWEEN '10/1/2014' AND '12/31/2014' THEN 'Q4'
ELSE 'X' END
When I run the full query as above, it runs for 12 hours. But when I run the query for 1 month, it runs in 8 minutes. So I want to run the query for each month and append into one file. That should make this query run in 2-3 hours.
I can use union and copy the code 24 times but that doesn't seem like the best way to do it. Is there a more programattic way to do this?
UPDATE: I want to be able to run this query every day to update the latest month's numbers.

By the looks of the execution plan you posted I think you have a missing join predicate and are generating a ton of intermediate rows:
Here's the same query cleaned up slightly (CTEs instead of correlated subqueries and replaced the CASE statement with DATEPART(QUARTER)), it might make it easier to tell where your missing predicate is:
WITH
m as (SELECT mcc, mcc_desc, mcc_industry from kaiserver.[dbKAI].[dbo].[merchantcategorycode]),
mp as (SELECT p.merchant_id, CAST(p.proposal_create_dt as date) as Proposal_Date, m.mcc_desc, m.mcc_industry
from kaiserver.[dbKAI].[dbo].[proposals] p
left join m on p.mcc = m.mcc where datepart(yyyy,proposal_create_dt) in ('2013', '2014')),
ac as (SELECT account_no, CAST(Account_Activate_dt as date) as Acct_Act_Date, signed_annual_volume, average_tkt
from kaiserver.[dbKAI].[dbo].[Account]
where current_ind=1 and datepart(yyyy,account_submit_dt) in ('2013', '2014')),
sr as (SELECT e1.repid, e1.repcode, e1.payrollname, e1.salesmanager, e2.payrollname as manager_name, e1.region,e1.market, e1.saleschannel
FROM [fdserver].fdms.[dbo].[tbl_reps] e1
LEFT JOIN [fdserver].fdms.[dbo].[tbl_reps] e2 ON e1.salesmanager = e2.repid
WHERE e1.market not like ('%TEST%') and e1.payrollname is not null and e1.region is not null and e1.market is not null),
bk as (SELECT [AU_name], [AU_Code], [SuperRegion_Name], [Region_Name] ,[Division_Name], [SubDivision_Name], [District_Name], [SubDistrict_Name]
FROM kaiserver.[dbKAI].[dbo].[BankAU_Hierarchy]
WHERE [Reporting_Interval_Id] = '201410'),
sv as (select merchantnumber, projected_profit from kaiserver.[dbKAI].[dbo].[SoldVolumeDetail])
SELECT DATEPART(YYYY,Referral_dt) AS RefYear, DATEPART(MM,Referral_dt) AS RefMonth, DATEPART(QUARTER, Referral_dt) as RefQtr,
crm.salesstatuscode, crm.Referral_State, crm.lead_source, mp.mcc_desc, mp.mcc_industry, sr.manager_name, sr.payrollname,
sr.region as Sales_Region,sr.market as Sales_Market, sr.saleschannel as SalesChannel, Bk.SuperRegion_Name as Bank_SuperRegion,
Bk.Region_Name as Bank_Region ,Bk.Division_Name as Bank_Division,
sum(case when crm.referral_state = 'Won' then 1 else 0 end) as referrals_won, sum(sv.projected_profit) as prj_profit,
sum(case when mp.proposal_Date is null then 0 else 1 end) as proposals_created, sum(ac.signed_annual_volume) as total_signed_volume,
sum(case when ac.Acct_Act_Date is null then 0 else 1 end) as activated_accounts, COUNT(*) as referral_count INTO moagg1
FROM kaiserver.dbKAI.dbo.Referrals_CRM CRM
LEFT JOIN mp ON crm.merchant_id = mp.merchant_id
LEFT JOIN ac ON crm.account_no = ac.account_no
LEFT JOIN sr ON crm.sales_rep_cd = sr.repcode
LEFT JOIN bk ON crm.referral_au = ck.au_code
LEFT JOIN sv ON crm.account_no = sv.merchantnumber
WHERE DATEPART(YYYY, Referral_dt) in ('2013', '2014')
AND (crm.salesstatuscode <> 'DUPL' or crm.salesstatuscode is null)
AND crm.lead_source not in ('Test Lead', 'Bank Lead Placeholder')
group by DATEPART(YYYY,Referral_dt), DATEPART(MM,Referral_dt), crm.Referral_State, crm.salesstatuscode, crm.lead_source, mp.mcc_desc,
mp.mcc_industry, sr.manager_name, sr.payrollname, sr.region,sr.market, sr.saleschannel, Bk.SuperRegion_Name, Bk.Region_Name ,Bk.Division_Name,
DATEPART(QUARTER, Referral_dt)

I think this produces identical output and it should be faster. Also, you need to ensure every field that is used for a JOIN or in the WHERE clause is indexed.
SELECT
DATEPART(YYYY,Referral_dt) AS RefYear, DATEPART(MM,Referral_dt) AS RefMonth,
CASE
WHEN CAST(Referral_dt as date) BETWEEN '1/1/2013' AND '4/14/2013' THEN 'Q1'
WHEN CAST(Referral_dt as date) BETWEEN '4/15/2013' AND '7/14/2013' THEN 'Q2'
WHEN CAST(Referral_dt as date) BETWEEN '7/15/2013' AND '9/30/2013' THEN 'Q3'
WHEN CAST(Referral_dt as date) BETWEEN '10/1/2013' AND '12/31/2013' THEN 'Q4'
WHEN CAST(Referral_dt as date) BETWEEN '1/1/2014' AND '4/14/2014' THEN 'Q1'
WHEN CAST(Referral_dt as date) BETWEEN '4/15/2014' AND '7/14/2014' THEN 'Q2'
WHEN CAST(Referral_dt as date) BETWEEN '7/15/2014' AND '9/30/2014' THEN 'Q3'
WHEN CAST(Referral_dt as date) BETWEEN '10/1/2014' AND '12/31/2014' THEN 'Q4'
ELSE 'X' END as RefQtr,
crm.salesstatuscode, crm.Referral_State, crm.lead_source, m.mcc_desc, m.mcc_industry, e2.manager_name, e1.payrollname,
e1.region as Sales_Region,e1.market as Sales_Market, e1.saleschannel as SalesChannel, Bk.SuperRegion_Name as Bank_SuperRegion,
Bk.Region_Name as Bank_Region ,Bk.Division_Name as Bank_Division,
sum(case when crm.referral_state = 'Won' then 1 else 0 end) as referrals_won, sum(sv.projected_profit) as prj_profit,
sum(case when p.proposal_Date is null then 0 else 1 end) as proposals_created, sum(ac.signed_annual_volume) as total_signed_volume,
sum(case when ac.Acct_Act_Date is null then 0 else 1 end) as activated_accounts, COUNT(*) as referral_count
into moagg1
FROM kaiserver.dbKAI.dbo.Referrals_CRM CRM
LEFT kaiserver.[dbKAI].[dbo].[proposals] p ON crm.merchant_id = p.merchant_id
AND datepart(yyyy,p.proposal_create_dt) in ('2013', '2014')
left join kaiserver.[dbKAI].[dbo].[merchantcategorycode] m on p.mcc = m.mcc
LEFT JOIN kaiserver.[dbKAI].[dbo].[Account] ac ON crm.account_no = ac.account_no
AND ac.current_ind=1
AND and datepart(yyyy,ac.account_submit_dt) in ('2013', '2014')
LEFT JOIN [fdserver].fdms.[dbo].[tbl_reps] e1 ON e1.repcode=CRM.Sales_Rep_Cd
AND e1.market not like ('%TEST%')
and e1.payrollname is not null
and e1.region is not null
and e1.market is not null
LEFT JOIN [fdserver].fdms.[dbo].[tbl_reps] e2 ON e1.salesmanager = e2.repid
LEFT JOIN kaiserver.[dbKAI].[dbo].[BankAU_Hierarchy] BK ON CRM.referral_au = BK.AU_code
AND [Reporting_Interval_Id] = '201410'
LEFT JOIN kaiserver.[dbKAI].[dbo].[SoldVolumeDetail] sv ON crm.account_no = sv.merchantnumber
WHERE DATEPART(YYYY, CRM.Referral_dt) in ('2013', '2014')
AND ISNULL(crm.salesstatuscode,'') <> 'DUPL'
AND crm.lead_source not in ('Test Lead', 'Bank Lead Placeholder')
group by DATEPART(YYYY,Referral_dt), DATEPART(MM,Referral_dt), crm.Referral_State, crm.salesstatuscode, crm.lead_source, mp.mcc_desc,
mp.mcc_industry, sr.manager_name, sr.payrollname, sr.region,sr.market, sr.saleschannel, Bk.SuperRegion_Name, Bk.Region_Name ,Bk.Division_Name,
CASE
WHEN CAST(Referral_dt as date) BETWEEN '1/1/2013' AND '4/14/2013' THEN 'Q1'
WHEN CAST(Referral_dt as date) BETWEEN '4/15/2013' AND '7/14/2013' THEN 'Q2'
WHEN CAST(Referral_dt as date) BETWEEN '7/15/2013' AND '9/30/2013' THEN 'Q3'
WHEN CAST(Referral_dt as date) BETWEEN '10/1/2013' AND '12/31/2013' THEN 'Q4'
WHEN CAST(Referral_dt as date) BETWEEN '1/1/2014' AND '4/14/2014' THEN 'Q1'
WHEN CAST(Referral_dt as date) BETWEEN '4/15/2014' AND '7/14/2014' THEN 'Q2'
WHEN CAST(Referral_dt as date) BETWEEN '7/15/2014' AND '9/30/2014' THEN 'Q3'
WHEN CAST(Referral_dt as date) BETWEEN '10/1/2014' AND '12/31/2014' THEN 'Q4'
ELSE 'X' END

Related

Alternative to using CASE in a GROUP BY

I am trying to find a more compact code form and faster way to execute a query that requires (or at least I think requires) grouping by TWO case statements
I've tried using OVER PARTITION but can't seem to get the desired result
SELECT
CASE
WHEN AA.BUSINESS_SEGMENT LIKE 'YEPPERS%'
THEN 'YES'
ELSE 'NO'
END 'YZY',
CASE
WHEN MONTH(POI.EX_FACTORY_DATE) >= 1 AND MONTH(POI.EX_FACTORY_DATE) <=3
THEN
'Q1'
WHEN MONTH(POI.EX_FACTORY_DATE) >= 4 AND MONTH(POI.EX_FACTORY_DATE) <=6
THEN
'Q2'
WHEN MONTH(POI.EX_FACTORY_DATE) >= 7 AND MONTH(POI.EX_FACTORY_DATE) <=9
THEN
'Q3'
WHEN MONTH(POI.EX_FACTORY_DATE) >= 10 AND MONTH(POI.EX_FACTORY_DATE) <=12
THEN
'Q4'
END 'QTR',
SUM(POI.PO_ORDERED_QUANTITY) PO_QTY
FROM VW_PO_ITEM POI
LEFT JOIN VW_ARTICLE_ATTRIBUTES AA ON AA.ARTICLE = POI.MATERIAL
WHERE POI.DEL_INDICATOR <> 'L' AND POI.EX_FACTORY_DATE BETWEEN '7/1/2019' AND '12/31/2019' AND ((POI.SHIPPING_INSTRUCT='A2' AND AA.BUSINESS_SEGMENT NOT LIKE 'YEPPERS%') OR AA.BUSINESS_SEGMENT LIKE 'YEPPERS%')
GROUP BY
CASE
WHEN AA.BUSINESS_SEGMENT LIKE 'YEPPERS%'
THEN 'YES'
ELSE 'NO'
END,
CASE
WHEN MONTH(POI.EX_FACTORY_DATE) >= 1 AND MONTH(POI.EX_FACTORY_DATE) <=3
THEN
'Q1'
WHEN MONTH(POI.EX_FACTORY_DATE) >= 4 AND MONTH(POI.EX_FACTORY_DATE) <=6
THEN
'Q2'
WHEN MONTH(POI.EX_FACTORY_DATE) >= 7 AND MONTH(POI.EX_FACTORY_DATE) <=9
THEN
'Q3'
WHEN MONTH(POI.EX_FACTORY_DATE) >= 10 AND MONTH(POI.EX_FACTORY_DATE) <=12
THEN
'Q4'
END
--desired result (the query above does produce this)
YZY QTR PO_QTY
-------- ---- ---------------------------------------
NO Q4 389309
YES Q4 649842
YES Q3 843438
NO Q3 20146
I think better is use DATEPART(quarter
FROM MyTable
GROUP BY DATEPART(quarter, columndate)
Consider a CTE to handle unit level calculation before final aggregation, avoiding repetition. Also, look into DatePart to extract date parts from datetime fields:
WITH cte AS (
SELECT CASE
WHEN AA.BUSINESS_SEGMENT LIKE 'YEPPERS%'
THEN 'YES' ELSE 'NO'
END [YZY],
DATEPART(qq, POI.EX_FACTORY_DATE) AS [QTR],
POI.PO_ORDERED_QUANTITY
FROM VW_PO_ITEM POI
LEFT JOIN VW_ARTICLE_ATTRIBUTES AA
ON AA.ARTICLE = POI.MATERIAL
WHERE POI.DEL_INDICATOR <> 'L'
AND POI.EX_FACTORY_DATE BETWEEN '2019-07-01' AND '2019-12-31'
AND (
(POI.SHIPPING_INSTRUCT='A2'
AND AA.BUSINESS_SEGMENT NOT LIKE 'YEPPERS%')
OR
AA.BUSINESS_SEGMENT LIKE 'YEPPERS%'
)
)
SELECT [YZY], [QTR],
SUM(POI.PO_ORDERED_QUANTITY) AS PO_QTY
FROM cte
GROUP BY [YZY], [QTR]

How to make one row from result

I am getting following result by using my store procedure. How would I get only one line of result after eliminate the nulls. ?
`cte_Sum
as
(
Select sum(NumberOfCode) as NumberOfCode, CodeName, Code, Quarters, Q1s, Q2s, Q3s, Q4s
from cte_totals
group by CodeName, Code, Quarters, Q1s, Q2s, Q3s, Q4s
)
Select
CodeName,Code,
Case When Quarters = 'Q1' Then NumberOfCode End as Q1_Number,
Case When Quarters = 'Q1' Then Q1s End as Q1_Date,
Case When Quarters = 'Q2' Then NumberOfCode End as Q2_Number,
Case When Quarters = 'Q2' Then Q2s End as Q2_Date,
Case When Quarters = 'Q3' Then NumberOfCode End as Q3_Number,
Case When Quarters = 'Q3' Then Q3s End as Q3_Date,
Case When Quarters = 'Q4' Then NumberOfCode End as Q4_Number,
Case When Quarters = 'Q4' Then Q4s End as Q4_Date
from cte_Sum`
Expected result.
I will self left join with itself for those lines where Q2 - Q4 columns are not NULL.
select t1.CodeName ,t1.Code ,
Q2.Q2_NUmber, Q2.Q2_DAte,
Q3.Q3_NUmber, Q3.Q3_DAte,
Q4.Q4_NUmber, Q4.Q4_DAte
from table t1
left join (select Code, Q2_Number, Q2_Date where Q2_Number is not NULL) Q2 on t1.Code = Q2.Code
left join (select Code, Q3_Number, Q3_Date where Q3_Number is not NULL) Q3 on t1.Code = Q3.Code
left join (select Code, Q4_Number, Q4_Date where Q4_Number is not NULL) Q4 on t1.Code = Q4.Code
Use aggregation:
Select CodeName, Code,
sum(Case When Quarters = 'Q1' Then NumberOfCode End) as Q1_Number,
max(Case When Quarters = 'Q1' Then Q1s End) as Q1_Date,
sum(Case When Quarters = 'Q2' Then NumberOfCode End) as Q2_Number,
max(Case When Quarters = 'Q2' Then Q2s End) as Q2_Date,
sum(Case When Quarters = 'Q3' Then NumberOfCode End) as Q3_Number,
max(Case When Quarters = 'Q3' Then Q3s End) as Q3_Date,
sum(Case When Quarters = 'Q4' Then NumberOfCode End) as Q4_Number,
max(Case When Quarters = 'Q4' Then Q4s End) as Q4_Date
from cte_Sum
group by CodeName, Code;
I don't think the CTE helps. You can also do:
Select CodeName, Code,
sum(Case When Quarters = 'Q1' Then NumberOfCode else 0 End) as Q1_Number,
max(Case When Quarters = 'Q1' Then Q1s End) as Q1_Date,
sum(Case When Quarters = 'Q2' Then NumberOfCode else 0 End) as Q2_Number,
max(Case When Quarters = 'Q2' Then Q2s End) as Q2_Date,
sum(Case When Quarters = 'Q3' Then NumberOfCode else 0 End) as Q3_Number,
max(Case When Quarters = 'Q3' Then Q3s End) as Q3_Date,
sum(Case When Quarters = 'Q4' Then NumberOfCode else 0 End) as Q4_Number,
max(Case When Quarters = 'Q4' Then Q4s End) as Q4_Date
from cte_totals
group by CodeName, Code;
You may also be able to simplify out the cte_totals as well, although your question doesn't show that code.

Using subquery alias in case

I'm having hard time using a subquery alias in one of my CASE, after spending my time in documentation I cant find the solution on my own.
SELECT
t1.cardcode as Kundennummer,
t1.cardname,
t3.groupname,
(select
sum(t11.doctotal)as sum24
from
oinv t11
where
t11.cardcode=t1.cardcode
and t11.docduedate > dateadd(month, -24, getdate()) and t11.docduedate < dateadd(month, -12, getdate())
)as Umsatz24,
(select
sum(t10.doctotal) as sum12
from
oinv t10
where
t10.cardcode=t1.cardcode
and t10.docduedate > dateadd(month, -12, getdate())
)as Umsatz12,
case
when t3.groupname = 'C' and Umsatz12 = 0
then 'Dummy 0'
when t3.groupname = 'C' and Umsatz12 > 0
then 'Dummy 15'
when t3.groupname = 'B' and Umsatz24 = 0
then 'Dummy 15'
else
'Dummy 15/30?'
end as 'Dummy'
from
(... some code)
Any idea how I could fix it?
Thanks in advance.
You can use CTE for this.
;WITH T AS
(
SELECT
t1.cardcode as Kundennummer,
t1.cardname,
t3.groupname,
(select
sum(t11.doctotal)as sum24
from
oinv t11
where
t11.cardcode=t1.cardcode
and t11.docduedate > dateadd(month, -24, getdate()) and t11.docduedate < dateadd(month, -12, getdate())
)as Umsatz24,
(select
sum(t10.doctotal) as sum12
from
oinv t10
where
t10.cardcode=t1.cardcode
and t10.docduedate > dateadd(month, -12, getdate())
)as Umsatz12
from
(... some code)
)
SELECT *,
case
when groupname = 'C' and Umsatz12 = 0
then 'Dummy 0'
when groupname = 'C' and Umsatz12 > 0
then 'Dummy 15'
when groupname = 'B' and Umsatz24 = 0
then 'Dummy 15'
else
'Dummy 15/30?'
end as 'Dummy'
FROM T
I'd move the subqueries to the FROM clause and make this one query instead of two by using conditional aggregation:
select
t1.cardcode as kundennummer,
t1.cardname,
t3.groupname,
umsatz.umsatz24,
umsatz.umsatz12,
case
when t3.groupname = 'C' and umsatz.umsatz12 = 0 then 'Dummy 0'
when t3.groupname = 'C' and umsatz.umsatz12 > 0 then 'Dummy 15'
when t3.groupname = 'B' and umsatz.umsatz24 = 0 then 'Dummy 15'
else 'Dummy 15/30?'
end as dummy
from (... some code)
left join
(
select
cardcode,
sum(case when oinv.docduedate > dateadd(month, -24, getdate())
and oinv.docduedate < dateadd(month, -12, getdate())
then oinv.doctotal end) as umsatz24
sum(case when oinv.docduedate > dateadd(month, -12, getdate())
then oinv.doctotal end) as umsatz12
from oinv
group by cardcode
) umsatz on umsatz.cardcode = t1.cardcode;
You can use below approach.
you can execute and test the query here
select cc.CID,cc.CustomerName,cc.ContactName,cc.City,cc.Umsatz24,cc.Umsatz12,
case
when cc.City = 'London' and cc.Umsatz12 = 0
then 'Dummy 0'
when cc.City = 'London' and cc.Umsatz12 > 0
then 'Dummy 15'
when cc.City = 'Paris' and cc.Umsatz24 = 0
then 'Dummy 15'
else
'Dummy 15/30?'
end as 'Dummy'
from (
SELECT
t1.CustomerID as CID,
t1.CustomerName,
t1.ContactName,
t1.City,
(select
sum(t11.CustomerID)as sum24
from
Customers t11
where
t11.CustomerID=t1.CustomerID
and t11.City = 'Paris'
)as Umsatz24,
(select
sum(t10.CustomerID) as sum12
from
Customers t10
where
t10.CustomerID=t1.CustomerID
and t10.City = 'London'
)as Umsatz12
from Customers t1
) cc

SQL - Average on DateDiff with taking out weekends

I have an SQL statement that calculates how many days late our vendors pay for invoices. It only includes weekdays and it works perfectly. My customer is now asking if I can have an average of those days late per vendor. Here is my code that works:
DATEDIFF(dd, PURCHTABLE.CONFIRMEDDLV, MAX(VENDPACKINGSLIPJOUR.DELIVERYDATE))
-(DATEDIFF(wk, PURCHTABLE.CONFIRMEDDLV, MAX(VENDPACKINGSLIPJOUR.DELIVERYDATE)) * 2)
-(CASE WHEN DATENAME(dw, PURCHTABLE.CONFIRMEDDLV) = 'Sunday'
THEN 1
ELSE 0
END)
-(CASE WHEN DATENAME(dw, MAX(VENDPACKINGSLIPJOUR.DELIVERYDATE)) = 'Saturday'
THEN 1
ELSE 0
END) AS 'DAYS LATE'
If I try to put this in an AVG(), but it tells me I cannot perform an aggregate function on an aggregate function.
UPDATE:
This is my original SQL:
SELECT
PURCHTABLE.PURCHNAME AS 'VENDOR NAME',
PURCHTABLE.ORDERACCOUNT AS 'VENDOR NUMBER',
COUNT(DISTINCT PURCHTABLE.PURCHID) AS 'PURCHASE ORDER',
COUNT(PURCHLINE.LINENUMBER) AS 'NUMBER OF LINES',
SUM(PURCHLINE.LINEAMOUNT) AS 'PO PRICE TOTAL',
DATEDIFF(dd, PURCHTABLE.CONFIRMEDDLV, MAX(VENDPACKINGSLIPJOUR.DELIVERYDATE))-(DATEDIFF(wk, PURCHTABLE.CONFIRMEDDLV, MAX(VENDPACKINGSLIPJOUR.DELIVERYDATE)) * 2)-(CASE WHEN DATENAME(dw, PURCHTABLE.CONFIRMEDDLV) = 'Sunday' THEN 1 ELSE 0 END)-(CASE WHEN DATENAME(dw, MAX(VENDPACKINGSLIPJOUR.DELIVERYDATE)) = 'Saturday' THEN 1 ELSE 0 END) AS 'DAYS LATE'
FROM
PURCHTABLE
JOIN
PURCHLINE ON PURCHLINE.PURCHID = PURCHTABLE.PURCHID
JOIN
VENDPACKINGSLIPJOUR ON VENDPACKINGSLIPJOUR.PURCHID = PURCHTABLE.PURCHID
WHERE
PURCHTABLE.DELIVERYDATE >= '2017-01-01'
AND
PURCHTABLE.DELIVERYDATE <= '2017-01-20'
AND
PURCHTABLE.ORDERACCOUNT = 'VN03526'
GROUP BY
PURCHTABLE.PURCHNAME,
PURCHTABLE.ORDERACCOUNT,
PURCHTABLE.DELIVERYDATE,
PURCHTABLE.CONFIRMEDDLV
So I don't quite understand how I change that to what you are saying.....I'm tried this but it's not working.
SELECT
PURCHTABLE.PURCHNAME AS 'VENDOR NAME',
PURCHTABLE.ORDERACCOUNT AS 'VENDOR NUMBER'
FROM
(SELECT
PURCHTABLE.PURCHNAME AS 'VENDOR NAME',
PURCHTABLE.ORDERACCOUNT AS 'VENDOR NUMBER',
COUNT(DISTINCT PURCHTABLE.PURCHID) AS 'PURCHASE ORDER',
COUNT(PURCHLINE.LINENUMBER) AS 'NUMBER OF LINES',
SUM(PURCHLINE.LINEAMOUNT) AS 'PO PRICE TOTAL',
DATEDIFF(dd, PURCHTABLE.CONFIRMEDDLV, MAX(VENDPACKINGSLIPJOUR.DELIVERYDATE))-(DATEDIFF(wk, PURCHTABLE.CONFIRMEDDLV, MAX(VENDPACKINGSLIPJOUR.DELIVERYDATE)) * 2)-(CASE WHEN DATENAME(dw, PURCHTABLE.CONFIRMEDDLV) = 'Sunday' THEN 1 ELSE 0 END)-(CASE WHEN DATENAME(dw, MAX(VENDPACKINGSLIPJOUR.DELIVERYDATE)) = 'Saturday' THEN 1 ELSE 0 END) AS 'DAYS LATE'
FROM
PURCHTABLE
JOIN
PURCHLINE ON PURCHLINE.PURCHID = PURCHTABLE.PURCHID
JOIN
VENDPACKINGSLIPJOUR ON VENDPACKINGSLIPJOUR.PURCHID = PURCHTABLE.PURCHID
WHERE
PURCHTABLE.DELIVERYDATE >= '2017-01-01'
AND
PURCHTABLE.DELIVERYDATE <= '2017-01-20'
AND
PURCHTABLE.ORDERACCOUNT = 'VN03526') A
GROUP BY
PURCHTABLE.PURCHNAME,
PURCHTABLE.ORDERACCOUNT,
PURCHTABLE.DELIVERYDATE,
PURCHTABLE.CONFIRMEDDLV
The code you have at the moment will be part of a larger query, such as:
select VendorID
,VendorName
...
...
,<Your Days Late Code> as DaysLate
,InvoiceAmount
...
from tables
group by VendorID
,VendorName
all you need to do to average over all of this is pick the other columns you want to do the average by and wrap the whole thing in another select statement:
select VendorID
,VendorName
,avg(DaysLate) as AverageDaysLate
,sum(InvoiceAmount) as TotalInvoiceAmount
from(
select VendorID
,VendorName
...
...
,<Your Days Late Code> as DaysLate
,InvoiceAmount
...
from tables
group by VendorID
,VendorName
) a
group by VendorID
,VendorName

Case Statement Questions regarding column names

In the following, I have a case statement. I am wondering if it's possible to have three separate columns in this case statement. Obviously, the 'else end' statement provides the 'Dependents', 'Employees', and 'Spouse' in a 'Relationship' column. I am looking to have 'Employee', 'Spouse', and 'Dependent' to be in their own column.
select
Convert (varchar(6),x.mem_date,112) as IncurMonth,
e.Meme_lev2 as Group#,
e.MEME_GRPN as Groupname,
--MONTH(x.mem_date) AS mem_date,
case when m.mem_rel = '01' then 'Employee'
when m.mem_rel = '02' then 'Spouse'
--when m.MEM_REL = '03' then 'Child'
--when m.MEM_REL = '04' then 'Child/No Financial Resp.'
--when m.MEM_REL = '05' then 'Step child'
--when m.MEM_REL = '06' then 'Foster child'
--when m.MEM_REL = '07' then 'Guardian/POA'
else 'Dependent' end as Relationship,
COUNT(*) as "Members/Subscribers"
from Impact.dbo.tbl_mem m
left join Impact.dbo.tbl_meme e on e.MEME_ID1 = m.MEM_ID1
inner join impactwork.dbo.tbl_mmonth x on x.mem_date between convert(varchar(10), e.meme_eff, 101) and convert(varchar(10), e.meme_trm, 101)
where e.MEME_LEV2 IN ('52032')
and x.mem_date between '01/01/2015' and '03/31/2015'
and meme_rank='900'
group by
e.Meme_lev2,
e.MEME_GRPN,
Convert (varchar(6),x.mem_date,112),
case when m.mem_rel = '01' then 'Employee'
when m.mem_rel = '02' then 'Spouse'
--when m.MEM_REL = '03' then 'Child'
--when m.MEM_REL = '04' then 'Child/No Financial Resp.'
--when m.MEM_REL = '05' then 'Step child'
--when m.MEM_REL = '06' then 'Foster child'
--when m.MEM_REL = '07' then 'Guardian/POA'
else 'Dependent' end
order by group#, Convert (varchar(6),x.mem_date,112), [members/subscribers] desc
IncurMonth Group# Groupname Relationship Members/Subscribers
201501 52005 Rosco LABORATORIES Employee 30
201501 52005 Rosco LABORATORIES Dependent 32
201501 52005 Rosco LABORATORIES Spouse 14
201501 52005 Rosco LABORATORIES RETIREE AR Employee 17
201501 52005 Rosco LABORATORIES RETIREE AR Spouse 6
You can use conditional aggregation to do this. Replace your case statement with an aggregate function with a conditional expression as argument (so that you only count the rows matching the expression).
I used sum below, but you could just as well use count:
count(case when m.mem_rel = '01' then m.mem_rel end) 'Employee',
also remove the expression from the group by clause as you're now using it as an aggregate and should not group by it.
select
Convert(varchar(6),x.mem_date,112) as IncurMonth,
e.Meme_lev2 as Group#,
e.MEME_GRPN as Groupname,
--MONTH(x.mem_date) AS mem_date,
sum(case when m.mem_rel = '01' then 1 else 0 end) 'Employee',
sum(case when m.mem_rel = '02' then 1 else 0 end) 'Spouse',
sum(case when m.MEM_REL NOT IN ('01','02') then 1 else 0 end) 'Dependent',
COUNT(*) as "Members/Subscribers"
from Impact.dbo.tbl_mem m
left join Impact.dbo.tbl_meme e on e.MEME_ID1 = m.MEM_ID1
inner join impactwork.dbo.tbl_mmonth x on x.mem_date between convert(varchar(10), e.meme_eff, 101)
and convert(varchar(10), e.meme_trm, 101)
where e.MEME_LEV2 IN ('52032')
and x.mem_date between '01/01/2015' and '03/31/2015'
and meme_rank='900'
group by
e.Meme_lev2,
e.MEME_GRPN,
Convert(varchar(6),x.mem_date,112)
order by group#, Convert(varchar(6),x.mem_date,112), [members/subscribers] desc;