'SQL Conditional sum
Thank you for your suggestion. I have incorporated your suggestion into a more streamlined query below. The results of this query are here:
PtID Sts StartDate EndDate DaysCount 10247 1 2022-02-01 2022-02-11 11 10247 5 2022-02-11 2022-02-15 5 10247 1 2022-02-15 2022-02-24 10 10247 5 2022-02-24 2022-02-28 5
When the sum of the DaysCount column is totaled at the Patient ID group level in SQL Server Reporting Services, it totals to 31 days for this patient. This is not correct. If the previous EndDate is the same as the next start date, it is counting an extra day for each time the patient had a new start date (which I want to keep so that each day is counted after the datediff calculation). What I want to do is sum all 4 of these rows by DaysCount, but NOT count that extra day for the 3 rows that come after the 1st StartDate of 2/1/2022. So the total in the above results set should be 28 instead of 31. If I can do it SQL or SSRS, either way that is the result set I want. Thank you again for your help!
CREATE TABLE mytable(
PtID INTEGER NOT NULL PRIMARY KEY
,PtInfusionStatusKey INTEGER NOT NULL
,StartDate DATE NOT NULL
,EndDate DATE NOT NULL
,DaysCount INTEGER NOT NULL
);
INSERT INTO mytable(PtID,PtInfusionStatusKey,StartDate,EndDate,DaysCount) VALUES (10247,2022-01-16,'2022-02-11','27',NULL);
INSERT INTO mytable(PtID,PtInfusionStatusKey,StartDate,EndDate,DaysCount) VALUES (10247,2022-02-11,'2022-02-15','5',NULL);
INSERT INTO mytable(PtID,PtInfusionStatusKey,StartDate,EndDate,DaysCount) VALUES (10247,2022-02-15,'2022-02-24','10',NULL);
INSERT INTO mytable(PtID,PtInfusionStatusKey,StartDate,EndDate,DaysCount) VALUES (10247,2022-02-24,'2022-03-23','28',NULL);
WITH seq(n) AS
(
SELECT 0 UNION ALL SELECT n + 1 FROM seq
WHERE n < DATEDIFF(DAY, convert(date,'1/1/2004'), convert(date, '1/1/2054'))
),
d(d) AS
(
SELECT DATEADD(DAY, n, convert(date,'1/1/2004')) FROM seq
),
src AS
(
SELECT
TheDate = CONVERT(date, d),
TheDay = DATEPART(DAY, d),
TheDayName = DATENAME(WEEKDAY, d),
TheWeek = DATEPART(WEEK, d),
TheISOWeek = DATEPART(ISO_WEEK, d),
TheDayOfWeek = DATEPART(WEEKDAY, d),
TheMonth = DATEPART(MONTH, d),
TheMonthName = DATENAME(MONTH, d),
TheQuarter = DATEPART(Quarter, d),
TheYear = DATEPART(YEAR, d),
TheFirstOfMonth = DATEFROMPARTS(YEAR(d), MONTH(d), 1),
TheLastOfYear = DATEFROMPARTS(YEAR(d), 12, 31),
TheDayOfYear = DATEPART(DAYOFYEAR, d)
FROM d
)
,
STAT AS
(
select
Pt.PtKey, ptid, PtPtInfusionStatus.ModifiedDate, PtInfusionStatus.Name, Pt.PersonKey, PtInfusionStatus.PtInfusionStatusKey, PtPtInfusionStatus.StartDate, PtPtInfusionStatus.EndDate
--,ROW_NUMBER() OVER(PARTITION BY pt.ptkey ORDER BY PtPtInfusionStatus.ModifiedDate asc) AS 'PtStatusRank'
from Pt left join PtPtInfusionStatus on PtPtInfusionStatus.PtKey = pt.PtKey
left join PtInfusionStatus on ptinfusionstatus.PtInfusionStatusKey = PtPtInfusionStatus.PtInfusionStatusKey
where
ptptinfusionstatus.PtInfusionStatusKey IN (1,5)
)
,
PAT as
(
SELECT
STAT.PtID
,stat.name
,PtKey
,Person.LastName
,Person.FirstName
,stat.StartDate
,stat.EndDate
,STAT.PtInfusionStatusKey
FROM STAT
JOIN Person ON STAT.PersonKey = Person.personkey
WHERE 1=1
AND STAT.PtInfusionStatusKey in (1,5)
)
,
DATEPAT as
(
SELECT pat.PtID
,pat.PtInfusionStatusKey
, COUNT(DISTINCT src.TheDate) AS DaysCount
,pat.StartDate
,pat.EndDate
FROM PAT
left JOIN src on src.TheDate BETWEEN pat.StartDate AND pat.EndDate
GROUP BY pat.PtID, pat.StartDate, pat.EndDate, pat.PtInfusionStatusKey
)
--***MAIN QUERY***
SELECT
DATEPAT.PtID
,DATEPAT.PtInfusionStatusKey
,DATEPAT.StartDate
,DATEPAT.EndDate
,DATEPAT.DaysCount
FROM DATEPAT
WHERE datepat.ptid = 10247
and DATEPAT.StartDate >= convert(date,'1/16/2022') and DATEPAT.EndDate <= convert(date,'3/23/2022')
ORDER BY PtID
OPTION (MAXRECURSION 0);
Solution 1:[1]
There may be more elegant ways of doing this but I would tackle this with a date table. If you don't have one there are plenty of examples of how to generate one in a few seconds.
Once you have your date table, you could refactor the query to something simple like this... (Note: this is a really cut down example for illustration but you should get the idea)
SELECT p.PatID, COUNT(DISTINCT dt.TheDate) AS DaysCount
FROM myPatientRecords p
JOIN myDateTable dt on dt.TheDate BETWEEN p.StartDate AND p.EndDate
GROUP BY p.PatID
By using a DISTINCT COUNT, we don't need to worry about the overlapping dates
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Alan Schofield |
