SQL: I need advice on how best to accomplish a complicated query - sql-server
I'm working on a complicated query that I need to produce for a report. The query gives me what I need, but takes about 5 mins to run. For a report, this isn't acceptable, so I want to dump these results into a table via an overnight job and truncate the table before it runs each time. Where I'm running into trouble is how best to accomplish this, given how the query is structured, so I was hoping to get input on how I might do this. I'll break the query down as best I can into a mile-high view below:
CREATE TABLE #SALESDATA
(
...
)
INSERT INTO #SALESDATA
EXEC STAGING_DATA_PROC
WITH CTE1 AS
(
PRELIMINARY DATA 1
JOINED WITH #SALESDATA
),
CTE2 AS
(
PRELIMINARY DATA 2
JOINED WITH #SALESDATA
)
So what I first attempted to do is tried to circumvent the STAGING_DATA_PROC by just making it a query in its place, but it itself contains a few INSERTS into temp tables and doesn't seem to like the nesting of inserts in that order.
Any insight into how I might go about this?
UPDATE 1: This is the SQL that is taking about 5 mins to run. I have since replaced my SP feeding a temp table to a stand alone table that gives results instantly.
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 as std_StandardAcctNo
,b.salesperson
,isnull(ac.counter,0) [Appearance_Count]
,isnull(b.[Year],0) [The_Year]
,isnull(b.[Month],0) [The_Month]
,isnull(b.customer,0) [CustomerName]
,sum(isnull(b.Gallons,0)) [Gallon_Qty]
,sum(isnull(b.sales,0)) [Total_Sale]
,sum(isnull(b.gm,0)) [Total_Gross_Profit]
from (select distinct a.year
,a.month
,b.customer
,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 IdealElephantSalesData a
join (select distinct customer from IdealElephantSalesData) b on 1 = 1
) a
join RicoCustom..Appearance_Count ac on a.customer = ac.customer_alias
left join IdealElephantSalesData b on a.customer = b.customer and a.Month = b.Month and a.Year = b.Year
group by a.order_num
,a.Period_Date
,a.year
,a.Month
,a.customer
,b.salesperson
,ac.counter
,b.[Year]
,b.[Month]
,b.customer
)
, saleslist as (
select distinct salesperson
,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, Appearance_Count, Period_Date, std_StandardAcctNo,std_the_month,std_the_year
), core_GP as (
select distinct a.customer
,convert(date,convert(varchar(2),a.month) + '/01/' + convert(varchar(4),a.year)) as Period_Date
,sum(a.gm) as Period_GP
from IdealElephantSalesData a
join RicoCustom..Appearance_Count ac on ac.customer_alias = a.customer
group by counter, convert(date,convert(varchar(2),a.month) + '/01/' + convert(varchar(4),a.year)), a.customer
), 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
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 is not null then bd.salesperson
when c.salesperson is not null then c.salesperson
when d.salesperson is not null then d.salesperson
when e.salesperson is not null then e.salesperson
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 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 is not null then bd.salesperson else c.salesperson end = c.salesperson
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 is not null then bd.salesperson when c.salesperson is not null then c.salesperson else d.salesperson end = d.salesperson
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 is not null then bd.salesperson when c.salesperson is not null then c.salesperson when d.salesperson is not null then d.salesperson else e.salesperson end = e.salesperson
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 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
GO
Have you tried breaking your complicated query into smaller queries that load the data into temporary tables. You can use the temporary tables to build your final result. With the temporary tables, you can build the necessary indexes against them to ensure better performance. Additionally, you will be working with smaller subsets of the data which should result in better performance.
Related
SQL query filling up tempdb
I am running the below query which is failing when it fills up the tempdb (170GB). It fails after around 1 hour. the script below : --Select Query BOM collection retail report Declare #Company Nvarchar(50) ='HMFI' Declare #Product Nvarchar(50) =Null select Upper (Be.DataAreaId)Company ,BE.BOM,BE.Product ,Max(ProItemName)ProItemName ,Max(ProUnitID)ProUnitID ,Be.Material,Max(MaterialItemName)MaterialItemName ,Be.UNITID MaterialUnitID ,Sum (Be.BOMQTY)MaterialQty ,Max (MaterialService) MaterialType from ExpBom_HMFI BE Outer Apply (SELECT UNITID ProUnitID FROM INVENTTABLEMODULE A With (Nolock) WHERE DATAAREAID = #Company AND A.ITEMID =BE.Product AND MODULETYPE = 0)ProUnitID Outer Apply(SELECT ITEMNAME ProItemName FROM INVENTTABLE B With (Nolock) WHERE DATAAREAID = #Company AND B.ITEMID = BE.Product)ProItemName Outer Apply(SELECT ITEMNAME MaterialItemName FROM INVENTTABLE C With (Nolock) WHERE DATAAREAID = #Company AND C.ITEMID = Be.Material)MaterialItemName Outer Apply(SELECT Case When ITEMTYPE=0 Then 'Item' When ITEMTYPE=1 Then 'BOM' When ITEMTYPE=2 Then 'Service Item' End MaterialService FROM INVENTTABLE With (Nolock) WHERE DATAAREAID = #Company AND ITEMID = Be.Material)MaterialService Where BE.DataAreaId in (#Company) and (#Product Is null Or Be.Product In(Select StringValue From Split(#Product,','))) Group by Be.DataAreaId,BE.BOM,BE.Product,Be.Material ,Be.UNITID Order By Be.DataAreaId,BE.BOM,BE.Product,Be.Material option (maxrecursion 0) --now Viewing the data collected with ExpBom ( DataAreaId, Bom, Product, Material, BomDepth, BOMQTY, Unitid, BomPath ) as ( select bv.DataAreaId, bv.BomId, bv.ItemId, b.ItemId, 1, Convert (NUMERIC(18,8), b.BOMQTY) BOMQTY, Convert (Nvarchar(10),b.UNITID )Unitid, convert(Nvarchar(max), bv.ItemId + '|' + b.ItemId) as BomPath from BomVersion bv With (Nolock) join InventTable ibv With (Nolock) on ibv.DataAreaId = bv.DataAreaId and ibv.ItemId = bv.ItemId join Bom b With (Nolock) on b.DataAreaId = bv.DataAreaId and b.BomId = bv.BomId join InventTable ib With (Nolock) on ib.DataAreaId = b.DataAreaId and ib.ItemId = b.ItemId where bv.Approved = 1 and bv.Active = 1 and bv.FromDate < getdate() and (bv.ToDate = '01-01-1900' or bv.ToDate >= getdate()) and b.FromDate < getdate() and (b.ToDate = '01-01-1900' or b.ToDate >= getdate()) and b.DATAAREAID in ('HMFI') union all select bv.DataAreaId, bv.BomId, bv.ItemId, eb.Material, eb.BomDepth + 1, Convert (NUMERIC(18,8),B.BOMQTY * eb.BOMQTY)BOMQTY, Convert (Nvarchar(10),eb.UNITID )Unitid, convert(Nvarchar(max), bv.ItemId + '|' + eb.BomPath) as BomPath from BomVersion bv With (Nolock) join InventTable ibv With (Nolock) on ibv.DataAreaId = bv.DataAreaId and ibv.ItemId = bv.ItemId join Bom b With (Nolock) on b.DataAreaId = bv.DataAreaId and b.BomId = bv.BomId join ExpBom eb on eb.DataAreaId = b.DataAreaId and eb.Product = b.ItemId where bv.Approved = 1 and bv.Active = 1 and bv.FromDate < getdate() and (bv.ToDate = '01-01-1900' or bv.ToDate >= getdate()) and b.FromDate < getdate() and (b.ToDate = '01-01-1900' or b.ToDate >= getdate()) and b.DATAAREAID in ('HMFI') ) select * from ExpBOM Where Material Not in (Select BOMV.ITEMID From BomVersion BOMV With (Nolock) Where BOMV.DataAreaId In( 'HMFI' ) and BOMV.Approved = 1 and BOMV.Active = 1 and BOMV.FromDate < getdate() and (BOMV.ToDate = '01-01-1900' or BOMV.ToDate >= getdate()) ) I'm not sure if the JOINS are causing the issue Estimated execution plan is below: Data collection : https://www.brentozar.com/pastetheplan/?id=S1UsXn4Po Data view: https://www.brentozar.com/pastetheplan/?id=BJDUBn4wi Please advise this report was working fine on daily basis without filling tempdb usualy it was taking 1 min to execute suddenly it stoped for unknown reason although there's no changes done on server/database levels
T-SQL, repeated same scalar subquery performance in views
Below is a simple query that retrieves Students and their exam results. The same student can take the same exam multiple times. The subqueries retrieve the latest exam results for each student. As you can see, the Line X (which retrieves the latest Exam ID) is exactly the same in every subquery for each row. How to store or cache the result of Line X to prevent three times execution for each row? I cannot use stored procedure or functions for this task, it has to be a VIEW for additional filtering. SELECT S.*, ( SELECT COUNT(*) FROM ExamAnswers WHERE IsCorrectAnswer IS NOT NULL AND IsCorrectAnswer = 1 AND ExamID = (SELECT TOP(1) ID FROM Exams E WHERE E.StudentID = S.ID ORDER BY ID DESC) --Line X ) CorrectAnswerCount, ( SELECT COUNT(*) FROM ExamAnswers EA WHERE EA.IsCorrectAnswer IS NOT NULL AND EA.IsCorrectAnswer = 0 AND EA.ExamID = (SELECT TOP(1) ID FROM Exams E WHERE E.StudentID = S.ID ORDER BY ID DESC) --Line X ) WrongAnswerCount, ( SELECT COUNT(*) FROM ExamAnswers WHERE IsCorrectAnswer IS NULL AND ExamID = (SELECT TOP(1) ID FROM Exams E WHERE E.StudentID = S.ID ORDER BY ID DESC) --Line X ) UnansweredQuestionCount FROM Students S
You can do it like this SELECT S.*, CA.* FROM Students S CROSS APPLY (SELECT SUM(CASE WHEN IsCorrectAnswer = 1 THEN 1 ELSE 0 END) AS CorrectAnswerCount, SUM(CASE WHEN IsCorrectAnswer = 0 THEN 1 ELSE 0 END) AS WrongAnswerCount, SUM(CASE WHEN IsCorrectAnswer IS NULL THEN 1 ELSE 0 END) AS UnansweredQuestionCount FROM ExamAnswers EA WHERE EA.ExamID = (SELECT TOP(1) ID FROM Exams E WHERE E.StudentID = S.ID ORDER BY ID DESC)) CA
What about this approach : WITH T AS ( SELECT Student_id, SUM(CASE IsCorrectAnswer WHEN 1 THEN 1 END) AS COUNT_TRUE, SUM(CASE IsCorrectAnswer WHEN 0 THEN 1 END) AS COUNT_FALSE, SUM(CASE WHEN IsCorrectAnswer IS NULL THEN 1 END) AS COUNT_UNKNOWN FROM ExamAnswers AS EA WHERE EA.ExamID = (SELECT MAX(ID) FROM Exams E WHERE E.StudentID = S.ID) GROUP BY Student_id ) SELECT S.*, COUNT_TRUE, COUNT_FALSE, COUNT_UNKNOWN FROM Students AS S JOIN T ON S.ID = T.Student_id
how to add left join with CTE , check my query
i have following query i want add my query left join with CTE how do this please help me because i have driver id i want second last driver id but i want add left join with CTE select d.Id,d.DriverNo,d.DriverName,TransId=dc.Id,dc.FromDate,dc.ToDate,dc.IsPaid, Active=(case when (dc.weekoff is null or dc.weekoff=0) then 'Active' else 'Off' end), Rent=(case when (IsNull(dc.CommissionTotal,0))> IsNull(dc.AccJobsTotal,0) then IsNull(dc.CommissionTotal,0)-(IsNull(dc.AccJobsTotal,0)) else 0 end), BalanceDue=IsNull(dc.OldBalance,0), AgentCommission=IsNull(dc.AgentFeesTotal,0), PDA= (case when (dc.weekoff is null or dc.weekoff=0) then (IsNull(dc.PDARent,0)+IsNull(dc.CollectionDeliveryCharges,0)) else 0 end), Total=(case when (IsNull(dc.CommissionTotal,0))> IsNull(dc.AccJobsTotal,0) then IsNull(dc.CommissionTotal,0)-(IsNull(dc.AccJobsTotal,0)) else 0 end) +((IsNull(dc.OldBalance,0)) +((IsNull(dc.AgentFeesTotal,0))) +(case when (dc.weekoff is null or dc.weekoff=0) then (IsNull(dc.PDARent,0)+IsNull(dc.CollectionDeliveryCharges,0)) else 0 end)) from Fleet_Driver d inner join Fleet_DriverCommision dc on d.Id=dc.DriverId where dc.Id in (select Max(Id) from Fleet_DriverCommision group by DriverId) as T1 left join on > LEFT JOIN WITH CTE With cte as (select AgentFeesTotal,DriverId,Row_Number()over(Partition by DriverID order by Transdate desc) as Rn, count(1)over(Partition by DriverID) as cnt from Fleet_DriverCommision) Select AgentFeesTotal,DriverId from cte Where (Rn = 2 and cnt > 1) or (Rn = 1 and cnt = 1) This is example with cte as (select AgentFeesTotal,DriverId,Row_Number()over(Partition by DriverID order by Transdate desc) as Rn, count(1)over(Partition by DriverID) as cnt from Fleet_DriverCommision) Select AgentFeesTotal,DriverId from cte Where (Rn = 2 and cnt > 1) or (Rn = 1 and cnt = 1) select t2.DriverNo from Fleet_Driver t2 left join cte c on c.DriverId=t2.Id
It looks like you are struggling with the syntax for using CTEs. The CTE declaration needs to happen before the rest of the query and then behaves like another table. Also note that the WITH statement must be the first statement or follow a semi-colon. This should get you on the right track. Also be sure to check the examples in the MSDN documentation. --With statement first - must follow ; if there are multiple statements... With cte as (select AgentFeesTotal,DriverId, Row_Number()over(Partition by DriverID order by Transdate desc) as Rn, count(1)over(Partition by DriverID) as cnt from Fleet_DriverCommision ) -- ...then select statement... select d.Id,d.DriverNo,d.DriverName,TransId=dc.Id, dc.FromDate,dc.ToDate,dc.IsPaid, Active=(case when (dc.weekoff is null or dc.weekoff=0) then 'Active' else 'Off' end), Rent=(case when (IsNull(dc.CommissionTotal,0))> IsNull(dc.AccJobsTotal,0) then IsNull(dc.CommissionTotal,0)-(IsNull(dc.AccJobsTotal,0)) else 0 end), BalanceDue=IsNull(dc.OldBalance,0), AgentCommission=IsNull(dc.AgentFeesTotal,0), PDA= (case when (dc.weekoff is null or dc.weekoff=0) then (IsNull(dc.PDARent,0)+IsNull(dc.CollectionDeliveryCharges,0)) else 0 end), Total=(case when (IsNull(dc.CommissionTotal,0))> IsNull(dc.AccJobsTotal,0) then IsNull(dc.CommissionTotal,0)-(IsNull(dc.AccJobsTotal,0)) else 0 end) +((IsNull(dc.OldBalance,0)) +((IsNull(dc.AgentFeesTotal,0))) +(case when (dc.weekoff is null or dc.weekoff=0) then (IsNull(dc.PDARent,0)+IsNull(dc.CollectionDeliveryCharges,0)) else 0 end)) from Fleet_Driver d inner join Fleet_DriverCommision dc on d.Id=dc.DriverId --...join in cte as a normal table left join cte on --join criteria here where dc.Id in (select Max(Id) from Fleet_DriverCommision group by DriverId) as T1 --move the remainder of the logic into your query Select AgentFeesTotal,DriverId from cte Where (Rn = 2 and cnt > 1) or (Rn = 1 and cnt = 1)
Add a WHERE clause in a complex SQL query
I want to pass a ShowRoomId value to the query below. The Employees table has a ShowRoomId column. How can I do it? My SQL query is as following: SELECT * FROM Employees A OUTER APPLY (SELECT TOP 1 * FROM EmployeeBasics B WHERE (A.EmployeeID = B.EmployeeID) ORDER BY B.BasicUpdateDate DESC) AS B OUTER APPLY ( SELECT C.EmployeeId , count(*) AS TotalAbsent FROM EmployeeAbsents C WHERE C.AbsentDate BETWEEN '2016-05-01' AND '2016-05-30' AND A.EmployeeID = C.EmployeeID GROUP BY C.EmployeeId ) AS C OUTER APPLY ( SELECT EmployeeId, SUM(CASE WHEN TransctionTypeId = 1 THEN Amount ELSE 0 END) AS Payment, SUM(CASE WHEN TransctionTypeId = 2 THEN Amount ELSE 0 END) AS RecoverSalary, SUM(CASE WHEN TransctionTypeId = 3 THEN Amount ELSE 0 END) AS RecoverCash FROM dbo.EmployeeAdvances D WHERE A.EmployeeID = D.EmployeeID GROUP BY EmployeeId ) AS D
Simply use a WHERE clause at the end as following: ... YOUR SELECT ... WHERE Col = ...YourCondition... OR Use WITH keyword to keep your current SELECT-statement in a cte. Then do your query on it. WITH cte AS ( ... YOUR SELECT ... ) SELECT * FROM cte WHERE Col = ...YourCondition... OR You can add your SELECT-statement in to parentheses and name it with an allias name. So you can do query on it too. SELECT * FROM ( ... YOUR SELECT ... ) t WHERE t.Col = ...YourCondition...
As per Giorgi Nakeuri's advice, I added the WHERE clause at the end of the statement. And it works for me. Revised code is here: SELECT * FROM Employees A OUTER APPLY (SELECT TOP 1 * FROM EmployeeBasics B WHERE (A.EmployeeID = B.EmployeeID) ORDER BY B.BasicUpdateDate DESC) AS B OUTER APPLY ( SELECT C.EmployeeId , count(*) AS TotalAbsent FROM EmployeeAbsents C WHERE C.AbsentDate BETWEEN '2016-05-01' AND '2016-05-30' AND A.EmployeeID = C.EmployeeID GROUP BY C.EmployeeId ) AS C OUTER APPLY ( SELECT EmployeeId, SUM(CASE WHEN TransctionTypeId = 1 THEN Amount ELSE 0 END) AS Payment, SUM(CASE WHEN TransctionTypeId = 2 THEN Amount ELSE 0 END) AS RecoverSalary, SUM(CASE WHEN TransctionTypeId = 3 THEN Amount ELSE 0 END) AS RecoverCash FROM dbo.EmployeeAdvances D WHERE A.EmployeeID = D.EmployeeID GROUP BY EmployeeId ) AS D WHERE A.ShowRoomId = 2
Case statement in sql using other selected columns in the same statement
I would like to know if the following is possible in SQL server 2005. Column A and B are calculated using other case statements in my actual stored proc. I don't want to repeat the same for another field unnecessarily. If this is not syntactically possible, any other ideas? SELECT A, B, CASE WHEN column1='1' THEN A ELSE B END Col1. Modified version of actual query provided as requested. CTE kind of seems to be tough in this model. WANNABE is the column I want to accomplish in the sub select statement. SELECT 1 AS Region, 'Test', CAST(Work AS NUMERIC(18,2)) Work, Work + 2 AS Work2, WANNABE FROM ( SELECT ROW_NUMBER() OVER(PARTITION BY G.Value, C.C, FR.Mod1 ORDER BY FR.Date DESC, FG.Date DESC, FC.Date DESC) ROW, CASE WHEN COALESCE(FR.Mod1, '') = '' THEN '' ELSE FR.Mod1 END Mod1, CASE WHEN #var1=1 AND #var2 = 1 THEN FR.Col1 * G.Value WHEN #var1=1 AND #var2 = 0 THEN FP.Col1 * G.Value END Work, CASE WHEN 1=1 THEN Work ELSE 1 END WANNABE, ( SELECT Col3 FROM Table2 WHERE c = FR.Value ) AS Custom FROM MainTable FR JOIN #C C ON FR.Col2 = C.Col2 LEFT JOIN Function1(#VersionDate) cv ON cv.Code = C.Code LEFT JOIN Function2(#VersionDate) hv ON hv.Code = C.Code LEFT JOIN #G G ON 1 = 1 LEFT JOIN SubTable1 FG ON FG.Number = G.Value, 2 AND FG.Date = #VersionDate LEFT JOIN SubTable2 FO ON FO.Number = G.Value AND FO.Date = #VersionDate AND FO.Code = FR.Code AND FR.Mod1 = FO.Mod1 LEFT JOIN SubTable3 FP ON FP.Code = FR.Code AND FP.VersionDate = #Versiondate AND CASE WHEN DATALENGTH(FR.Mod1) = 0 THEN '00' ELSE FR.Mod1 END = CASE WHEN DATALENGTH(FP.Mod1) = 0 THEN '00' ELSE FP.Mod1 END LEFT JOIN SubTable4 FC ON FC.Date = #VersionDate WHERE FR.Date = #VersionDate ) x WHERE x.Row = 1 AND RTRIM(LTRIM(x.Col1)) IN ('', '2')
You can define the A,B column aliases in a CTE then reference them in an outer select. ;WITH CTE AS ( SELECT CASE ... END AS A, CASE ... END AS B, column1 FROM your_table ) SELECT A, B, CASE WHEN column1='1' THEN A ELSE B END Col1 FROM CTE Similarly you can also define them in a CROSS APPLY that is sometimes a bit less verbose. A silly example just to show the syntax is SELECT A, B, CASE WHEN type='P' THEN A ELSE B END Col1 FROM master..spt_values CROSS APPLY (SELECT CASE WHEN number %2 = 1 THEN 1 END, CASE WHEN number %2 = 0 THEN 0 END) T(A,B) Following your update you can replace the derived table with a CTE and nest CTEs as follows ;WITH x as ( SELECT ROW_NUMBER() OVER(PARTITION BY G.Value, C.Code, FR.Mod1 ORDER BY FR.Date DESC, FG.Date DESC, FC.Date DESC) ROW, ...<snip> WHERE FR.Date = #VersionDate ), x2 As ( SELECT *, CASE WHEN 1=1 THEN Work ELSE 1 END WANNABE FROM x ) SELECT 1 AS Region, 'Test', CAST(Work AS NUMERIC(18,2)) Work, Work + 2 AS Work2, WANNABE FROM x2 WHERE x2.Row = 1 AND RTRIM(LTRIM(x2.Col1)) IN ('', '2')
Yeah it is posible, but how is all your sql statement? You can use the case statement in the select statement as you are using it. Something like this SELECT SUM((CASE WHEN column1='1' THEN 10 ELSE 0 END)) AS A, SUM((CASE WHEN column1='2' THEN 10 ELSE 0 END)) AS B FROM YourTable