Batch updating an SQL table by month with multiple WHEREs - loops

I have a query where I am uncommenting and re-commenting in multiple WHERE clauses since I would like to update a table one month at a time. See below sample WHERE clause:
update L
set
[skeySpotTypeTele] = COALESCE(ST.[skeySpotTypeTele], -1),
[skeySalesOptionTele] = COALESCE(SOT.[skeySalesOptionTele], -1)
FROM [BI_DWH_TELE].[dwh].[EDC_LIGNECAMPAGNE_FINAL] L
LEFT JOIN [dwh].[DimSpotTypeTele] ST ON L.[NO_CATEGORIEOCCASION] = ST.[SpotTypeID] AND ST.Source = 'T1' AND CAST(L.CALR_ID_JRDIFN AS date) >= ST.[scd_start] AND CAST(L.CALR_ID_JRDIFN AS date) < ST.[scd_end]
LEFT JOIN [dwh].[DimSalesOptionTele] SOT ON L.[NO_OPTIONVENTE] = SOT.[SalesOptionID] AND SOT.Source = 'T1' AND CAST(L.CALR_ID_JRDIFN AS date) >= SOT.[scd_start] AND CAST(L.CALR_ID_JRDIFN AS date) < SOT.[scd_end]
--2016
--where L.skeyDate >= 20151228 and L.skeyDate <= 20160131
where L.skeyDate >= 20160201 and L.skeyDate <= 20160229
--where L.skeyDate >= 20160301 and L.skeyDate <= 20160331
--where L.skeyDate >= 20160401 and L.skeyDate <= 20160430
--where L.skeyDate >= 20160501 and L.skeyDate <= 20160531
--where L.skeyDate >= 20160601 and L.skeyDate <= 20160630
--where L.skeyDate >= 20160701 and L.skeyDate <= 20160731
--where L.skeyDate >= 20160801 and L.skeyDate <= 20160831
--where L.skeyDate >= 20160901 and L.skeyDate <= 20160930
--where L.skeyDate >= 20161001 and L.skeyDate <= 20161031
--where L.skeyDate >= 20161101 and L.skeyDate <= 20161130
--where L.skeyDate >= 20161201 and L.skeyDate <= 20161231
--2017
--where L.skeyDate >= 20170101 and L.skeyDate <= 20170131
--where L.skeyDate >= 20170201 and L.skeyDate <= 20170228
--where L.skeyDate >= 20170301 and L.skeyDate <= 20170331
--where L.skeyDate >= 20170401 and L.skeyDate <= 20170430
--where L.skeyDate >= 20170501 and L.skeyDate <= 20170531
--where L.skeyDate >= 20170601 and L.skeyDate <= 20170630
--where L.skeyDate >= 20170701 and L.skeyDate <= 20170731
--where L.skeyDate >= 20170801 and L.skeyDate <= 20170831
--where L.skeyDate >= 20170901 and L.skeyDate <= 20170930
--where L.skeyDate >= 20171001 and L.skeyDate <= 20171031
--where L.skeyDate >= 20171101 and L.skeyDate <= 20171130
--where L.skeyDate >= 20171201 and L.skeyDate <= 20171231
--2018
--where L.skeyDate >= 20180101 and L.skeyDate <= 20180131
--where L.skeyDate >= 20180201 and L.skeyDate <= 20180228
--where L.skeyDate >= 20180301 and L.skeyDate <= 20180331
--where L.skeyDate >= 20180401 and L.skeyDate <= 20180430
--where L.skeyDate >= 20180501 and L.skeyDate <= 20180531
--where L.skeyDate >= 20180601 and L.skeyDate <= 20180630
--where L.skeyDate >= 20180701 and L.skeyDate <= 20180731
--where L.skeyDate >= 20180801 and L.skeyDate <= 20180831
--where L.skeyDate >= 20180901 and L.skeyDate <= 20180930
--where L.skeyDate >= 20181001 and L.skeyDate <= 20181031
--where L.skeyDate >= 20181101 and L.skeyDate <= 20181130
--where L.skeyDate >= 20181201 and L.skeyDate <= 20181231
--2019
--where L.skeyDate >= 20190101 and L.skeyDate <= 20190131
--where L.skeyDate >= 20190201 and L.skeyDate <= 20190228
--where L.skeyDate >= 20190301 and L.skeyDate <= 20190331
--where L.skeyDate >= 20190401 and L.skeyDate <= 20190430
--where L.skeyDate >= 20190501 and L.skeyDate <= 20190531
--where L.skeyDate >= 20190601 and L.skeyDate <= 20190630
--where L.skeyDate >= 20190701 and L.skeyDate <= 20190731
--where L.skeyDate >= 20190801 and L.skeyDate <= 20190831
--where L.skeyDate >= 20190901 and L.skeyDate <= 20190930
--where L.skeyDate >= 20191001 and L.skeyDate <= 20191031
--where L.skeyDate >= 20191101 and L.skeyDate <= 20191130
--where L.skeyDate >= 20191201 and L.skeyDate <= 20191231
--2020
--where L.skeyDate >= 20200101 and L.skeyDate <= 20200131
--where L.skeyDate >= 20200201 and L.skeyDate <= 20200229
--where L.skeyDate >= 20200301 and L.skeyDate <= 20200331
--where L.skeyDate >= 20200401 and L.skeyDate <= 20200430
--where L.skeyDate >= 20200501 and L.skeyDate <= 20200531
--where L.skeyDate >= 20200601 and L.skeyDate <= 20200630
--where L.skeyDate >= 20200701 and L.skeyDate <= 20200731
--where L.skeyDate >= 20200801 and L.skeyDate <= 20200831
--where L.skeyDate >= 20200901 and L.skeyDate <= 20200930
--where L.skeyDate >= 20201001 and L.skeyDate <= 20201031
--where L.skeyDate >= 20201101 and L.skeyDate <= 20201130
--where L.skeyDate >= 20201201 and L.skeyDate <= 20201231
--2021
--where L.skeyDate >= 20210101 and L.skeyDate <= 20210131
--where L.skeyDate >= 20210201 and L.skeyDate <= 20210228
--where L.skeyDate >= 20210301 and L.skeyDate <= 20210331
--where L.skeyDate >= 20210401 and L.skeyDate <= 20210430
--where L.skeyDate >= 20210501 and L.skeyDate <= 20210531
--where L.skeyDate >= 20210601 and L.skeyDate <= 20210630
--where L.skeyDate >= 20210701 and L.skeyDate <= 20210731
--where L.skeyDate >= 20210801 and L.skeyDate <= 20210831
--where L.skeyDate >= 20210901 and L.skeyDate <= 20210930
--where L.skeyDate >= 20211001 and L.skeyDate <= 20211031
--where L.skeyDate >= 20211101 and L.skeyDate <= 20211130
--where L.skeyDate >= 20211201 and L.skeyDate <= 20211231
--2022
--where L.skeyDate >= 20220101 and L.skeyDate <= 20220131
--where L.skeyDate >= 20220201 and L.skeyDate <= 20220228
--where L.skeyDate >= 20220301 and L.skeyDate <= 20220331
--where L.skeyDate >= 20220401 and L.skeyDate <= 20220430
--where L.skeyDate >= 20220501 and L.skeyDate <= 20220531
--where L.skeyDate >= 20220601 and L.skeyDate <= 20220630
--where L.skeyDate >= 20220701 and L.skeyDate <= 20220731
--where L.skeyDate >= 20220801 and L.skeyDate <= 20220831
--where L.skeyDate >= 20220901 and L.skeyDate <= 20220930
--where L.skeyDate >= 20221001
I am basically, doing a manual uncomment going down each of my WHERE clauses waiting for the query to complete its update for each month.
I would like to modify my update query in order to have more of a batch update to loop through each month.
Ideally, I would like to avoid using a loop in SQL and rather try to find another solution such as with a CTE. I know that I might need to declare some start date and end date variables and perhaps defin a calendar of some sort in my CTE block? I am looking for the most efficiant solution for a table with hundreds of millions of rows.
I am open to any sugestions.
Thanks!

