initial commit

This commit is contained in:
Andrew Charlwood
2026-05-12 16:40:03 +01:00
commit 647d1bfa7f
38 changed files with 2715 additions and 0 deletions
@@ -0,0 +1,138 @@
/*
Baseline vs rolling evaluation template
=======================================
Purpose:
Compare a fixed baseline cohort with rolling evaluation periods.
Typical use:
- A medicines optimisation search where the baseline is fixed.
- Later periods check whether the same patients still meet criteria.
- Output is practice x period, preserving the baseline count.
Replace medicine_products and the evaluation criteria before use.
*/
SET BASELINE_START = '2025-04-01';
SET BASELINE_END = '2025-06-30';
SET FIRST_EVALUATION_START = '2025-04-01';
SET EVALUATION_MONTHS = 3;
SET BNF_PREFIX = 'REPLACE_WITH_BNF_PREFIX';
WITH latest_prescribing_date AS (
-- Caps generated periods to data already present in the prescribing table.
SELECT MAX("DateMedicationStart")::DATE AS "MaxDate"
FROM REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable"
WHERE "DateMedicationStart" <= CURRENT_DATE()
),
periods AS (
-- Generates candidate month starts; increase ROWCOUNT for longer projects.
SELECT
ROW_NUMBER() OVER (ORDER BY SEQ4()) AS "PeriodNumber",
DATEADD(MONTH, ROW_NUMBER() OVER (ORDER BY SEQ4()) - 1, $FIRST_EVALUATION_START::DATE)::DATE AS "PeriodStartDate"
FROM TABLE(GENERATOR(ROWCOUNT => 48))
),
evaluation_periods AS (
SELECT
"PeriodNumber",
"PeriodStartDate",
LAST_DAY(DATEADD(MONTH, $EVALUATION_MONTHS - 1, "PeriodStartDate"))::DATE AS "PeriodEndDate"
FROM periods
CROSS JOIN latest_prescribing_date
WHERE "PeriodStartDate" <= "MaxDate"
),
date_bounds AS (
SELECT
$BASELINE_START::DATE AS "MinEventDate",
GREATEST($BASELINE_END::DATE, COALESCE(MAX("PeriodEndDate"), $BASELINE_END::DATE)) AS "MaxEventDate"
FROM evaluation_periods
),
practices AS (
-- Default to active Norfolk and Suffolk parent GP practices.
SELECT DISTINCT
"OrganisationCode" AS "PracticeCode",
"OrganisationName" AS "PracticeName"
FROM DATA_HUB.DWH."DimOrganisationAndSite"
WHERE "OrganisationSubType" = 'GP Practice'
AND "IsSiteActive" = 'Yes'
AND "IsSiteNorfolkAndSuffolk" = 'Yes'
AND "SiteCode" = "OrganisationCode"
),
medicine_products AS (
-- Replace this CTE for VTM, VMP, explicit SNOMED, or cluster-based definitions.
SELECT DISTINCT "ProductSnomedCode"
FROM DATA_HUB.DWH."DimMedicineAndDevice"
WHERE "BNFCode" LIKE $BNF_PREFIX || '%'
),
medicine_events AS (
-- Pull the smallest event window needed for both baseline and evaluation.
SELECT DISTINCT
rx."PersonKey",
rx."CurrentGeneralPractice" AS "PracticeCode",
rx."DateMedicationStart"
FROM REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable" rx
CROSS JOIN date_bounds db
INNER JOIN medicine_products mp
ON rx."SNOMEDCode" = mp."ProductSnomedCode"
WHERE rx."PersonKey" IS NOT NULL
AND rx."CurrentGeneralPractice" IS NOT NULL
AND rx."DateMedicationStart" BETWEEN db."MinEventDate" AND db."MaxEventDate"
),
baseline_cohort AS (
-- Fixes each patient to the practice recorded during the baseline window.
SELECT DISTINCT
me."PersonKey",
me."PracticeCode"
FROM medicine_events me
WHERE me."DateMedicationStart" BETWEEN $BASELINE_START AND $BASELINE_END
),
baseline_counts AS (
SELECT
"PracticeCode",
COUNT(DISTINCT "PersonKey") AS "BaselineCount"
FROM baseline_cohort
GROUP BY "PracticeCode"
),
practice_periods AS (
-- Ensures every active practice returns one row per evaluation period.
SELECT
p."PracticeCode",
p."PracticeName",
ep."PeriodNumber",
ep."PeriodStartDate",
ep."PeriodEndDate"
FROM practices p
CROSS JOIN evaluation_periods ep
),
evaluation_counts AS (
SELECT
bc."PracticeCode",
ep."PeriodNumber",
ep."PeriodStartDate",
ep."PeriodEndDate",
COUNT(DISTINCT me."PersonKey") AS "EvaluationCount"
FROM baseline_cohort bc
CROSS JOIN evaluation_periods ep
LEFT JOIN medicine_events me
ON me."PersonKey" = bc."PersonKey"
AND me."DateMedicationStart" BETWEEN ep."PeriodStartDate" AND ep."PeriodEndDate"
GROUP BY bc."PracticeCode", ep."PeriodNumber", ep."PeriodStartDate", ep."PeriodEndDate"
)
SELECT
pp."PracticeCode",
pp."PracticeName",
pp."PeriodNumber",
pp."PeriodStartDate",
pp."PeriodEndDate",
COALESCE(bc."BaselineCount", 0) AS "BaselineCount",
COALESCE(ec."EvaluationCount", 0) AS "EvaluationCount",
COALESCE(bc."BaselineCount", 0) - COALESCE(ec."EvaluationCount", 0) AS "ReductionFromBaseline"
FROM practice_periods pp
LEFT JOIN baseline_counts bc
ON pp."PracticeCode" = bc."PracticeCode"
LEFT JOIN evaluation_counts ec
ON pp."PracticeCode" = ec."PracticeCode"
AND pp."PeriodNumber" = ec."PeriodNumber"
ORDER BY
pp."PracticeName",
pp."PeriodNumber";
@@ -0,0 +1,147 @@
/*
Dual-source long-format measure template
========================================
Purpose:
Produce the same measure from dispensing and prescribing data, then return
a tidy long output:
OrganisationName, PeriodStartDate, PeriodEndDate, DataSource,
Measure, Indicator, Value
Why this shape:
- Easy to append multiple measures.
- Easy to chart in Excel or Power BI.
- Avoids changing columns every time a new indicator is added.
Replace the BNF filter and measure-specific calculations before use.
*/
SET FIRST_PERIOD_END_DATE = '2025-06-30';
SET LAST_PERIOD_END_DATE = LAST_DAY(DATEADD('MONTH', -1, CURRENT_DATE()));
SET LOOKBACK_MONTHS = 12;
SET BNF_PREFIX = '0501';
SET MEASURE_ID = 'M_REPLACE';
WITH RECURSIVE date_periods AS (
-- Month-end series; cap LAST_PERIOD_END_DATE before sharing a final report.
SELECT $FIRST_PERIOD_END_DATE::DATE AS "PeriodEndDate"
UNION ALL
SELECT LAST_DAY(DATEADD(MONTH, 1, "PeriodEndDate"))::DATE AS "PeriodEndDate"
FROM date_periods
WHERE "PeriodEndDate" < $LAST_PERIOD_END_DATE::DATE
),
rolling_periods AS (
-- Converts each period end into a fixed lookback window.
SELECT
DATEADD(MONTH, 1 - $LOOKBACK_MONTHS, DATE_TRUNC('MONTH', "PeriodEndDate"))::DATE AS "PeriodStartDate",
"PeriodEndDate"
FROM date_periods
),
date_bounds AS (
SELECT
MIN("PeriodStartDate") AS "MinPeriodStartDate",
MAX("PeriodEndDate") AS "MaxPeriodEndDate"
FROM rolling_periods
),
practices AS (
-- Default reporting geography: active Norfolk and Suffolk parent GP practices.
SELECT DISTINCT
"OrganisationCode" AS "PracticeCode",
"OrganisationName" AS "OrganisationName"
FROM DATA_HUB.DWH."DimOrganisationAndSite"
WHERE "OrganisationSubType" = 'GP Practice'
AND "IsSiteActive" = 'Yes'
AND "IsSiteNorfolkAndSuffolk" = 'Yes'
AND "SiteCode" = "OrganisationCode"
),
practice_periods AS (
SELECT
p."PracticeCode",
p."OrganisationName",
rp."PeriodStartDate",
rp."PeriodEndDate"
FROM practices p
CROSS JOIN rolling_periods rp
),
prescribing_events AS (
-- Pre-filter prescribing once to keep later rolling joins smaller.
SELECT
rx."PersonKey",
rx."CurrentGeneralPractice",
rx."DateMedicationStart",
rx."Quantity",
rx."EstPrice"
FROM REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable" rx
CROSS JOIN date_bounds db
INNER JOIN DATA_HUB.DWH."DimMedicineAndDevice" med
ON rx."SNOMEDCode" = med."ProductSnomedCode"
AND med."BNFCode" LIKE $BNF_PREFIX || '%'
WHERE rx."PersonKey" IS NOT NULL
AND rx."DateMedicationStart" BETWEEN db."MinPeriodStartDate" AND db."MaxPeriodEndDate"
),
dispensing_agg AS (
-- Dispensing is official paid activity; use ProcessingPeriodDate for periods.
SELECT
pp."OrganisationName",
pp."PeriodStartDate",
pp."PeriodEndDate",
COUNT(DISTINCT gpm."PatientPseudonym") AS "Patients",
COALESCE(SUM(gpm."ItemCount"), 0) AS "Items",
COALESCE(SUM(gpm."PaidQuantity"), 0) AS "Quantity"
FROM practice_periods pp
LEFT JOIN NATIONAL.GPMED."MedicinesDispensedInPrimarycare" gpm
ON pp."PracticeCode" = gpm."CostCentreODSCode"
AND gpm."ProcessingPeriodDate" BETWEEN pp."PeriodStartDate" AND pp."PeriodEndDate"
AND gpm."PaidBNFCode" LIKE $BNF_PREFIX || '%'
AND gpm."PatientPseudonym" IS NOT NULL
GROUP BY pp."OrganisationName", pp."PeriodStartDate", pp."PeriodEndDate"
),
prescribing_agg AS (
-- Prescribing is current clinical-system activity from the unified table.
SELECT
pp."OrganisationName",
pp."PeriodStartDate",
pp."PeriodEndDate",
COUNT(DISTINCT rx."PersonKey") AS "Patients",
COUNT(rx."PersonKey") AS "Items",
COALESCE(SUM(TRY_CAST(rx."Quantity" AS FLOAT)), 0) AS "Quantity",
COALESCE(SUM(rx."EstPrice"), 0) AS "EstimatedCost"
FROM practice_periods pp
LEFT JOIN prescribing_events rx
ON pp."PracticeCode" = rx."CurrentGeneralPractice"
AND rx."DateMedicationStart" BETWEEN pp."PeriodStartDate" AND pp."PeriodEndDate"
GROUP BY pp."OrganisationName", pp."PeriodStartDate", pp."PeriodEndDate"
)
SELECT
"OrganisationName",
"PeriodStartDate",
"PeriodEndDate",
'Dispensing' AS "DataSource",
$MEASURE_ID AS "Measure",
'Patients' AS "Indicator",
CAST("Patients" AS FLOAT) AS "Value"
FROM dispensing_agg
UNION ALL
SELECT "OrganisationName", "PeriodStartDate", "PeriodEndDate", 'Dispensing', $MEASURE_ID, 'Items', CAST("Items" AS FLOAT)
FROM dispensing_agg
UNION ALL
SELECT "OrganisationName", "PeriodStartDate", "PeriodEndDate", 'Dispensing', $MEASURE_ID, 'Quantity', CAST("Quantity" AS FLOAT)
FROM dispensing_agg
UNION ALL
SELECT "OrganisationName", "PeriodStartDate", "PeriodEndDate", 'Prescribing', $MEASURE_ID, 'Patients', CAST("Patients" AS FLOAT)
FROM prescribing_agg
UNION ALL
SELECT "OrganisationName", "PeriodStartDate", "PeriodEndDate", 'Prescribing', $MEASURE_ID, 'Items', CAST("Items" AS FLOAT)
FROM prescribing_agg
UNION ALL
SELECT "OrganisationName", "PeriodStartDate", "PeriodEndDate", 'Prescribing', $MEASURE_ID, 'Quantity', CAST("Quantity" AS FLOAT)
FROM prescribing_agg
UNION ALL
SELECT "OrganisationName", "PeriodStartDate", "PeriodEndDate", 'Prescribing', $MEASURE_ID, 'EstimatedCost', CAST("EstimatedCost" AS FLOAT)
FROM prescribing_agg
ORDER BY
"PeriodEndDate",
"DataSource",
"OrganisationName",
"Indicator";
+36
View File
@@ -0,0 +1,36 @@
/*
Latest data dates
=================
Purpose:
Check freshness anchors before deciding reporting periods.
Notes:
- Dispensing uses ProcessingPeriodDate and usually lags.
- Unified prescribing DateMedicationStart can include future starts, so the
TPP DateEventRecorded probe is included as a more conservative source
event freshness marker.
*/
SELECT
'NATIONAL.GPMED.MedicinesDispensedInPrimarycare' AS "Source",
MAX("ProcessingPeriodDate")::DATE AS "LatestDate"
FROM NATIONAL.GPMED."MedicinesDispensedInPrimarycare"
UNION ALL
SELECT
'REPORTING_DATASETS_ICB.SCRATCHPAD.MEDS__UnifiedPrescribingTable DateMedicationStart' AS "Source",
MAX("DateMedicationStart")::DATE AS "LatestDate"
FROM REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable"
WHERE "DateMedicationStart" <= CURRENT_DATE()
UNION ALL
SELECT
'PRIMARY_CARE.TPP.SRPrimaryCareMedication DateEventRecorded' AS "Source",
MAX(CAST("DateEventRecorded" AS DATE)) AS "LatestDate"
FROM PRIMARY_CARE.TPP."SRPrimaryCareMedication"
WHERE "DateEventRecorded" >= DATEADD('MONTH', -3, CURRENT_DATE())
ORDER BY "Source";
@@ -0,0 +1,39 @@
/*
Rolling period generator
========================
Purpose:
Generate reusable rolling reporting windows for monthly outputs.
Use this first when a measure needs:
- one row per practice per period;
- a rolling lookback window;
- stable PeriodStartDate and PeriodEndDate columns for Excel or Power BI.
*/
SET FIRST_PERIOD_END_DATE = '2025-06-30';
SET LAST_PERIOD_END_DATE = LAST_DAY(DATEADD('MONTH', -1, CURRENT_DATE()));
SET LOOKBACK_MONTHS = 12;
WITH RECURSIVE date_periods AS (
-- Month-end series; cap LAST_PERIOD_END_DATE before sharing a final report.
SELECT $FIRST_PERIOD_END_DATE::DATE AS "PeriodEndDate"
UNION ALL
SELECT LAST_DAY(DATEADD(MONTH, 1, "PeriodEndDate"))::DATE AS "PeriodEndDate"
FROM date_periods
WHERE "PeriodEndDate" < $LAST_PERIOD_END_DATE::DATE
),
rolling_periods AS (
-- Converts each period end into a fixed lookback window.
SELECT
DATEADD(MONTH, 1 - $LOOKBACK_MONTHS, DATE_TRUNC('MONTH', "PeriodEndDate"))::DATE AS "PeriodStartDate",
"PeriodEndDate",
$LOOKBACK_MONTHS AS "LookbackMonths"
FROM date_periods
)
SELECT
"PeriodStartDate",
"PeriodEndDate",
"LookbackMonths"
FROM rolling_periods
ORDER BY "PeriodEndDate";