Case Statement Questions regarding column names - sql

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;

Related

Sybase - Return only data from last three days

I am fairly new to this. I have a statement where I want to only return the last three days of data based on shipment_datedelivered. What date functions can I use to achieve this? I am using Sybase.
select dba.disp_ship.ds_id, dba.disp_ship.ds_origin_id, dba.disp_ship.ds_findest_id, dba.disp_ship.ds_billto_id, dba.disp_ship.ds_bill_charge, dba.disp_ship.ds_ref1_text,
dba.disp_ship.ds_status, dba.disp_ship.ds_bill_date, dba.disp_ship.ds_ship_date, dba.disp_ship.ds_ship_type, dba.disp_ship.movecode,
dba.companies.co_id, dba.companies.co_name, dba.current_shipments.cs_id, dba.current_shipments.cs_event_count, dba.current_shipments.cs_routed, dba.current_shipments.cs_assigned, dba.current_shipments.cs_completed, dba.current_shipments.shipment_datedelivered,
(CASE ds_status WHEN 'A' THEN 'TEMPLATE'
WHEN 'C' THEN 'CANCELLED'
WHEN 'D' THEN 'DECLINED'
WHEN 'E' THEN 'QUOTED'
WHEN 'F' THEN 'OFFERED'
WHEN 'H' THEN 'PENDING'
WHEN 'K' THEN 'OPEN'
WHEN 'N' THEN 'AUTHORIZED'
WHEN 'Q' THEN 'AUDIT REQUIRED'
WHEN 'T' THEN 'AUDITED'
WHEN 'W' THEN 'BILLED'
END) AS 'BILLING STATUS',
(CASE ds_ship_type WHEN '2201' THEN 'MONTREAL'
WHEN '2202' THEN 'DRYVAN'
WHEN '2203' THEN 'BROKERAGE'
WHEN '2204' THEN 'OLD BROKERAGE (NO GOOD)'
WHEN '2205' THEN 'LIFTING'
WHEN '2206' THEN 'WAREHOUSE'
END) AS 'DIVISION',
(CASE WHEN dba.current_shipments.cs_event_count = dba.current_shipments.cs_completed
THEN 'OPEN COMPLETED'
ELSE 'INCOMPLETE'
END)
AS 'STATUS'
from dba.disp_ship
inner join dba.companies ON dba.disp_ship.ds_billto_id=dba.companies.co_id
inner join dba.current_shipments ON dba.disp_ship.ds_id=DBA.current_shipments.cs_id
Well, I think I just got it. I added this to the end of my query and I am now getting the desired data.
where shipment_datedelivered >= dateadd(day, -3, GETDATE())

SUM Function with WHERE clause for each sum?

I have two tables: Staff and Hours.
Staff(200+ rows) with:
Staff_ID, Name, Position
each staff member only appears once in this table
Hours (1000+ rows) with:
Staff_ID, Hours, Amount, BillableFlag, Office, DatePeriod
each staff member appears many times in this table
I need a query that pulls in all Staff from the Staff table with position = 'Assistant' and the Hours and Amount columns from the Hours table summed twice each with different logic for each sum.
Something like this ( it's a query with some plain english to help with the explanation ):
select s.name,
sum(h.hours) as 'Hours_Not_Billable' --[NEED IT TO SUM ONLY HOURS WHERE h.BILLABLEFLAG <> 'Y', h.office = '2', h.period = 'Q3' AND ONLY DO IT FOR EACH STAFF MEMBER],
sum(h.amount) as 'Amount_Not_Billable' --[NEED IT TO SUM ONLY AMOUNT WHERE h.BILLABLEFLAG <> 'Y', h.office = '2', h.period = 'Q3' AND ONLY DO IT FOR EACH STAFF MEMBER],
sum(h.hours) as 'Hours_Billable' --[NEED IT TO SUM ONLY HOURS WHERE h.BILLABLEFLAG = 'Y', h.office = '2', h.period = 'Q3' AND ONLY DO IT FOR EACH STAFF MEMBER],
sum(h.amount) as 'Amount_Billable --[NEED IT TO SUM ONLY HOURS WHERE h.BILLABLEFLAG = 'Y', h.office = '2', h.period = 'Q3' AND ONLY DO IT FOR EACH STAFF MEMBER]'
from Staff S
left join Hours H on S.Staff_ID = H.Staff_ID
where s.position = 'Assistant'
group by s.name
Help much appreciated!
Thank you
Use conditional aggregation. The idea is to put a case expression inside the sum(), that filters out with values are taken into account.
Your pseudo-code would translate as:
select
s.name,
sum(case when h.billableflag <> 'Y' then h.hours else 0 end) hours_not_billable,
sum(case when h.billableflag <> 'Y' then h.amount else 0 end) amount_not_billable,
sum(case when h.billableflag = 'Y' then h.hours else 0 end) hours_billable,
sum(case when h.billableflag = 'Y' then h.amount else 0 end) amount_billable
from staff s
left join hours h
on s.staff_id = h.staff_id and h.office = 2 and h.period = 'Q3'
where s.position = 'Assistant'
group by s.name
Note: most of the conditions are common to all expressions, so I moved them to the on clause of the left join.
You can use CASE WHEN within SUM() aggregation function as follows
select
s.name,
sum(case when h.BILLABLEFLAG <> 'Y' and h.office = '2' and h.DatePeriod = 'Q3' then h.hours else null end) as 'Hours_Not_Billable',
sum(case when h.BILLABLEFLAG <> 'Y' and h.office = '2' and h.DatePeriod = 'Q3' then h.amount else null end) as 'Amount_Not_Billable',
sum(case when h.BILLABLEFLAG = 'Y' and h.office = '2' and h.DatePeriod = 'Q3' then h.hours else null end) as 'Hours_Billable',
sum(case when h.BILLABLEFLAG = 'Y' and h.office = '2' and h.DatePeriod = 'Q3' then h.amount else null end ) as 'Amount_Billable'
from Staff S
left join Hours H on S.Staff_ID = H.Staff_ID
where s.position = 'Assistant'
group by s.name

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.

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

Optimizing SQL Server 2012 Query

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