Related

Simplyfing update query with case when

I have a query where there is a lot of repetitions of one condition. I am wondering - is it possible to put this condition into variable or something like that, so not the whole sentence is repeated each time?
The part which is repeating:
ISNULL((CASE WHEN IS_HOLIDAY = 1 THEN 2.5 * NETO_HOUR
WHEN DAY_IN_WEEK = 'Sunday' THEN NETO_HOUR END),0)
In query it looks like this:
UPDATE #tblALL_HOURS SET REG_WORK_COST = (CASE WHEN MINUTE_FROM >= 0 AND MINUTE_FROM <= #6h AND MINUTE_TO >= #6h AND MINUTE_TO <= #18h
AND IS_ABSENT = 0
THEN (DATEDIFF(MINUTE, DATEADD(MINUTE, #6h, CAST(CAST(DATE_TO AS DATE) AS DATETIME)), date_to)/60.00) * (BRUTO_HOUR + ISNULL((CASE WHEN IS_HOLIDAY = 1 THEN 2.5 * NETO_HOUR WHEN DAY_IN_WEEK = 'Sunday' THEN NETO_HOUR END),0))
WHEN MINUTE_FROM >= 0 AND MINUTE_FROM <= #6h AND MINUTE_TO >= #18h AND MINUTE_TO < #24h
AND IS_ABSENT = 0
THEN 12.00 * (BRUTO_HOUR + ISNULL((CASE WHEN IS_HOLIDAY = 1 THEN 2.5 * NETO_HOUR WHEN DAY_IN_WEEK = 'Sunday' THEN NETO_HOUR END),0))
WHEN MINUTE_FROM >= #6h AND MINUTE_FROM <= #18h AND MINUTE_TO >= #6h AND MINUTE_TO <= #18h
AND IS_ABSENT = 0
THEN (DATEDIFF(MINUTE, DATE_FROM, DATE_TO) / 60.00) * (BRUTO_HOUR + ISNULL((CASE WHEN IS_HOLIDAY = 1 THEN 2.5 * NETO_HOUR WHEN DAY_IN_WEEK = 'Sunday' THEN NETO_HOUR END),0))
WHEN MINUTE_FROM >= #6h AND MINUTE_FROM <= #18h AND MINUTE_TO >= #18h AND MINUTE_TO < #24h
AND IS_ABSENT = 0
THEN (DATEDIFF(MINUTE, DATE_FROM, DATEADD(MINUTE, #18h, CAST(CAST(DATE_FROM AS DATE) AS DATETIME))) / 60.00) * (BRUTO_HOUR + ISNULL((CASE WHEN IS_HOLIDAY = 1 THEN 2.5 * NETO_HOUR WHEN DAY_IN_WEEK = 'Sunday' THEN NETO_HOUR END),0))
END)
Is it possible to have something like this instead:
WHEN MINUTE_FROM >= #6h AND MINUTE_FROM <= #18h AND MINUTE_TO >= #18h AND MINUTE_TO < #24h AND IS_ABSENT = 0 THEN (DATEDIFF(MINUTE, DATE_FROM, DATEADD(MINUTE, #18h, CAST(CAST(DATE_FROM AS DATE) AS DATETIME))) / 60.00) * (BRUTO_HOUR + #myCondition)
Use a simple CTE that returns all the columns of #tblALL_HOURS and the value returned by ISNULL function:
ISNULL(CASE WHEN IS_HOLIDAY = 1 THEN 2.5 * NETO_HOUR WHEN DAY_IN_WEEK = 'Sunday' THEN NETO_HOUR END,0)
as a column and then update With the CTE and use that column in place of the condition:
WITH cte AS (
SELECT *,
ISNULL(CASE WHEN IS_HOLIDAY = 1 THEN 2.5 * NETO_HOUR WHEN DAY_IN_WEEK = 'Sunday' THEN NETO_HOUR END,0) AS myCondition
FROM #tblALL_HOURS
)
UPDATE cte
SET REG_WORK_COST = CASE
WHEN MINUTE_FROM >= 0 AND MINUTE_FROM <= #6h AND MINUTE_TO >= #6h AND MINUTE_TO <= #18h AND IS_ABSENT = 0
THEN (DATEDIFF(MINUTE, DATEADD(MINUTE, #6h, CAST(CAST(DATE_TO AS DATE) AS DATETIME)), date_to)/60.00) * (BRUTO_HOUR + myCondition)
WHEN MINUTE_FROM >= 0 AND MINUTE_FROM <= #6h AND MINUTE_TO >= #18h AND MINUTE_TO < #24h AND IS_ABSENT = 0
THEN 12.00 * (BRUTO_HOUR + myCondition)
WHEN MINUTE_FROM >= #6h AND MINUTE_FROM <= #18h AND MINUTE_TO >= #6h AND MINUTE_TO <= #18h AND IS_ABSENT = 0
THEN (DATEDIFF(MINUTE, DATE_FROM, DATE_TO) / 60.00) * (BRUTO_HOUR + myCondition)
WHEN MINUTE_FROM >= #6h AND MINUTE_FROM <= #18h AND MINUTE_TO >= #18h AND MINUTE_TO < #24h AND IS_ABSENT = 0
THEN (DATEDIFF(MINUTE, DATE_FROM, DATEADD(MINUTE, #18h, CAST(CAST(DATE_FROM AS DATE) AS DATETIME))) / 60.00) * (BRUTO_HOUR + myCondition)
END

ISNULL not working

I'm trying to get the salary of an employee and I'm not sure why ISNULL is not working here. Although the same query works when used outside subquery.
Maybe I'm implementing the Isnull function wrong.
Net salary is showing null even there is basic pay given.
DECLARE #dateFrom datetime
SET #dateFrom = '2018-03-01'
DECLARE #dateTo datetime
SET #dateTo = '2018-03-31'
Select
[Emp].ID
,[Emp].EmpCode
,[Emp].FirstName + ' ' + [Emp].LastName AS Name
,[Emp].BasicPay
,((select SUM(InstallmentAmount) from HRM.tbl_EmployeeLoanInstallment [Loan]
LEFT JOIN HRM.tbl_EmployeeLoan [EmpLoan] ON [EmpLoan].ID = [Loan].EmployeeLoanCode
where [EmpLoan].EmpCode = Emp.ID AND IsReceived != 1
AND CONVERT(date, [Loan].InstallmentDueOn) >= CONVERT(date, #dateFrom)
AND CONVERT(date, [Loan].InstallmentDueOn) <= CONVERT(date, #dateTo))) AS LoanDeduction
,( SELECT
(ISNULL([Info].[BasicPay], 0))
-
(SELECT SUM(ISNULL([Loan].InstallmentAmount, 0))
FROM [HRM].[tbl_EmployeeLoan] [EmpLoan]
FULL JOIN [HRM].[tbl_EmployeeInfo] [Info] ON [Info].[ID] = [EmpLoan].[EmpCode]
FULL JOIN [HRM].[tbl_EmployeeLoanInstallment] [Loan] ON [EmpLoan].[ID] = [Loan].[EmployeeLoanCode]
WHERE
CONVERT(date, [Loan].InstallmentDueOn) >= CONVERT(date, #dateFrom)
AND
CONVERT(date, [Loan].InstallmentDueOn) <= CONVERT(date, #dateTo)
AND
[Info].[ID] = [Emp].[ID]
GROUP BY Info.ID)
FROM
[HRM].[tbl_EmployeeInfo] [Info]
WHERE Info.ID = Emp.ID
GROUP BY [Info].[ID], [Info].[BasicPay]
) AS NetSalary
from HRM.tbl_EmployeeInfo [Emp]
Output:
412 C3-345 Ayesha Fatima 20000.00 NULL NULL
413 C3-651 Zainab Ali 20000.00 NULL NULL
414 C1343 Ahmed Abdullah 20000.00 11111.11 8888.89
415 231 Ahmed Aslam 20000.00 NULL NULL
416 FS-16 Fawaz Aslam 25000.00 NULL NULL
Are you sure that your subquery return a value? Seems to not be the case.
If you really want a value, you should catch your null value at the end of your subquery.
,ISNULL(
( SELECT
(ISNULL([Info].[BasicPay], 0))
-
(SELECT SUM(ISNULL([Loan].InstallmentAmount, 0))
FROM [HRM].[tbl_EmployeeLoan] [EmpLoan]
FULL JOIN [HRM].[tbl_EmployeeInfo] [Info] ON [Info].[ID] = [EmpLoan].[EmpCode]
FULL JOIN [HRM].[tbl_EmployeeLoanInstallment] [Loan] ON [EmpLoan].[ID] = [Loan].[EmployeeLoanCode]
WHERE
CONVERT(date, [Loan].InstallmentDueOn) >= CONVERT(date, #dateFrom)
AND
CONVERT(date, [Loan].InstallmentDueOn) <= CONVERT(date, #dateTo)
AND
[Info].[ID] = [Emp].[ID]
GROUP BY Info.ID)
, 0)
FROM
[HRM].[tbl_EmployeeInfo] [Info]

Max and min from the column in a table

i have a table with the following data, i am trying to get the max and min columns from the table. if it is one column i can use max/min for the column, but here i am comparing all the column in a table. what i need is add new columns to store max and min data.
and there will be only one row in the table
create table
#test ( column1 int, column2 int , column3 int , column4 int ,column5 int,column6 int)
insert into #test
values( 89, 103,87,67,86,56)
select * from #test
--drop table #test
thanks in advance.
The easiest way to do this is just cross applying the min/max values of the columns. For example:
SELECT *
FROM #test t
CROSS APPLY (
SELECT MAX(val), MIN(val)
FROM (VALUES (t.column1), (t.column2), (t.column3), (t.column4), (t.column5), (t.column6)) AS c(val)
) AS c(maxvalue, minvalue);
Using the VALUES method to unpivot the data and then reaggravating it will make for a cleaner syntax but it does come with a cost to performance (not terrible but it is there). Using CASE expressions is a bit more cumbersome but in the syntax department, especially if there a lot of columns to be evaluated, but you won't incur the same performance penalty...
SELECT
t.column1, t.column2, t.column3, t.column4, t.column5, t.column6,
MinValue = CASE
WHEN t.column1 <= t.column2 AND t.column1 <= t.column3 AND t.column1 <= t.column4 AND t.column1 <= t.column5 AND t.column1 <= t.column6 THEN t.column1
WHEN t.column2 <= t.column1 AND t.column2 <= t.column3 AND t.column2 <= t.column4 AND t.column2 <= t.column5 AND t.column2 <= t.column6 THEN t.column2
WHEN t.column3 <= t.column1 AND t.column3 <= t.column2 AND t.column3 <= t.column4 AND t.column3 <= t.column5 AND t.column3 <= t.column6 THEN t.column3
WHEN t.column4 <= t.column1 AND t.column4 <= t.column2 AND t.column4 <= t.column3 AND t.column4 <= t.column5 AND t.column4 <= t.column6 THEN t.column4
WHEN t.column5 <= t.column1 AND t.column5 <= t.column2 AND t.column5 <= t.column3 AND t.column5 <= t.column4 AND t.column5 <= t.column6 THEN t.column5
ELSE t.column6
END,
MaxValue = CASE
WHEN t.column1 >= t.column2 AND t.column1 >= t.column3 AND t.column1 >= t.column4 AND t.column1 >= t.column5 AND t.column1 >= t.column6 THEN t.column1
WHEN t.column2 >= t.column1 AND t.column2 >= t.column3 AND t.column2 >= t.column4 AND t.column2 >= t.column5 AND t.column2 >= t.column6 THEN t.column2
WHEN t.column3 >= t.column1 AND t.column3 >= t.column2 AND t.column3 >= t.column4 AND t.column3 >= t.column5 AND t.column3 >= t.column6 THEN t.column3
WHEN t.column4 >= t.column1 AND t.column4 >= t.column2 AND t.column4 >= t.column3 AND t.column4 >= t.column5 AND t.column4 >= t.column6 THEN t.column4
WHEN t.column5 >= t.column1 AND t.column5 >= t.column2 AND t.column5 >= t.column3 AND t.column5 >= t.column4 AND t.column5 >= t.column6 THEN t.column5
ELSE t.column6
END
FROM
#test t;
Results...
column1 column2 column3 column4 column5 column6 MinValue MaxValue
----------- ----------- ----------- ----------- ----------- ----------- ----------- -----------
89 103 87 67 86 56 56 103
I found this solution here.
SELECT
column1
,column2
,column3
,column4
,column5
,column6
,(SELECT MAX(MaxValue)
FROM (VALUES (column1),(column2),(column3), (column4), (column5), (column6)) AS [Values](MaxValue))
AS MaxValue
,(SELECT MIN(MinValue)
FROM (VALUES (column1),(column2),(column3), (column4), (column5), (column6)) AS [Values](MinValue))
AS MinValue
FROM #test

case when in sqlserver

i try to use case in for my condition to show out which is late,but after i use case when my result show out too many result.
select
grp.checktime,
--min(CONVERT(smalldatetime,l.checktime)) as clockin,
--max(CONVERT(smalldatetime,l.checktime)) as clockout,
ClockIn = case when min(cast(l.checktime as time)) <= cast(sc.StartTime as time)
then convert(varchar(100), cast(l.checktime as time), 100)
else 'Late ClockIn ' + convert(varchar(100), cast(l.checktime as time), 100)
end,
Clockout = case when max(cast(l.checktime as time)) >= cast(sc.EndTime as time)
then convert(varchar(100), cast(l.checktime as time), 100)
else 'Early ClockOut ' + convert(varchar(100), cast(l.checktime as time), 100)
end,
l.userid,
u.showname,
u.BADGENUMBER
from checkinout l
inner join userinfo u on l.userid = u.userid
inner join UserUsedsclasses uuc on u.userid = uuc.userid
inner join SchClass sc on uuc.SchId = sc.schClassid
inner join (
select distinct CONVERT(Date,checktime) as checktime
from checkinout
group by CONVERT(Date,checktime)
) as grp on grp.checktime = CONVERT(Date, l.checktime)
where uuc.SchId = 1 and u.badgenumber = 107
and u.badgenumber not in (79, 103, 78)
and l.checktime >= dateadd(month, datediff(month, 0, GETDATE() ) , 0)
and l.checktime < dateadd(month, datediff(month, 0, GETDATE ())+1, 0)
group by grp.checktime,l.userid,u.showname,u.BADGENUMBER,sc.StartTime,l.checktime,sc.EndTime
my result show me
Change your group by to group by the date of l.checktime.
select
grp.checktime,
--min(convert(smalldatetime,l.checktime)) as clockin,
--max(convert(smalldatetime,l.checktime)) as clockout,
ClockIn = case when min(cast(l.checktime as time)) <= cast(sc.StartTime as time)
then convert(varchar(100), cast(l.checktime as time), 100)
else 'Late ClockIn ' + convert(varchar(100), cast(l.checktime as time), 100)
end,
Clockout = case when max(cast(l.checktime as time)) >= cast(sc.EndTime as time)
then convert(varchar(100), cast(l.checktime as time), 100)
else 'Early ClockOut ' + convert(varchar(100), cast(l.checktime as time), 100)
end,
l.userid,
u.showname,
u.BADGENUMBER
from checkinout l
inner join userinfo u on l.userid = u.userid
inner join UserUsedsclasses uuc on u.userid = uuc.userid
inner join SchClass sc on uuc.SchId = sc.schClassid
inner join (
select distinct convert(Date,checktime) as checktime
from checkinout
group by convert(Date,checktime)
) as grp on grp.checktime = convert(Date, l.checktime)
where uuc.SchId = 1 and u.badgenumber = 107
and u.badgenumber not in (79, 103, 78)
and l.checktime >= dateadd(month, datediff(month, 0, getdate() ) , 0)
and l.checktime < dateadd(month, datediff(month, 0, getdate ())+1, 0)
group by
grp.checktime
, l.userid
, u.showname
, u.BADGENUMBER
, sc.StartTime
, convert(date, l.checktime)
, sc.EndTime

Query inside CASE statement with SUM

I have a nestled query I need to use in my CASE statement. I need to use the Max(AgeDate) that is correctly retrieved in the SELECT statement in my CASE statement but it does not see my Max(AgeDate) in my SELECT statement in my CASE statement. Please help...
Select
Inv.InvoiceNumber,
Fact_FinInvoice.InvoiceID,
dbo.Dim_Date.FullDate AS InvoiceDate,
pra.PracticeName,
pra.PracticeLogonName,
pat.AccNo,
pat.FileNo,
pmai.MedicalAidNumber,
per.Title + ' ' + per.Initials + ' ' + per.Surname AS PatientName,
sch.SCHEMES5,
sch.SchemeOption,
(SELECT MAX(B.AgeDate) FROM Fact_FinInvoice B WHERE Fact_FinInvoice.InvoiceID = B.InvoiceID AND Fact_FinInvoice.PracticeIdKey = B.PracticeIdKey) MaxAgeDate,
SUM(Fact_FinInvoice.Amount) AS Amount,
SUM(Fact_FinInvoice.AmountFunder) AS AmountFunder,
SUM(Fact_FinInvoice.AmountPatient) AS AmountPatient,
SUM(CASE WHEN DATEDIFF(dd, MaxAgeDate, GETDATE()) between 0 and 29 and AmountFunder != 0 THEN AmountFunder ELSE 0 END) as FunderCurrent,
SUM(CASE WHEN DATEDIFF(dd, MaxAgeDate, GETDATE()) between 30 and 59 and AmountFunder != 0 THEN AmountFunder ELSE 0 END) as Funder30Days,
SUM(CASE WHEN DATEDIFF(dd, MaxAgeDate, GETDATE()) between 60 and 89 and AmountFunder != 0 THEN AmountFunder ELSE 0 END) as Funder60Days,
SUM(CASE WHEN DATEDIFF(dd, MaxAgeDate, GETDATE()) between 90 and 119 and AmountFunder != 0 THEN AmountFunder ELSE 0 END) as Funder90Days,
SUM(CASE WHEN DATEDIFF(dd, MaxAgeDate, GETDATE()) >= 120 and AmountFunder != 0 THEN AmountFunder ELSE 0 END) as Funder120Days,
SUM(CASE WHEN DATEDIFF(dd, MaxAgeDate, GETDATE()) between 0 and 29 and AmountPatient != 0 THEN AmountPatient ELSE 0 END) as PatientCurrent,
SUM(CASE WHEN DATEDIFF(dd, MaxAgeDate, GETDATE()) between 30 and 59 and AmountPatient != 0 THEN AmountPatient ELSE 0 END) as Patient30Days,
SUM(CASE WHEN DATEDIFF(dd, MaxAgeDate, GETDATE()) between 60 and 89 and AmountPatient != 0 THEN AmountPatient ELSE 0 END) as Patient60Days,
SUM(CASE WHEN DATEDIFF(dd, MaxAgeDate, GETDATE()) between 90 and 119 and AmountPatient != 0 THEN AmountPatient ELSE 0 END) as Patient90Days,
SUM(CASE WHEN DATEDIFF(dd, MaxAgeDate, GETDATE()) >= 120 and AmountPatient != 0 THEN AmountPatient ELSE 0 END) as Patient120Days,
mcs.Name AS BureauManager,
mcso.Name AS BureauOfficer
FROM dbo.Fact_FinInvoice LEFT OUTER JOIN
dbo.Dim_Practice pra ON dbo.Fact_FinInvoice.PracticeIdKey = pra.PracticeIDCode LEFT OUTER JOIN
dbo.Fact_Invoice Inv ON dbo.Fact_FinInvoice.InvoiceID = Inv.ID LEFT OUTER JOIN
dbo.Dim_PersonMAInfo pmai INNER JOIN
dbo.Dim_Scheme sch ON sch.CodeNo = pmai.CodeNo ON Inv.PersonMAInfoCode = pmai.PersonMAInfoID LEFT OUTER JOIN
dbo.Dim_BureauStaffProvider bsp INNER JOIN
dbo.Dim_MediChargeStaff mcs ON mcs.ID = bsp.BureauStaffId ON bsp.ProviderID = Inv.ProviderId INNER JOIN
dbo.Dim_MediChargeStaff mcso ON mcs.Manager = mcso.ID LEFT OUTER JOIN
dbo.Dim_Date ON Inv.InvoiceDateKey = dbo.Dim_Date.DateKey LEFT OUTER JOIN
dbo.Dim_Patient pat INNER JOIN
dbo.Dim_PersonData per ON per.PersonDataId = pat.PersonId ON pat.PatientId = Inv.PatientKey
GROUP BY Inv.InvoiceNumber,
Fact_FinInvoice.InvoiceID,
dbo.Dim_Date.FullDate,
pra.PracticeName,
pra.PracticeLogonName,
pmai.MedicalAidNumber,
sch.SCHEMES5,
sch.SchemeOption,
mcs.Name,
mcso.Name,
pat.AccNo,
pat.FileNo,
per.Title + ' ' + per.Initials + ' ' + per.Surname,
[Fact_FinInvoice].PracticeIdKey
USE CTE on top and then join that CTE with your joins:
;with mycte as (
select MAX(AgeDate) as MaxAgeDate,InvoiceID FROM Fact_FinInvoice
group by InvoiceID
)
Select
Inv.InvoiceNumber,
Fact_FinInvoice.InvoiceID,
dbo.Dim_Date.FullDate AS InvoiceDate,
pra.PracticeName,
pra.PracticeLogonName,
pat.AccNo,
pat.FileNo,
pmai.MedicalAidNumber,
per.Title + ' ' + per.Initials + ' ' + per.Surname AS PatientName,
sch.SCHEMES5,
sch.SchemeOption,
MaxAgeDate,
SUM(Fact_FinInvoice.Amount) AS Amount,
SUM(Fact_FinInvoice.AmountFunder) AS AmountFunder,
SUM(Fact_FinInvoice.AmountPatient) AS AmountPatient,
SUM(CASE WHEN DATEDIFF(dd, MaxAgeDate, GETDATE()) between 0 and 29 and AmountFunder != 0 THEN AmountFunder ELSE 0 END) as FunderCurrent,
SUM(CASE WHEN DATEDIFF(dd, MaxAgeDate, GETDATE()) between 30 and 59 and AmountFunder != 0 THEN AmountFunder ELSE 0 END) as Funder30Days,
SUM(CASE WHEN DATEDIFF(dd, MaxAgeDate, GETDATE()) between 60 and 89 and AmountFunder != 0 THEN AmountFunder ELSE 0 END) as Funder60Days,
SUM(CASE WHEN DATEDIFF(dd, MaxAgeDate, GETDATE()) between 90 and 119 and AmountFunder != 0 THEN AmountFunder ELSE 0 END) as Funder90Days,
SUM(CASE WHEN DATEDIFF(dd, MaxAgeDate, GETDATE()) >= 120 and AmountFunder != 0 THEN AmountFunder ELSE 0 END) as Funder120Days,
SUM(CASE WHEN DATEDIFF(dd, MaxAgeDate, GETDATE()) between 0 and 29 and AmountPatient != 0 THEN AmountPatient ELSE 0 END) as PatientCurrent,
SUM(CASE WHEN DATEDIFF(dd, MaxAgeDate, GETDATE()) between 30 and 59 and AmountPatient != 0 THEN AmountPatient ELSE 0 END) as Patient30Days,
SUM(CASE WHEN DATEDIFF(dd, MaxAgeDate, GETDATE()) between 60 and 89 and AmountPatient != 0 THEN AmountPatient ELSE 0 END) as Patient60Days,
SUM(CASE WHEN DATEDIFF(dd, MaxAgeDate, GETDATE()) between 90 and 119 and AmountPatient != 0 THEN AmountPatient ELSE 0 END) as Patient90Days,
SUM(CASE WHEN DATEDIFF(dd, MaxAgeDate, GETDATE()) >= 120 and AmountPatient != 0 THEN AmountPatient ELSE 0 END) as Patient120Days,
mcs.Name AS BureauManager,
mcso.Name AS BureauOfficer
FROM dbo.Fact_FinInvoice LEFT OUTER JOIN
dbo.Dim_Practice pra ON dbo.Fact_FinInvoice.PracticeIdKey = pra.PracticeIDCode LEFT OUTER JOIN
dbo.Fact_Invoice Inv ON dbo.Fact_FinInvoice.InvoiceID = Inv.ID LEFT OUTER JOIN
dbo.Dim_PersonMAInfo pmai INNER JOIN
dbo.Dim_Scheme sch ON sch.CodeNo = pmai.CodeNo ON Inv.PersonMAInfoCode = pmai.PersonMAInfoID LEFT OUTER JOIN
dbo.Dim_BureauStaffProvider bsp INNER JOIN
dbo.Dim_MediChargeStaff mcs ON mcs.ID = bsp.BureauStaffId ON bsp.ProviderID = Inv.ProviderId INNER JOIN
dbo.Dim_MediChargeStaff mcso ON mcs.Manager = mcso.ID LEFT OUTER JOIN
dbo.Dim_Date ON Inv.InvoiceDateKey = dbo.Dim_Date.DateKey LEFT OUTER JOIN
dbo.Dim_Patient pat INNER JOIN
dbo.Dim_PersonData per ON per.PersonDataId = pat.PersonId ON pat.PatientId = Inv.PatientKey
join mycte ct
on Fact_FinInvoice.InvoiceID = ct.InvoiceID
GROUP BY Inv.InvoiceNumber,
Fact_FinInvoice.InvoiceID,
dbo.Dim_Date.FullDate,
pra.PracticeName,
pra.PracticeLogonName,
pmai.MedicalAidNumber,
sch.SCHEMES5,
sch.SchemeOption,
mcs.Name,
mcso.Name,
pat.AccNo,
pat.FileNo,
per.Title + ' ' + per.Initials + ' ' + per.Surname,
[Fact_FinInvoice].PracticeIdKey
You can't use aliases given in select part in other places in the select, but you can use outer apply to fetch data that you'll then use in select, with something like this:
select
....
sch.SchemeOption,
AD.MaxAgeDate,
....
SUM(CASE WHEN DATEDIFF(dd, AD.MaxAgeDate, GETDATE())
from
dbo.Fact_FinInvoice
outer apply (
SELECT MAX(B.AgeDate)
FROM Fact_FinInvoice B
WHERE Fact_FinInvoice.InvoiceID = B.InvoiceID AND
Fact_FinInvoice.PracticeIdKey = B.PracticeIdKey) AD
LEFT OUTER JOIN ...
And you can also calculate the datediff already in the outer apply as a second column, so you don't have to repeat the same code several times.
Use Cross Apply
SELECT Inv.InvoiceNumber,
Fact_FinInvoice.InvoiceID,
dbo.Dim_Date.FullDate AS InvoiceDate,
pra.PracticeName,
pra.PracticeLogonName,
pat.AccNo,
pat.FileNo,
pmai.MedicalAidNumber,
per.Title + ' ' + per.Initials + ' ' + per.Surname AS PatientName,
sch.SCHEMES5,
sch.SchemeOption,
cs.MaxAgeDate,
Sum(Fact_FinInvoice.Amount) AS Amount,
Sum(Fact_FinInvoice.AmountFunder) AS AmountFunder,
Sum(Fact_FinInvoice.AmountPatient) AS AmountPatient,
Sum(CASE
WHEN Datediff(dd, MaxAgeDate, Getdate()) BETWEEN 0 AND 29
AND AmountFunder != 0 THEN AmountFunder
ELSE 0
END) AS FunderCurrent,
Sum(CASE
WHEN Datediff(dd, MaxAgeDate, Getdate()) BETWEEN 30 AND 59
AND AmountFunder != 0 THEN AmountFunder
ELSE 0
END) AS Funder30Days,
Sum(CASE
WHEN Datediff(dd, MaxAgeDate, Getdate()) BETWEEN 60 AND 89
AND AmountFunder != 0 THEN AmountFunder
ELSE 0
END) AS Funder60Days,
Sum(CASE
WHEN Datediff(dd, MaxAgeDate, Getdate()) BETWEEN 90 AND 119
AND AmountFunder != 0 THEN AmountFunder
ELSE 0
END) AS Funder90Days,
Sum(CASE
WHEN Datediff(dd, MaxAgeDate, Getdate()) >= 120
AND AmountFunder != 0 THEN AmountFunder
ELSE 0
END) AS Funder120Days,
Sum(CASE
WHEN Datediff(dd, MaxAgeDate, Getdate()) BETWEEN 0 AND 29
AND AmountPatient != 0 THEN AmountPatient
ELSE 0
END) AS PatientCurrent,
Sum(CASE
WHEN Datediff(dd, MaxAgeDate, Getdate()) BETWEEN 30 AND 59
AND AmountPatient != 0 THEN AmountPatient
ELSE 0
END) AS Patient30Days,
Sum(CASE
WHEN Datediff(dd, MaxAgeDate, Getdate()) BETWEEN 60 AND 89
AND AmountPatient != 0 THEN AmountPatient
ELSE 0
END) AS Patient60Days,
Sum(CASE
WHEN Datediff(dd, MaxAgeDate, Getdate()) BETWEEN 90 AND 119
AND AmountPatient != 0 THEN AmountPatient
ELSE 0
END) AS Patient90Days,
Sum(CASE
WHEN Datediff(dd, MaxAgeDate, Getdate()) >= 120
AND AmountPatient != 0 THEN AmountPatient
ELSE 0
END) AS Patient120Days,
mcs.Name AS BureauManager,
mcso.Name AS BureauOfficer
FROM dbo.Fact_FinInvoice FFI
LEFT OUTER JOIN dbo.Dim_Practice pra ON FFI.PracticeIdKey = pra.PracticeIDCode
LEFT OUTER JOIN dbo.Fact_Invoice Inv ON FFI.InvoiceID = Inv.ID
LEFT OUTER JOIN dbo.Dim_PersonMAInfo pmai
INNER JOIN dbo.Dim_Scheme sch ON sch.CodeNo = pmai.CodeNo ON Inv.PersonMAInfoCode = pmai.PersonMAInfoID
LEFT OUTER JOIN dbo.Dim_BureauStaffProvider bsp
INNER JOIN dbo.Dim_MediChargeStaff mcs ON mcs.ID = bsp.BureauStaffId ON bsp.ProviderID = Inv.ProviderId
INNER JOIN dbo.Dim_MediChargeStaff mcso ON mcs.Manager = mcso.ID
LEFT OUTER JOIN dbo.Dim_Date ON Inv.InvoiceDateKey = dbo.Dim_Date.DateKey
LEFT OUTER JOIN dbo.Dim_Patient pat
INNER JOIN dbo.Dim_PersonData per ON per.PersonDataId = pat.PersonId ON pat.PatientId = Inv.PatientKey
CROSS APPLY (SELECT Max(B.AgeDate) AS MaxAgeDAte
FROM Fact_FinInvoice B
WHERE FFI.InvoiceID = B.InvoiceID
AND FFI.PracticeIdKey = B.PracticeIdKey) CS
GROUP BY Inv.InvoiceNumber,
FFI.InvoiceID,
dbo.Dim_Date.FullDate,
pra.PracticeName,
pra.PracticeLogonName,
pmai.MedicalAidNumber,
sch.SCHEMES5,
sch.SchemeOption,
mcs.Name,
mcso.Name,
pat.AccNo,
pat.FileNo,
per.Title + ' ' + per.Initials + ' ' + per.Surname,
[FFI].PracticeIdKey

Resources