sqlsql-servercommon-table-expressionsql-server-2019

CTE to match days after discharge and days supply from prescription


I'm assuming CTE is the most efficient way to do this, but any suggestions would be great. I think I can do this in multiple steps a different way if I have to, but would love to make this as efficient as possible since the table is huge. I have a table like this:

PatientID DischargeDate RxDate DaysSupply
1 1/1/2025 1/2/2025 3
2 1/3/2025 1/3/2025 5
3 1/3/2025 2/4/2025 10

I need to produce a table which keeps one line per patient discharge and creates 30 new columns indicating whether or not the patient had an antibiotic that day, like this:

PatientID DischargeDate RxDate DaysSupply Day1 Day2 Day3 Day4 and so on
1 1/1/2025 1/2/2025 3 1 1 1 0

However, for the purposes of this post, I'll certainly settle for a solution that produces the following and then I can transpose it. Note - I am only keeping the records in which a patient started a prescription within 1-30 days post discharge. So you'll notice I left out patient #3 below.

PatientID DischargeDate RxDate
1 1/1/2025 1/2/2025
1 1/1/2025 1/3/2025
1 1/1/2025 1/4/2025
2 1/3/2025 1/3/2025
2 1/3/2025 1/4/2025
2 1/3/2025 1/5/2025
2 1/3/2025 1/6/2025
2 1/3/2025 1/7/2025

Any suggestions are greatly appreciated. Thank you!


Solution

  • For the first option, the best way (if not very concise) is to just use a bunch of CASE expressions.

    SELECT
      p.PatientID,
      p.DischargeDate,
      p.RxDate,
      p.DaysSupply,
      CASE WHEN p.DaysSupply >= 01 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day01,
      CASE WHEN p.DaysSupply >= 02 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day02,
      CASE WHEN p.DaysSupply >= 03 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day03,
      CASE WHEN p.DaysSupply >= 04 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day04,
      CASE WHEN p.DaysSupply >= 05 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day05,
      CASE WHEN p.DaysSupply >= 06 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day06,
      CASE WHEN p.DaysSupply >= 07 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day07,
      CASE WHEN p.DaysSupply >= 08 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day08,
      CASE WHEN p.DaysSupply >= 09 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day09,
      CASE WHEN p.DaysSupply >= 10 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day10,
      CASE WHEN p.DaysSupply >= 11 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day11,
      CASE WHEN p.DaysSupply >= 12 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day12,
      CASE WHEN p.DaysSupply >= 13 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day13,
      CASE WHEN p.DaysSupply >= 14 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day14,
      CASE WHEN p.DaysSupply >= 15 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day15,
      CASE WHEN p.DaysSupply >= 16 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day16,
      CASE WHEN p.DaysSupply >= 17 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day17,
      CASE WHEN p.DaysSupply >= 18 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day18,
      CASE WHEN p.DaysSupply >= 19 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day19,
      CASE WHEN p.DaysSupply >= 20 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day20,
      CASE WHEN p.DaysSupply >= 21 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day21,
      CASE WHEN p.DaysSupply >= 22 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day22,
      CASE WHEN p.DaysSupply >= 23 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day23,
      CASE WHEN p.DaysSupply >= 24 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day24,
      CASE WHEN p.DaysSupply >= 25 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day25,
      CASE WHEN p.DaysSupply >= 26 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day26,
      CASE WHEN p.DaysSupply >= 27 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day27,
      CASE WHEN p.DaysSupply >= 28 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day28,
      CASE WHEN p.DaysSupply >= 29 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day29,
      CASE WHEN p.DaysSupply >= 30 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS Day30
    FROM Patient p
    WHERE DATEADD(day, 30, p.DischargeDate) > p.RxDate;
    

    For the second option you can use GENERATE_SERIES to dynamically generate more rows, and some date math.

    SELECT
      p.PatientID,
      p.DischargeDate,
      DATEADD(day, g.value, p.RxDate) AS RxDate
    FROM Patient p
    CROSS APPLY GENERATE_SERIES(0, p.DaysSupply - 1) g
    WHERE DATEADD(day, 30, p.DischargeDate) > p.RxDate;
    

    db<>fiddle