initial commit
This commit is contained in:
+15
@@ -0,0 +1,15 @@
|
|||||||
|
*.csv
|
||||||
|
*.xlsx
|
||||||
|
*.xls
|
||||||
|
*.parquet
|
||||||
|
*.html
|
||||||
|
*.png
|
||||||
|
*.jpg
|
||||||
|
*.jpeg
|
||||||
|
*.log
|
||||||
|
*.tmp
|
||||||
|
.tmp/
|
||||||
|
.vscode/
|
||||||
|
.claude/
|
||||||
|
.openpackage/
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# Copied Reference Queries
|
||||||
|
|
||||||
|
These files were copied from the working `Snowflake-Queries` repo because they were already explicitly template-like.
|
||||||
|
|
||||||
|
Use these as reference examples, not as the first place to start a new query. Several contain historic assumptions such as Norfolk and Waveney geography, hardcoded SNOMED codes, or notes that were current when the original work was done.
|
||||||
|
|
||||||
|
For new work, start from the cleaned templates in the numbered folders at the repo root.
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
|
||||||
|
- `medicine_lookup_checks/`: original short checks for prescribing or dispensing by VTM or VMP.
|
||||||
|
- `pqs_long_format/`: original PQS long-format and rolling-period templates.
|
||||||
|
- `useful_short_queries/`: original compact lookup, freshness, price/unit, and practice-list queries.
|
||||||
|
|
||||||
|
The original `CheckPrescribingByPseudo.sql` file was deliberately not copied because it contains a hardcoded patient pseudonym.
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
-- Snowflake version: Check dispensing by VMP (Virtual Medicinal Product)
|
||||||
|
-- Uses GPMeds dispensing data from NATIONAL.GPMED
|
||||||
|
|
||||||
|
WITH SnomedCodes AS (
|
||||||
|
SELECT "ProductSnomedCode"
|
||||||
|
FROM DATA_HUB.DWH."DimMedicineAndDevice"
|
||||||
|
WHERE "MedicinalLatestSnomedCode" = '40326811000001109' -- Specific VMP
|
||||||
|
),
|
||||||
|
LatestPeriod AS (
|
||||||
|
SELECT MAX("ProcessingPeriodDate") AS MaxPeriodDate
|
||||||
|
FROM NATIONAL.GPMED."MedicinesDispensedInPrimarycare"
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
gpm."ProcessingPeriodDate",
|
||||||
|
dos."OrganisationName",
|
||||||
|
COUNT(DISTINCT gpm."PatientPseudonym") AS UniquePatientCount,
|
||||||
|
SUM(gpm."ItemCount") AS TotalItemsDispensed,
|
||||||
|
SUM(gpm."PaidQuantity") AS TotalQuantityDispensed
|
||||||
|
FROM NATIONAL.GPMED."MedicinesDispensedInPrimarycare" gpm
|
||||||
|
INNER JOIN SnomedCodes sc ON gpm."PaiddmdCode" = sc."ProductSnomedCode"
|
||||||
|
LEFT JOIN DATA_HUB.DWH."DimOrganisationAndSite" dos
|
||||||
|
ON gpm."CostCentreODSCode" = dos."SiteCode"
|
||||||
|
CROSS JOIN LatestPeriod lp
|
||||||
|
WHERE gpm."ProcessingPeriodDate" > DATEADD(MONTH, -12, lp.MaxPeriodDate)
|
||||||
|
AND gpm."ProcessingPeriodDate" <= lp.MaxPeriodDate
|
||||||
|
GROUP BY gpm."ProcessingPeriodDate", dos."OrganisationName", gpm."CostCentreODSCode"
|
||||||
|
ORDER BY gpm."ProcessingPeriodDate", dos."OrganisationName";
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
-- Snowflake version: Check dispensing by VTM (Virtual Therapeutic Moiety)
|
||||||
|
-- Uses GPMeds dispensing data from NATIONAL.GPMED
|
||||||
|
|
||||||
|
WITH SnomedCodes AS (
|
||||||
|
SELECT "ProductSnomedCode", "ProductDescription"
|
||||||
|
FROM DATA_HUB.DWH."DimMedicineAndDevice"
|
||||||
|
WHERE "TherapeuticMoietySnomedCode" = '41145911000001106' -- Tirzepatide VTM
|
||||||
|
),
|
||||||
|
LatestPeriod AS (
|
||||||
|
SELECT MAX("ProcessingPeriodDate") AS MaxPeriodDate
|
||||||
|
FROM NATIONAL.GPMED."MedicinesDispensedInPrimarycare"
|
||||||
|
)
|
||||||
|
SELECT *
|
||||||
|
FROM NATIONAL.GPMED."MedicinesDispensedInPrimarycare" gpm
|
||||||
|
INNER JOIN SnomedCodes sc ON gpm."PaiddmdCode" = sc."ProductSnomedCode"
|
||||||
|
CROSS JOIN LatestPeriod lp
|
||||||
|
WHERE gpm."ProcessingPeriodDate" > DATEADD(MONTH, -1, lp.MaxPeriodDate)
|
||||||
|
AND gpm."ProcessingPeriodDate" <= lp.MaxPeriodDate
|
||||||
|
limit 100;
|
||||||
|
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
COUNT(DISTINCT gpm."PatientPseudonym") AS UniquePatientCount,
|
||||||
|
MAX(gpm."ProcessingPeriodDate") AS LatestPeriod
|
||||||
|
FROM NATIONAL.GPMED."MedicinesDispensedInPrimarycare" gpm
|
||||||
|
INNER JOIN SnomedCodes sc ON gpm."PaiddmdCode" = sc."ProductSnomedCode"
|
||||||
|
CROSS JOIN LatestPeriod lp
|
||||||
|
WHERE gpm."ProcessingPeriodDate" > DATEADD(MONTH, -1, lp.MaxPeriodDate)
|
||||||
|
AND gpm."ProcessingPeriodDate" <= lp.MaxPeriodDate;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
-- Snowflake version: Check prescribing by VMP (Virtual Medicinal Product)
|
||||||
|
-- Uses unified PrimaryCareMedication table (combines EMIS + TPP)
|
||||||
|
|
||||||
|
SET StartDate = '2025-04-01';
|
||||||
|
SET EndDate = '2025-07-31';
|
||||||
|
|
||||||
|
WITH SnomedCodes AS (
|
||||||
|
SELECT "ProductSnomedCode"
|
||||||
|
FROM DATA_HUB.DWH."DimMedicineAndDevice"
|
||||||
|
WHERE "MedicinalLatestSnomedCode" = '40326811000001109' -- Specific VMP
|
||||||
|
)
|
||||||
|
SELECT DISTINCT
|
||||||
|
pcm."PatientPseudonym",
|
||||||
|
pcm."DateMedicationStart" AS EffectiveDate,
|
||||||
|
CAST(pcm."Quantity" AS VARCHAR(20)) AS Quantity
|
||||||
|
FROM DATA_HUB.PHM."PrimaryCareMedication" pcm
|
||||||
|
INNER JOIN SnomedCodes sc ON pcm."SNOMEDCode" = sc."ProductSnomedCode"
|
||||||
|
WHERE pcm."DateMedicationStart" BETWEEN $StartDate AND $EndDate
|
||||||
|
AND pcm."PatientPseudonym" IS NOT NULL;
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
-- Snowflake version: Check prescribing by VTM (Virtual Therapeutic Moiety)
|
||||||
|
-- Uses unified PrimaryCareMedication table (combines EMIS + TPP)
|
||||||
|
|
||||||
|
SET StartDate = '2025-11-01';
|
||||||
|
SET EndDate = '2025-12-31';
|
||||||
|
|
||||||
|
WITH SnomedCodes AS (
|
||||||
|
SELECT "ProductSnomedCode", "ProductDescription"
|
||||||
|
FROM DATA_HUB.DWH."DimMedicineAndDevice"
|
||||||
|
WHERE "TherapeuticMoietySnomedCode" = '41145911000001106' -- Tirzepatide VTM
|
||||||
|
)
|
||||||
|
SELECT DISTINCT
|
||||||
|
dos."OrganisationName",
|
||||||
|
dp."PersonKey",
|
||||||
|
pcm."DateMedicationStart" AS EffectiveDate,
|
||||||
|
sc."ProductDescription",
|
||||||
|
CAST(pcm."Quantity" AS VARCHAR(20)) AS Quantity,
|
||||||
|
pcm."QuantityText" AS Dosage
|
||||||
|
FROM DATA_HUB.PHM."PrimaryCareMedication" pcm
|
||||||
|
INNER JOIN DATA_HUB.DWH."DimPerson" dp
|
||||||
|
ON pcm."PatientPseudonym" = dp."PatientPseudonym"
|
||||||
|
INNER JOIN SnomedCodes sc
|
||||||
|
ON pcm."SNOMEDCode" = sc."ProductSnomedCode"
|
||||||
|
INNER JOIN DATA_HUB.DWH."DimOrganisationAndSite" dos
|
||||||
|
ON dp."CurrentGeneralPractice" = dos."SiteCode"
|
||||||
|
WHERE pcm."DateMedicationStart" BETWEEN $StartDate AND $EndDate
|
||||||
|
AND pcm."PatientPseudonym" IS NOT NULL
|
||||||
|
AND dos."OrganisationSubType" = 'GP Practice'
|
||||||
|
AND dos."IsSiteNorfolkAndWaveney" = 'Yes'
|
||||||
|
AND dos."IsSiteActive" = 'Yes';
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
-- Snowflake version: Check prescribing by VTM (Virtual Therapeutic Moiety)
|
||||||
|
-- Uses unified PrimaryCareMedication table (combines EMIS + TPP)
|
||||||
|
|
||||||
|
SET StartDate = '2025-05-01';
|
||||||
|
SET EndDate = '2025-11-30';
|
||||||
|
|
||||||
|
WITH SnomedCodes AS (
|
||||||
|
SELECT "ProductSnomedCode", "ProductDescription"
|
||||||
|
FROM DATA_HUB.DWH."DimMedicineAndDevice"
|
||||||
|
WHERE "TherapeuticMoietySnomedCode" = '41145911000001106' -- Tirzepatide VTM
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
DATE_TRUNC('MONTH', pcm."DateMedicationStart") AS PrescribingMonth,
|
||||||
|
COUNT(DISTINCT dp."PersonKey") AS UniquePatientCount
|
||||||
|
FROM DATA_HUB.PHM."PrimaryCareMedication" pcm
|
||||||
|
INNER JOIN DATA_HUB.DWH."DimPerson" dp
|
||||||
|
ON pcm."PatientPseudonym" = dp."PatientPseudonym"
|
||||||
|
INNER JOIN SnomedCodes sc
|
||||||
|
ON pcm."SNOMEDCode" = sc."ProductSnomedCode"
|
||||||
|
INNER JOIN DATA_HUB.DWH."DimOrganisationAndSite" dos
|
||||||
|
ON dp."CurrentGeneralPractice" = dos."SiteCode"
|
||||||
|
WHERE pcm."DateMedicationStart" BETWEEN $StartDate AND $EndDate
|
||||||
|
AND pcm."PatientPseudonym" IS NOT NULL
|
||||||
|
AND dos."OrganisationSubType" = 'GP Practice'
|
||||||
|
AND dos."IsSiteNorfolkAndWaveney" = 'Yes'
|
||||||
|
AND dos."IsSiteActive" = 'Yes'
|
||||||
|
GROUP BY DATE_TRUNC('MONTH', pcm."DateMedicationStart")
|
||||||
|
ORDER BY PrescribingMonth
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
-- Snowflake version: Check prescribing by VTM for last 3 months
|
||||||
|
-- Uses unified PrimaryCareMedication table (combines EMIS + TPP)
|
||||||
|
-- Dynamically calculates date range from latest data
|
||||||
|
|
||||||
|
WITH LatestDate AS (
|
||||||
|
SELECT DATEADD(DAY, 1, MAX("DateMedicationStart")::DATE) AS EndDate
|
||||||
|
FROM DATA_HUB.PHM."PrimaryCareMedication"
|
||||||
|
WHERE "DateMedicationStart" >= DATEADD(MONTH, -6, CURRENT_DATE())
|
||||||
|
),
|
||||||
|
DateRange AS (
|
||||||
|
SELECT
|
||||||
|
EndDate,
|
||||||
|
DATEADD(MONTH, -3, EndDate) AS StartDate
|
||||||
|
FROM LatestDate
|
||||||
|
),
|
||||||
|
SnomedCodes AS (
|
||||||
|
SELECT "ProductSnomedCode", "ProductDescription"
|
||||||
|
FROM DATA_HUB.DWH."DimMedicineAndDevice"
|
||||||
|
WHERE "TherapeuticMoietySnomedCode" = '775477008' -- Tirzepatide VTM
|
||||||
|
),
|
||||||
|
AllPatients AS (
|
||||||
|
SELECT DISTINCT pcm."PatientPseudonym"
|
||||||
|
FROM DATA_HUB.PHM."PrimaryCareMedication" pcm
|
||||||
|
INNER JOIN SnomedCodes sc ON pcm."SNOMEDCode" = sc."ProductSnomedCode"
|
||||||
|
CROSS JOIN DateRange dr
|
||||||
|
WHERE pcm."DateMedicationStart" > dr.StartDate
|
||||||
|
AND pcm."DateMedicationStart" <= dr.EndDate
|
||||||
|
AND pcm."PatientPseudonym" IS NOT NULL
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
COUNT(DISTINCT "PatientPseudonym") AS UniquePatientCount,
|
||||||
|
(SELECT StartDate FROM DateRange) AS StartDate,
|
||||||
|
(SELECT EndDate FROM DateRange) AS EndDate
|
||||||
|
FROM AllPatients;
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
-- ==============================================================================
|
||||||
|
-- PERIOD GENERATOR - Phase 7 Long Format Output
|
||||||
|
-- ==============================================================================
|
||||||
|
-- This file contains the reusable recursive CTE pattern for generating
|
||||||
|
-- dynamic rolling periods from June 2025 to the current month.
|
||||||
|
--
|
||||||
|
-- Requirements:
|
||||||
|
-- - Earliest period: ends 2025-06-30 (hardcoded)
|
||||||
|
-- - Latest period: ends at last day of current month (dynamic)
|
||||||
|
-- - One period per month from June 2025 to current month
|
||||||
|
-- - 12-month lookback for M1, M2, M3, M5, M6, M7, M8
|
||||||
|
-- - 6-month lookback for M4 (Female UTI)
|
||||||
|
--
|
||||||
|
-- Example output (run 2026-01-29):
|
||||||
|
-- 8 periods: Jun 25, Jul 25, Aug 25, Sep 25, Oct 25, Nov 25, Dec 25, Jan 26
|
||||||
|
-- ==============================================================================
|
||||||
|
|
||||||
|
-- ==============================================================================
|
||||||
|
-- RECURSIVE CTE PATTERN (Copy this into each measure query)
|
||||||
|
-- ==============================================================================
|
||||||
|
|
||||||
|
WITH RECURSIVE date_periods AS (
|
||||||
|
-- Anchor: first period ends June 2025
|
||||||
|
SELECT DATE '2025-06-30' AS period_end_date
|
||||||
|
UNION ALL
|
||||||
|
-- Recurse: add one month until we reach current month
|
||||||
|
SELECT LAST_DAY(DATEADD(MONTH, 1, period_end_date))
|
||||||
|
FROM date_periods
|
||||||
|
WHERE period_end_date < LAST_DAY(CURRENT_DATE())
|
||||||
|
),
|
||||||
|
|
||||||
|
-- Calculate start dates for both 12-month and 6-month lookbacks
|
||||||
|
rolling_periods AS (
|
||||||
|
SELECT
|
||||||
|
CAST(DATEADD(MONTH, -11, DATE_TRUNC('MONTH', period_end_date)) AS DATE) AS "PeriodStartDate_12m",
|
||||||
|
CAST(DATEADD(MONTH, -5, DATE_TRUNC('MONTH', period_end_date)) AS DATE) AS "PeriodStartDate_6m",
|
||||||
|
CAST(period_end_date AS DATE) AS "PeriodEndDate"
|
||||||
|
FROM date_periods
|
||||||
|
)
|
||||||
|
|
||||||
|
SELECT * FROM rolling_periods ORDER BY "PeriodEndDate";
|
||||||
|
|
||||||
|
-- ==============================================================================
|
||||||
|
-- EXPECTED OUTPUT (as of January 2026)
|
||||||
|
-- ==============================================================================
|
||||||
|
-- PeriodEndDate PeriodStartDate_12m PeriodStartDate_6m
|
||||||
|
-- 2025-06-30 2024-07-01 2025-01-01
|
||||||
|
-- 2025-07-31 2024-08-01 2025-02-01
|
||||||
|
-- 2025-08-31 2024-09-01 2025-03-01
|
||||||
|
-- 2025-09-30 2024-10-01 2025-04-01
|
||||||
|
-- 2025-10-31 2024-11-01 2025-05-01
|
||||||
|
-- 2025-11-30 2024-12-01 2025-06-01
|
||||||
|
-- 2025-12-31 2025-01-01 2025-07-01
|
||||||
|
-- 2026-01-31 2025-02-01 2025-08-01
|
||||||
|
--
|
||||||
|
-- 8 periods total (June 2025 through January 2026)
|
||||||
|
-- ==============================================================================
|
||||||
|
|
||||||
|
-- ==============================================================================
|
||||||
|
-- USAGE NOTES
|
||||||
|
-- ==============================================================================
|
||||||
|
-- 1. For 12-month measures (M1, M2, M3, M5, M6, M7, M8):
|
||||||
|
-- Filter data WHERE date_column BETWEEN "PeriodStartDate_12m" AND "PeriodEndDate"
|
||||||
|
--
|
||||||
|
-- 2. For 6-month measure (M4):
|
||||||
|
-- Filter data WHERE date_column BETWEEN "PeriodStartDate_6m" AND "PeriodEndDate"
|
||||||
|
--
|
||||||
|
-- 3. The recursive CTE is dynamic:
|
||||||
|
-- - Running in January 2026 → 8 periods
|
||||||
|
-- - Running in February 2026 → 9 periods
|
||||||
|
-- - Running in June 2026 → 13 periods
|
||||||
|
--
|
||||||
|
-- 4. This pattern should be included at the START of each measure query
|
||||||
|
-- before the main data CTEs.
|
||||||
|
-- ==============================================================================
|
||||||
|
|
||||||
|
-- ==============================================================================
|
||||||
|
-- DATA AVAILABILITY NOTES
|
||||||
|
-- ==============================================================================
|
||||||
|
-- DISPENSING (NATIONAL.GPMED.MedicinesDispensedInPrimarycare):
|
||||||
|
-- Max date: ~2025-07 (updates monthly)
|
||||||
|
-- Min date: 2018-04
|
||||||
|
-- Coverage: 7+ years — all periods will have full data
|
||||||
|
--
|
||||||
|
-- PRESCRIBING (REPORTING_DATASETS_ICB.SCRATCHPAD.MEDS__UnifiedPrescribingTable):
|
||||||
|
-- Max date: ~2026-01 (updates frequently)
|
||||||
|
-- Min date: 2024-01
|
||||||
|
-- Coverage: ~2 years — earlier periods may have partial/no data
|
||||||
|
-- Note: Periods with PeriodStartDate before 2024-01 will show no prescribing data
|
||||||
|
-- ==============================================================================
|
||||||
@@ -0,0 +1,203 @@
|
|||||||
|
-- ==============================================================================
|
||||||
|
-- ROLLING PERIODS TEMPLATE - Phase 7 Long Format Output
|
||||||
|
-- ==============================================================================
|
||||||
|
-- This file documents the reusable CTE patterns for generating rolling time
|
||||||
|
-- periods for both dispensing and prescribing data sources.
|
||||||
|
--
|
||||||
|
-- Key considerations:
|
||||||
|
-- - Dispensing data: 2018-04 to 2025-07 (88 months) - full historical coverage
|
||||||
|
-- - Prescribing data: 2024-01 to 2026-01 (25 months) - LIMITED HISTORY
|
||||||
|
-- (prescribing period 2 will have partial/no data)
|
||||||
|
--
|
||||||
|
-- IMPORTANT: Each data source has its own MAX date, so periods must be
|
||||||
|
-- calculated separately within each UNION ALL branch.
|
||||||
|
-- ==============================================================================
|
||||||
|
|
||||||
|
-- ==============================================================================
|
||||||
|
-- PATTERN 1: 12-MONTH ROLLING PERIODS (for M1, M2, M3, M5, M6, M7, M8)
|
||||||
|
-- ==============================================================================
|
||||||
|
-- Generates 3 rolling periods covering approximately 3 years:
|
||||||
|
-- Period 0: Most recent 12 months
|
||||||
|
-- Period 1: 12-24 months ago
|
||||||
|
-- Period 2: 24-36 months ago
|
||||||
|
|
||||||
|
/*
|
||||||
|
-- DISPENSING DATA version:
|
||||||
|
WITH max_dates_disp AS (
|
||||||
|
SELECT MAX("ProcessingPeriodDate") AS max_date
|
||||||
|
FROM NATIONAL.GPMED."MedicinesDispensedInPrimarycare"
|
||||||
|
),
|
||||||
|
period_offsets AS (
|
||||||
|
SELECT 0 AS period_offset UNION ALL
|
||||||
|
SELECT 1 UNION ALL
|
||||||
|
SELECT 2
|
||||||
|
),
|
||||||
|
rolling_periods_12m AS (
|
||||||
|
SELECT
|
||||||
|
period_offset,
|
||||||
|
CAST(DATEADD(MONTH, -11, DATE_TRUNC('MONTH', DATEADD(MONTH, -12 * period_offset, max_date))) AS DATE) AS period_start_date,
|
||||||
|
CAST(LAST_DAY(DATEADD(MONTH, -12 * period_offset, max_date)) AS DATE) AS period_end_date
|
||||||
|
FROM period_offsets, max_dates_disp
|
||||||
|
)
|
||||||
|
-- Then filter data WHERE "ProcessingPeriodDate" BETWEEN period_start_date AND period_end_date
|
||||||
|
|
||||||
|
-- Example output (as of July 2025):
|
||||||
|
-- Period 0: 2024-08-01 to 2025-07-31
|
||||||
|
-- Period 1: 2023-08-01 to 2024-07-31
|
||||||
|
-- Period 2: 2022-08-01 to 2023-07-31
|
||||||
|
*/
|
||||||
|
|
||||||
|
-- ==============================================================================
|
||||||
|
-- PATTERN 2: 6-MONTH ROLLING PERIODS (for M4 - Female UTI)
|
||||||
|
-- ==============================================================================
|
||||||
|
-- Generates 6 rolling periods covering approximately 3 years:
|
||||||
|
-- Period 0: Most recent 6 months
|
||||||
|
-- Period 1: 6-12 months ago
|
||||||
|
-- Period 2: 12-18 months ago
|
||||||
|
-- ...etc
|
||||||
|
|
||||||
|
/*
|
||||||
|
WITH max_dates_disp AS (
|
||||||
|
SELECT MAX("ProcessingPeriodDate") AS max_date
|
||||||
|
FROM NATIONAL.GPMED."MedicinesDispensedInPrimarycare"
|
||||||
|
),
|
||||||
|
period_offsets AS (
|
||||||
|
SELECT 0 AS period_offset UNION ALL
|
||||||
|
SELECT 1 UNION ALL
|
||||||
|
SELECT 2 UNION ALL
|
||||||
|
SELECT 3 UNION ALL
|
||||||
|
SELECT 4 UNION ALL
|
||||||
|
SELECT 5
|
||||||
|
),
|
||||||
|
rolling_periods_6m AS (
|
||||||
|
SELECT
|
||||||
|
period_offset,
|
||||||
|
CAST(DATEADD(MONTH, -5, DATE_TRUNC('MONTH', DATEADD(MONTH, -6 * period_offset, max_date))) AS DATE) AS period_start_date,
|
||||||
|
CAST(LAST_DAY(DATEADD(MONTH, -6 * period_offset, max_date)) AS DATE) AS period_end_date
|
||||||
|
FROM period_offsets, max_dates_disp
|
||||||
|
)
|
||||||
|
-- Then filter data WHERE "ProcessingPeriodDate" BETWEEN period_start_date AND period_end_date
|
||||||
|
|
||||||
|
-- Example output (as of July 2025):
|
||||||
|
-- Period 0: 2025-02-01 to 2025-07-31
|
||||||
|
-- Period 1: 2024-08-01 to 2025-01-31
|
||||||
|
-- Period 2: 2024-02-01 to 2024-07-31
|
||||||
|
-- Period 3: 2023-08-01 to 2024-01-31
|
||||||
|
-- Period 4: 2023-02-01 to 2023-07-31
|
||||||
|
-- Period 5: 2022-08-01 to 2023-01-31
|
||||||
|
*/
|
||||||
|
|
||||||
|
-- ==============================================================================
|
||||||
|
-- COMBINED DISPENSING + PRESCRIBING TEMPLATE
|
||||||
|
-- ==============================================================================
|
||||||
|
-- Each data source calculates periods from its own MAX date, then combines
|
||||||
|
-- with UNION ALL. The DataSource column distinguishes them.
|
||||||
|
|
||||||
|
/*
|
||||||
|
WITH
|
||||||
|
-- =========================
|
||||||
|
-- DISPENSING PERIODS
|
||||||
|
-- =========================
|
||||||
|
max_dates_disp AS (
|
||||||
|
SELECT MAX("ProcessingPeriodDate") AS max_date
|
||||||
|
FROM NATIONAL.GPMED."MedicinesDispensedInPrimarycare"
|
||||||
|
),
|
||||||
|
period_offsets AS (
|
||||||
|
SELECT 0 AS period_offset UNION ALL SELECT 1 UNION ALL SELECT 2
|
||||||
|
),
|
||||||
|
disp_periods AS (
|
||||||
|
SELECT
|
||||||
|
period_offset,
|
||||||
|
CAST(DATEADD(MONTH, -11, DATE_TRUNC('MONTH', DATEADD(MONTH, -12 * period_offset, max_date))) AS DATE) AS period_start_date,
|
||||||
|
CAST(LAST_DAY(DATEADD(MONTH, -12 * period_offset, max_date)) AS DATE) AS period_end_date
|
||||||
|
FROM period_offsets, max_dates_disp
|
||||||
|
),
|
||||||
|
|
||||||
|
-- =========================
|
||||||
|
-- PRESCRIBING PERIODS
|
||||||
|
-- =========================
|
||||||
|
max_dates_pres AS (
|
||||||
|
SELECT MAX("DateMedicationStart") AS max_date
|
||||||
|
FROM REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable"
|
||||||
|
WHERE "DateMedicationStart" IS NOT NULL
|
||||||
|
),
|
||||||
|
pres_periods AS (
|
||||||
|
SELECT
|
||||||
|
period_offset,
|
||||||
|
CAST(DATEADD(MONTH, -11, DATE_TRUNC('MONTH', DATEADD(MONTH, -12 * period_offset, max_date))) AS DATE) AS period_start_date,
|
||||||
|
CAST(LAST_DAY(DATEADD(MONTH, -12 * period_offset, max_date)) AS DATE) AS period_end_date
|
||||||
|
FROM period_offsets, max_dates_pres
|
||||||
|
),
|
||||||
|
|
||||||
|
-- =========================
|
||||||
|
-- DATA QUERIES (example structure)
|
||||||
|
-- =========================
|
||||||
|
disp_data AS (
|
||||||
|
SELECT
|
||||||
|
org."OrganisationName",
|
||||||
|
dp.period_start_date AS "PeriodStartDate",
|
||||||
|
dp.period_end_date AS "PeriodEndDate",
|
||||||
|
'Dispensing' AS "DataSource",
|
||||||
|
-- ... aggregations
|
||||||
|
FROM NATIONAL.GPMED."MedicinesDispensedInPrimarycare" meds
|
||||||
|
CROSS JOIN disp_periods dp
|
||||||
|
JOIN DATA_HUB.DWH."DimOrganisationAndSite" org ON ...
|
||||||
|
WHERE meds."ProcessingPeriodDate" BETWEEN dp.period_start_date AND dp.period_end_date
|
||||||
|
GROUP BY org."OrganisationName", dp.period_start_date, dp.period_end_date
|
||||||
|
),
|
||||||
|
|
||||||
|
pres_data AS (
|
||||||
|
SELECT
|
||||||
|
org."OrganisationName",
|
||||||
|
pp.period_start_date AS "PeriodStartDate",
|
||||||
|
pp.period_end_date AS "PeriodEndDate",
|
||||||
|
'Prescribing' AS "DataSource",
|
||||||
|
-- ... aggregations
|
||||||
|
FROM REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable" rx
|
||||||
|
CROSS JOIN pres_periods pp
|
||||||
|
JOIN DATA_HUB.DWH."DimOrganisationAndSite" org ON ...
|
||||||
|
WHERE rx."DateMedicationStart" BETWEEN pp.period_start_date AND pp.period_end_date
|
||||||
|
GROUP BY org."OrganisationName", pp.period_start_date, pp.period_end_date
|
||||||
|
)
|
||||||
|
|
||||||
|
-- =========================
|
||||||
|
-- UNPIVOT TO LONG FORMAT
|
||||||
|
-- =========================
|
||||||
|
SELECT "OrganisationName", "PeriodStartDate", "PeriodEndDate", "DataSource",
|
||||||
|
'M1' AS "Measure", 'IndicatorA' AS "Indicator", CAST("IndicatorA" AS FLOAT) AS "Value"
|
||||||
|
FROM disp_data
|
||||||
|
UNION ALL
|
||||||
|
SELECT "OrganisationName", "PeriodStartDate", "PeriodEndDate", "DataSource",
|
||||||
|
'M1' AS "Measure", 'IndicatorB' AS "Indicator", CAST("IndicatorB" AS FLOAT) AS "Value"
|
||||||
|
FROM disp_data
|
||||||
|
UNION ALL
|
||||||
|
SELECT "OrganisationName", "PeriodStartDate", "PeriodEndDate", "DataSource",
|
||||||
|
'M1' AS "Measure", 'IndicatorA' AS "Indicator", CAST("IndicatorA" AS FLOAT) AS "Value"
|
||||||
|
FROM pres_data
|
||||||
|
UNION ALL
|
||||||
|
SELECT "OrganisationName", "PeriodStartDate", "PeriodEndDate", "DataSource",
|
||||||
|
'M1' AS "Measure", 'IndicatorB' AS "Indicator", CAST("IndicatorB" AS FLOAT) AS "Value"
|
||||||
|
FROM pres_data
|
||||||
|
*/
|
||||||
|
|
||||||
|
-- ==============================================================================
|
||||||
|
-- DATE RANGE NOTES
|
||||||
|
-- ==============================================================================
|
||||||
|
-- As of January 2026:
|
||||||
|
--
|
||||||
|
-- DISPENSING (NATIONAL.GPMED.MedicinesDispensedInPrimarycare):
|
||||||
|
-- Max date: 2025-07-01
|
||||||
|
-- Min date: 2018-04-01
|
||||||
|
-- Coverage: 88 months (7+ years)
|
||||||
|
-- All 3 rolling periods have full data
|
||||||
|
--
|
||||||
|
-- PRESCRIBING (REPORTING_DATASETS_ICB.SCRATCHPAD.MEDS__UnifiedPrescribingTable):
|
||||||
|
-- Max date: 2026-01-06
|
||||||
|
-- Min date: 2024-01-06
|
||||||
|
-- Coverage: 25 months (~2 years)
|
||||||
|
-- Period 0: Full data
|
||||||
|
-- Period 1: Full data
|
||||||
|
-- Period 2: PARTIAL OR NO DATA (starts 2023-02, but data begins 2024-01)
|
||||||
|
--
|
||||||
|
-- This asymmetry is expected - prescribing data is newer than dispensing.
|
||||||
|
-- ==============================================================================
|
||||||
@@ -0,0 +1,255 @@
|
|||||||
|
-- ==============================================================================
|
||||||
|
-- UNIFIED SQL TEMPLATE - Phase 7 Long Format Output
|
||||||
|
-- ==============================================================================
|
||||||
|
-- This template shows the complete pattern for converting measures to long format
|
||||||
|
-- with both dispensing and prescribing data sources and rolling time periods.
|
||||||
|
--
|
||||||
|
-- Output columns (7 standard columns):
|
||||||
|
-- OrganisationName - GP Practice name
|
||||||
|
-- PeriodStartDate - Start of the time window (DATE type)
|
||||||
|
-- PeriodEndDate - End of the time window (DATE type)
|
||||||
|
-- DataSource - 'Dispensing' or 'Prescribing'
|
||||||
|
-- Measure - Measure identifier (e.g., 'M2')
|
||||||
|
-- Indicator - Metric name (e.g., 'TotalPrescriptions')
|
||||||
|
-- Value - The metric value (FLOAT type)
|
||||||
|
--
|
||||||
|
-- Key patterns:
|
||||||
|
-- 1. Recursive CTE generates all periods from June 2025 to current month
|
||||||
|
-- 2. Cross join practices with periods for all combinations
|
||||||
|
-- 3. Left join dispensing data filtered by date range per period
|
||||||
|
-- 4. Inner join prescribing data filtered by date range per period
|
||||||
|
-- 5. UNION ALL to unpivot wide indicators into long format
|
||||||
|
-- 6. UNION ALL to combine dispensing and prescribing data sources
|
||||||
|
-- ==============================================================================
|
||||||
|
|
||||||
|
-- ==============================================================================
|
||||||
|
-- SECTION 1: RECURSIVE PERIOD GENERATOR
|
||||||
|
-- Copy this section to all measure queries unchanged
|
||||||
|
-- ==============================================================================
|
||||||
|
|
||||||
|
WITH RECURSIVE date_periods AS (
|
||||||
|
-- Anchor: first period ends June 2025
|
||||||
|
SELECT DATE '2025-06-30' AS period_end_date
|
||||||
|
UNION ALL
|
||||||
|
-- Recurse: add one month until we reach current month
|
||||||
|
SELECT LAST_DAY(DATEADD(MONTH, 1, period_end_date))
|
||||||
|
FROM date_periods
|
||||||
|
WHERE period_end_date < LAST_DAY(CURRENT_DATE())
|
||||||
|
),
|
||||||
|
rolling_periods AS (
|
||||||
|
SELECT
|
||||||
|
-- For 12-month measures (M1, M2, M3, M5, M6, M7, M8):
|
||||||
|
CAST(DATEADD(MONTH, -11, DATE_TRUNC('MONTH', period_end_date)) AS DATE) AS "PeriodStartDate",
|
||||||
|
-- For 6-month measures (M4), use this instead:
|
||||||
|
-- CAST(DATEADD(MONTH, -5, DATE_TRUNC('MONTH', period_end_date)) AS DATE) AS "PeriodStartDate",
|
||||||
|
CAST(period_end_date AS DATE) AS "PeriodEndDate"
|
||||||
|
FROM date_periods
|
||||||
|
),
|
||||||
|
|
||||||
|
-- ==============================================================================
|
||||||
|
-- SECTION 2: COMMON REFERENCE TABLES
|
||||||
|
-- Adapt these CTEs based on measure requirements
|
||||||
|
-- ==============================================================================
|
||||||
|
|
||||||
|
practices AS (
|
||||||
|
-- Norfolk & Waveney GP practices
|
||||||
|
SELECT DISTINCT "OrganisationCode", "OrganisationName"
|
||||||
|
FROM DATA_HUB.DWH."DimOrganisationAndSite"
|
||||||
|
WHERE "IsSiteNorfolkAndWaveney" = 'Yes'
|
||||||
|
AND "IsSiteActive" = 'Yes'
|
||||||
|
AND "OrganisationSubType" = 'GP Practice'
|
||||||
|
),
|
||||||
|
practice_periods AS (
|
||||||
|
-- Cross join: all practices × all periods
|
||||||
|
SELECT
|
||||||
|
p."OrganisationCode",
|
||||||
|
p."OrganisationName",
|
||||||
|
rp."PeriodStartDate",
|
||||||
|
rp."PeriodEndDate"
|
||||||
|
FROM practices p
|
||||||
|
CROSS JOIN rolling_periods rp
|
||||||
|
),
|
||||||
|
ooh_providers AS (
|
||||||
|
-- Out of Hours provider organisations (for prescribing data)
|
||||||
|
SELECT DISTINCT "OrganisationCode"
|
||||||
|
FROM DATA_HUB.DWH."DimOrganisationAndSite"
|
||||||
|
WHERE "IsSiteActive" = 'Yes'
|
||||||
|
AND ("OrganisationName" LIKE '%INTEGRATED CARE%'
|
||||||
|
OR "OrganisationName" LIKE '%IC24%'
|
||||||
|
OR "OrganisationCode" = 'Y02751')
|
||||||
|
),
|
||||||
|
patients AS (
|
||||||
|
-- All patients with a registered GP (adapt age/gender filters per measure)
|
||||||
|
SELECT p."PersonKey", p."PatientPseudonym", p."PHMGeneralPractice" AS "GP"
|
||||||
|
FROM DATA_HUB.DWH."DimPerson" p
|
||||||
|
WHERE p."PHMGeneralPractice" IS NOT NULL
|
||||||
|
AND p."PHMGeneralPractice" <> '*'
|
||||||
|
),
|
||||||
|
|
||||||
|
-- ==============================================================================
|
||||||
|
-- SECTION 3: DISPENSING DATA AGGREGATION
|
||||||
|
-- Adapt the SELECT, JOIN, WHERE, and GROUP BY for each measure
|
||||||
|
-- ==============================================================================
|
||||||
|
|
||||||
|
dispensing_agg AS (
|
||||||
|
SELECT
|
||||||
|
pp."OrganisationName",
|
||||||
|
pp."PeriodStartDate",
|
||||||
|
pp."PeriodEndDate",
|
||||||
|
-- Measure-specific aggregations (example: M2 duration)
|
||||||
|
COUNT(DISTINCT meds."PatientPseudonym") AS "UniquePatients",
|
||||||
|
COUNT(*) AS "TotalPrescriptions",
|
||||||
|
SUM(
|
||||||
|
CASE
|
||||||
|
WHEN (LEFT(meds."PaidBNFCode", 9) IN ('0501030I0', '0501030Z0') AND meds."PaidQuantity" > 6) THEN 1
|
||||||
|
WHEN (LEFT(meds."PaidBNFCode", 9) = '0501013B0' AND meds."PaidQuantity" > 15) THEN 1
|
||||||
|
ELSE 0
|
||||||
|
END
|
||||||
|
) AS "PrescriptionsMoreThan5Days"
|
||||||
|
FROM practice_periods pp
|
||||||
|
LEFT JOIN NATIONAL.GPMED."MedicinesDispensedInPrimarycare" meds
|
||||||
|
ON pp."OrganisationCode" = meds."CostCentreODSCode"
|
||||||
|
AND meds."ProcessingPeriodDate" BETWEEN pp."PeriodStartDate" AND pp."PeriodEndDate"
|
||||||
|
-- Measure-specific BNF code filter
|
||||||
|
AND LEFT(meds."PaidBNFCode", 9) IN ('0501030I0', '0501030Z0', '0501013B0')
|
||||||
|
LEFT JOIN DATA_HUB.DWH."DimPerson" dp
|
||||||
|
ON dp."PatientPseudonym" = meds."PatientPseudonym"
|
||||||
|
-- Y02751 exclusion: exclude OOH provider's own registered patients
|
||||||
|
WHERE (pp."OrganisationCode" <> 'Y02751' OR dp."PHMGeneralPractice" = 'Y02751')
|
||||||
|
GROUP BY pp."OrganisationName", pp."PeriodStartDate", pp."PeriodEndDate"
|
||||||
|
-- Only include practices with data
|
||||||
|
HAVING COUNT(*) > 0
|
||||||
|
),
|
||||||
|
dispensing_with_pct AS (
|
||||||
|
-- Calculate derived metrics (percentages, ratios)
|
||||||
|
SELECT
|
||||||
|
"OrganisationName",
|
||||||
|
"PeriodStartDate",
|
||||||
|
"PeriodEndDate",
|
||||||
|
"UniquePatients",
|
||||||
|
"TotalPrescriptions",
|
||||||
|
"PrescriptionsMoreThan5Days",
|
||||||
|
ROUND(100.0 * "PrescriptionsMoreThan5Days" / NULLIF("TotalPrescriptions", 0), 2) AS "PercentageMoreThan5Days"
|
||||||
|
FROM dispensing_agg
|
||||||
|
),
|
||||||
|
|
||||||
|
-- ==============================================================================
|
||||||
|
-- SECTION 4: PRESCRIBING DATA AGGREGATION
|
||||||
|
-- Similar structure to dispensing, but with SNOMED→BNF mapping
|
||||||
|
-- ==============================================================================
|
||||||
|
|
||||||
|
prescribing_agg AS (
|
||||||
|
SELECT
|
||||||
|
pp."OrganisationName",
|
||||||
|
pp."PeriodStartDate",
|
||||||
|
pp."PeriodEndDate",
|
||||||
|
-- Measure-specific aggregations
|
||||||
|
COUNT(DISTINCT patients."PatientPseudonym") AS "UniquePatients",
|
||||||
|
COUNT(*) AS "TotalPrescriptions",
|
||||||
|
SUM(
|
||||||
|
CASE
|
||||||
|
WHEN (LEFT(med."BNFCode", 9) IN ('0501030I0', '0501030Z0') AND rx."Quantity" > 6) THEN 1
|
||||||
|
WHEN (LEFT(med."BNFCode", 9) = '0501013B0' AND rx."Quantity" > 15) THEN 1
|
||||||
|
ELSE 0
|
||||||
|
END
|
||||||
|
) AS "PrescriptionsMoreThan5Days"
|
||||||
|
FROM practice_periods pp
|
||||||
|
INNER JOIN patients ON patients."GP" = pp."OrganisationCode"
|
||||||
|
INNER JOIN REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable" rx
|
||||||
|
ON rx."PersonKey" = patients."PersonKey"
|
||||||
|
AND rx."DateMedicationStart" BETWEEN pp."PeriodStartDate" AND pp."PeriodEndDate"
|
||||||
|
-- SNOMED→BNF mapping via DimMedicineAndDevice
|
||||||
|
INNER JOIN DATA_HUB.DWH."DimMedicineAndDevice" med
|
||||||
|
ON rx."SNOMEDCode" = med."ProductSnomedCode"
|
||||||
|
AND med."BNFCode" IS NOT NULL
|
||||||
|
-- Measure-specific BNF code filter
|
||||||
|
AND LEFT(med."BNFCode", 9) IN ('0501030I0', '0501030Z0', '0501013B0')
|
||||||
|
-- OOH provider filter
|
||||||
|
INNER JOIN ooh_providers ooh ON ooh."OrganisationCode" = rx."OrgCode"
|
||||||
|
-- Exclude OOH provider's own registered patients
|
||||||
|
WHERE NOT (rx."OrgCode" = 'Y02751' AND rx."CurrentGeneralPractice" = 'Y02751')
|
||||||
|
GROUP BY pp."OrganisationName", pp."PeriodStartDate", pp."PeriodEndDate"
|
||||||
|
HAVING COUNT(*) > 0
|
||||||
|
),
|
||||||
|
prescribing_with_pct AS (
|
||||||
|
SELECT
|
||||||
|
"OrganisationName",
|
||||||
|
"PeriodStartDate",
|
||||||
|
"PeriodEndDate",
|
||||||
|
"UniquePatients",
|
||||||
|
"TotalPrescriptions",
|
||||||
|
"PrescriptionsMoreThan5Days",
|
||||||
|
ROUND(100.0 * "PrescriptionsMoreThan5Days" / NULLIF("TotalPrescriptions", 0), 2) AS "PercentageMoreThan5Days"
|
||||||
|
FROM prescribing_agg
|
||||||
|
)
|
||||||
|
|
||||||
|
-- ==============================================================================
|
||||||
|
-- SECTION 5: LONG FORMAT OUTPUT
|
||||||
|
-- Use UNION ALL to:
|
||||||
|
-- 1. Unpivot each indicator into separate rows
|
||||||
|
-- 2. Combine dispensing and prescribing data sources
|
||||||
|
-- ==============================================================================
|
||||||
|
|
||||||
|
-- DISPENSING indicators
|
||||||
|
SELECT "OrganisationName", "PeriodStartDate", "PeriodEndDate",
|
||||||
|
'Dispensing' AS "DataSource", 'M2' AS "Measure",
|
||||||
|
'UniquePatients' AS "Indicator",
|
||||||
|
CAST("UniquePatients" AS FLOAT) AS "Value"
|
||||||
|
FROM dispensing_with_pct
|
||||||
|
UNION ALL
|
||||||
|
SELECT "OrganisationName", "PeriodStartDate", "PeriodEndDate",
|
||||||
|
'Dispensing' AS "DataSource", 'M2' AS "Measure",
|
||||||
|
'TotalPrescriptions' AS "Indicator",
|
||||||
|
CAST("TotalPrescriptions" AS FLOAT) AS "Value"
|
||||||
|
FROM dispensing_with_pct
|
||||||
|
UNION ALL
|
||||||
|
SELECT "OrganisationName", "PeriodStartDate", "PeriodEndDate",
|
||||||
|
'Dispensing' AS "DataSource", 'M2' AS "Measure",
|
||||||
|
'PrescriptionsMoreThan5Days' AS "Indicator",
|
||||||
|
CAST("PrescriptionsMoreThan5Days" AS FLOAT) AS "Value"
|
||||||
|
FROM dispensing_with_pct
|
||||||
|
UNION ALL
|
||||||
|
SELECT "OrganisationName", "PeriodStartDate", "PeriodEndDate",
|
||||||
|
'Dispensing' AS "DataSource", 'M2' AS "Measure",
|
||||||
|
'PercentageMoreThan5Days' AS "Indicator",
|
||||||
|
CAST("PercentageMoreThan5Days" AS FLOAT) AS "Value"
|
||||||
|
FROM dispensing_with_pct
|
||||||
|
UNION ALL
|
||||||
|
-- PRESCRIBING indicators
|
||||||
|
SELECT "OrganisationName", "PeriodStartDate", "PeriodEndDate",
|
||||||
|
'Prescribing' AS "DataSource", 'M2' AS "Measure",
|
||||||
|
'UniquePatients' AS "Indicator",
|
||||||
|
CAST("UniquePatients" AS FLOAT) AS "Value"
|
||||||
|
FROM prescribing_with_pct
|
||||||
|
UNION ALL
|
||||||
|
SELECT "OrganisationName", "PeriodStartDate", "PeriodEndDate",
|
||||||
|
'Prescribing' AS "DataSource", 'M2' AS "Measure",
|
||||||
|
'TotalPrescriptions' AS "Indicator",
|
||||||
|
CAST("TotalPrescriptions" AS FLOAT) AS "Value"
|
||||||
|
FROM prescribing_with_pct
|
||||||
|
UNION ALL
|
||||||
|
SELECT "OrganisationName", "PeriodStartDate", "PeriodEndDate",
|
||||||
|
'Prescribing' AS "DataSource", 'M2' AS "Measure",
|
||||||
|
'PrescriptionsMoreThan5Days' AS "Indicator",
|
||||||
|
CAST("PrescriptionsMoreThan5Days" AS FLOAT) AS "Value"
|
||||||
|
FROM prescribing_with_pct
|
||||||
|
UNION ALL
|
||||||
|
SELECT "OrganisationName", "PeriodStartDate", "PeriodEndDate",
|
||||||
|
'Prescribing' AS "DataSource", 'M2' AS "Measure",
|
||||||
|
'PercentageMoreThan5Days' AS "Indicator",
|
||||||
|
CAST("PercentageMoreThan5Days" AS FLOAT) AS "Value"
|
||||||
|
FROM prescribing_with_pct
|
||||||
|
|
||||||
|
ORDER BY "PeriodEndDate", "DataSource", "OrganisationName", "Indicator";
|
||||||
|
|
||||||
|
-- ==============================================================================
|
||||||
|
-- EXPECTED OUTPUT STRUCTURE
|
||||||
|
-- ==============================================================================
|
||||||
|
-- For M2 with 4 indicators, 2 data sources, 8 periods, ~100 practices:
|
||||||
|
-- Rows ≈ 4 indicators × 2 sources × 8 periods × 100 practices = 6,400 rows
|
||||||
|
--
|
||||||
|
-- Sample row:
|
||||||
|
-- | OrganisationName | PeriodStartDate | PeriodEndDate | DataSource | Measure | Indicator | Value |
|
||||||
|
-- |------------------------|-----------------|---------------|-------------|---------|------------------------|--------|
|
||||||
|
-- | Acle Medical Partnership | 2024-07-01 | 2025-06-30 | Dispensing | M2 | PercentageMoreThan5Days| 57.04 |
|
||||||
|
-- ==============================================================================
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
-- ============================================================================
|
||||||
|
-- MEDS__ProductPriceAndUnitLookup
|
||||||
|
-- Medicine Reference Data: Price Per Unit and Pack Unit Descriptions
|
||||||
|
-- ============================================================================
|
||||||
|
-- Derives PricePerUnit and PackUnitDescription for all dm+d product levels
|
||||||
|
-- For VMPP/AMPP: uses direct values from DimMedicineAndDevice
|
||||||
|
-- For VMP/AMP: derives from child VMPP/AMPP products
|
||||||
|
-- - Price: AVG of child prices
|
||||||
|
-- - Units: MODE (most common) of child units
|
||||||
|
-- Price priority: DrugTariffPricePerUnit > IndicativePricePerUnit > AnnualCost/AnnualQuantity
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
WITH PackLevelData AS (
|
||||||
|
-- Get prices and units for pack-level products (VMPP/AMPP)
|
||||||
|
SELECT
|
||||||
|
"ProductSnomedCode",
|
||||||
|
"ParentPresentationSnomedCode",
|
||||||
|
"ProductLevel",
|
||||||
|
"PackUnitDescription",
|
||||||
|
COALESCE(
|
||||||
|
"DrugTariffPricePerUnit",
|
||||||
|
"IndicativePricePerUnit",
|
||||||
|
CASE WHEN "AnnualQuantity" > 0 THEN "AnnualCost" / "AnnualQuantity" END
|
||||||
|
) AS PricePerUnit
|
||||||
|
FROM DATA_HUB.DWH."DimMedicineAndDevice"
|
||||||
|
WHERE "ProductLevel" IN ('VMPP', 'AMPP')
|
||||||
|
),
|
||||||
|
|
||||||
|
ProductPrices AS (
|
||||||
|
-- Direct prices for VMPP/AMPP
|
||||||
|
SELECT
|
||||||
|
"ProductSnomedCode",
|
||||||
|
PricePerUnit
|
||||||
|
FROM PackLevelData
|
||||||
|
WHERE PricePerUnit IS NOT NULL
|
||||||
|
|
||||||
|
UNION ALL
|
||||||
|
|
||||||
|
-- Aggregated prices for VMP/AMP from their children
|
||||||
|
SELECT
|
||||||
|
parent."ProductSnomedCode",
|
||||||
|
AVG(pld.PricePerUnit) AS PricePerUnit
|
||||||
|
FROM DATA_HUB.DWH."DimMedicineAndDevice" parent
|
||||||
|
JOIN PackLevelData pld ON pld."ParentPresentationSnomedCode" = parent."ProductSnomedCode"
|
||||||
|
WHERE parent."ProductLevel" IN ('VMP', 'AMP')
|
||||||
|
AND pld.PricePerUnit IS NOT NULL
|
||||||
|
GROUP BY parent."ProductSnomedCode"
|
||||||
|
),
|
||||||
|
|
||||||
|
PackUnits AS (
|
||||||
|
-- Direct units for VMPP/AMPP
|
||||||
|
SELECT
|
||||||
|
"ProductSnomedCode",
|
||||||
|
"PackUnitDescription"
|
||||||
|
FROM PackLevelData
|
||||||
|
WHERE "PackUnitDescription" IS NOT NULL
|
||||||
|
|
||||||
|
UNION ALL
|
||||||
|
|
||||||
|
-- Units for VMP/AMP: use most common unit from child VMPP/AMPP products
|
||||||
|
SELECT
|
||||||
|
parent."ProductSnomedCode",
|
||||||
|
MODE(pld."PackUnitDescription") AS "PackUnitDescription"
|
||||||
|
FROM DATA_HUB.DWH."DimMedicineAndDevice" parent
|
||||||
|
JOIN PackLevelData pld ON pld."ParentPresentationSnomedCode" = parent."ProductSnomedCode"
|
||||||
|
WHERE parent."ProductLevel" IN ('VMP', 'AMP')
|
||||||
|
AND pld."PackUnitDescription" IS NOT NULL
|
||||||
|
GROUP BY parent."ProductSnomedCode"
|
||||||
|
)
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- Usage: Join these CTEs to prescribing data on ProductSnomedCode
|
||||||
|
-- ============================================================================
|
||||||
|
-- Example:
|
||||||
|
-- SELECT
|
||||||
|
-- prescribing.*,
|
||||||
|
-- pp.PricePerUnit,
|
||||||
|
-- pu."PackUnitDescription",
|
||||||
|
-- ROUND(pp.PricePerUnit * prescribing."Quantity", 2) AS EstPrice
|
||||||
|
-- FROM [prescribing_data] prescribing
|
||||||
|
-- LEFT JOIN ProductPrices pp ON prescribing."SNOMEDCode" = pp."ProductSnomedCode"
|
||||||
|
-- LEFT JOIN PackUnits pu ON prescribing."SNOMEDCode" = pu."ProductSnomedCode"
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
pp."ProductSnomedCode",
|
||||||
|
pp.PricePerUnit,
|
||||||
|
pu."PackUnitDescription"
|
||||||
|
FROM ProductPrices pp
|
||||||
|
LEFT JOIN PackUnits pu ON pp."ProductSnomedCode" = pu."ProductSnomedCode"
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
-- =============================================================================
|
||||||
|
-- Run BOTH queries and import into a sheet called "Lookup":
|
||||||
|
-- - Column A = Brand Name (from Query 1)
|
||||||
|
-- - Column C = Generic Name (from Query 2)
|
||||||
|
-- =============================================================================
|
||||||
|
|
||||||
|
-- QUERY 1: Brand Names -> paste into Column A of "Lookup" sheet
|
||||||
|
SELECT DISTINCT
|
||||||
|
mad."ProductDescription" AS "Brand Name"
|
||||||
|
FROM DATA_HUB.DWH."DimMedicineAndDevice" mad
|
||||||
|
WHERE mad."ProductDescription" IS NOT NULL
|
||||||
|
ORDER BY mad."ProductDescription";
|
||||||
|
|
||||||
|
|
||||||
|
-- QUERY 2: Generic Names -> paste into Column C of "Lookup" sheet
|
||||||
|
SELECT DISTINCT
|
||||||
|
gen."ProductDescription" AS "Generic Name"
|
||||||
|
FROM DATA_HUB.DWH."DimMedicineAndDevice" mad
|
||||||
|
INNER JOIN DATA_HUB.DWH."DimMedicineAndDevice" gen
|
||||||
|
ON mad."MedicinalLatestSnomedCode" = gen."ProductSnomedCode"
|
||||||
|
WHERE gen."ProductDescription" IS NOT NULL
|
||||||
|
ORDER BY gen."ProductDescription";
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
-- Latest Data Query for Snowflake
|
||||||
|
-- Returns the most recent prescribing system event date.
|
||||||
|
-- DateMedicationStart can include future-dated medication records, so this uses
|
||||||
|
-- DateEventRecorded as the data freshness marker.
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
MAX(CAST("DateEventRecorded" AS DATE)) AS "LatestEventRecordedDate"
|
||||||
|
FROM PRIMARY_CARE.TPP."SRPrimaryCareMedication"
|
||||||
|
WHERE "DateEventRecorded" >= DATEADD('MONTH', -3, CURRENT_DATE());
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
================================================================================
|
||||||
|
HF_07_PracticeList.sql
|
||||||
|
Distinct list of GP Practices in Norfolk & Waveney ICB
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
PURPOSE:
|
||||||
|
Reference list of GP practice codes and names for the heart failure analysis.
|
||||||
|
|
||||||
|
CREATED: 2026-01-13
|
||||||
|
================================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
SELECT DISTINCT
|
||||||
|
org."SiteCode" AS "Practice Code",
|
||||||
|
org."OrganisationName" AS "Practice Name",
|
||||||
|
org."PlaceName" AS "Place",
|
||||||
|
org."PCNName" AS "PCN"
|
||||||
|
FROM DATA_HUB.DWH."DimOrganisationAndSite" org
|
||||||
|
WHERE org."IsSiteActive" = 'Yes'
|
||||||
|
AND org."SiteType" = 'Parent'
|
||||||
|
AND org."IsSiteNorfolkAndWaveney" = 'Yes'
|
||||||
|
AND org."OrganisationSubType" = 'GP Practice'
|
||||||
|
ORDER BY org."OrganisationName";
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
-- REGISTERED POPULATION: Practice population counts for all Norfolk & Waveney GP practices
|
||||||
|
-- Returns OrganisationName and RegisteredPopulation for reporting and per-capita calculations
|
||||||
|
|
||||||
|
SELECT DISTINCT
|
||||||
|
"OrganisationName",
|
||||||
|
"RegisteredPopulation"
|
||||||
|
FROM DATA_HUB.DWH."DimOrganisationAndSite"
|
||||||
|
WHERE "IsSiteNorfolkAndWaveney" = 'Yes'
|
||||||
|
AND "IsSiteActive" = 'Yes'
|
||||||
|
AND "OrganisationSubType" = 'GP Practice'
|
||||||
|
AND "OrganisationName" <> 'Vulnerable Adults Service'
|
||||||
|
ORDER BY "OrganisationName"
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
Dispensing by VTM or VMP
|
||||||
|
========================
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
Summarise dispensed items, patients, and quantity for a medicine group
|
||||||
|
using national dispensing data.
|
||||||
|
|
||||||
|
Data source:
|
||||||
|
NATIONAL.GPMED."MedicinesDispensedInPrimarycare"
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- Dispensing data is official/payment-oriented and usually lags prescribing.
|
||||||
|
- Set either VTM_SNOMED_CODE or VMP_SNOMED_CODE. Leave the other as NULL.
|
||||||
|
- ProcessingPeriodDate is a month-level period date.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SET START_PERIOD = '2025-04-01';
|
||||||
|
SET END_PERIOD = '2026-03-31';
|
||||||
|
SET VTM_SNOMED_CODE = NULL;
|
||||||
|
SET VMP_SNOMED_CODE = 'REPLACE_WITH_VMP_SNOMED_CODE';
|
||||||
|
|
||||||
|
WITH products AS (
|
||||||
|
-- Expands the selected VTM/VMP into product-level dm+d codes found in GPMED.
|
||||||
|
SELECT DISTINCT
|
||||||
|
"ProductSnomedCode",
|
||||||
|
"ProductDescription",
|
||||||
|
"TherapeuticMoietyName",
|
||||||
|
"BNFCode"
|
||||||
|
FROM DATA_HUB.DWH."DimMedicineAndDevice"
|
||||||
|
WHERE ($VTM_SNOMED_CODE IS NOT NULL AND "TherapeuticMoietySnomedCode" = $VTM_SNOMED_CODE)
|
||||||
|
OR ($VMP_SNOMED_CODE IS NOT NULL AND "MedicinalLatestSnomedCode" = $VMP_SNOMED_CODE)
|
||||||
|
OR ($VMP_SNOMED_CODE IS NOT NULL AND "ProductSnomedCode" = $VMP_SNOMED_CODE)
|
||||||
|
),
|
||||||
|
practices AS (
|
||||||
|
-- Restricts output to active Norfolk and Suffolk parent GP practices.
|
||||||
|
SELECT DISTINCT
|
||||||
|
"OrganisationCode" AS "PracticeCode",
|
||||||
|
"OrganisationName" AS "PracticeName",
|
||||||
|
"PCNName",
|
||||||
|
"PlaceName",
|
||||||
|
"AllianceName"
|
||||||
|
FROM DATA_HUB.DWH."DimOrganisationAndSite"
|
||||||
|
WHERE "OrganisationSubType" = 'GP Practice'
|
||||||
|
AND "IsSiteActive" = 'Yes'
|
||||||
|
AND "IsSiteNorfolkAndSuffolk" = 'Yes'
|
||||||
|
AND "SiteCode" = "OrganisationCode"
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
gpm."ProcessingPeriodDate" AS "PeriodDate",
|
||||||
|
p."PracticeCode",
|
||||||
|
p."PracticeName",
|
||||||
|
p."PCNName",
|
||||||
|
p."PlaceName",
|
||||||
|
p."AllianceName",
|
||||||
|
prod."TherapeuticMoietyName",
|
||||||
|
COUNT(DISTINCT gpm."PatientPseudonym") AS "Patients",
|
||||||
|
SUM(gpm."ItemCount") AS "Items",
|
||||||
|
SUM(gpm."PaidQuantity") AS "PaidQuantity"
|
||||||
|
FROM NATIONAL.GPMED."MedicinesDispensedInPrimarycare" gpm
|
||||||
|
INNER JOIN products prod
|
||||||
|
ON gpm."PaiddmdCode" = prod."ProductSnomedCode"
|
||||||
|
INNER JOIN practices p
|
||||||
|
ON gpm."CostCentreODSCode" = p."PracticeCode"
|
||||||
|
WHERE gpm."ProcessingPeriodDate" BETWEEN $START_PERIOD AND $END_PERIOD
|
||||||
|
AND gpm."PatientPseudonym" IS NOT NULL
|
||||||
|
GROUP BY
|
||||||
|
gpm."ProcessingPeriodDate",
|
||||||
|
p."PracticeCode",
|
||||||
|
p."PracticeName",
|
||||||
|
p."PCNName",
|
||||||
|
p."PlaceName",
|
||||||
|
p."AllianceName",
|
||||||
|
prod."TherapeuticMoietyName"
|
||||||
|
ORDER BY
|
||||||
|
"PeriodDate",
|
||||||
|
"PracticeName",
|
||||||
|
prod."TherapeuticMoietyName";
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
Medicine reference lookup
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
Search DATA_HUB.DWH."DimMedicineAndDevice" for dm+d products and their
|
||||||
|
related BNF, VTM, VMP, AMP, and pack-level identifiers.
|
||||||
|
|
||||||
|
Common uses:
|
||||||
|
- Find the SNOMED product codes to use in a prescribing or dispensing query.
|
||||||
|
- Check whether a medicine group is better captured by BNF, VTM, VMP, or
|
||||||
|
explicit product codes.
|
||||||
|
- Understand how products roll up through the dm+d hierarchy.
|
||||||
|
|
||||||
|
Replace the SEARCH_TEXT and optional BNF_PREFIX before running.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SET SEARCH_TEXT = 'tirzepatide';
|
||||||
|
SET BNF_PREFIX = NULL;
|
||||||
|
|
||||||
|
SELECT DISTINCT
|
||||||
|
med."ProductSnomedCode",
|
||||||
|
med."ProductDescription",
|
||||||
|
med."ProductLevel",
|
||||||
|
med."TherapeuticMoietySnomedCode",
|
||||||
|
med."TherapeuticMoietyName",
|
||||||
|
med."MedicinalLatestSnomedCode",
|
||||||
|
med."ParentPresentationSnomedCode",
|
||||||
|
med."BNFCode",
|
||||||
|
med."BNFParagraphCode",
|
||||||
|
med."RouteName",
|
||||||
|
med."StrengthDescription",
|
||||||
|
med."PackUnitDescription",
|
||||||
|
med."IndicativePricePerUnit",
|
||||||
|
med."DrugTariffPricePerUnit"
|
||||||
|
FROM DATA_HUB.DWH."DimMedicineAndDevice" med
|
||||||
|
WHERE (
|
||||||
|
LOWER(med."ProductDescription") LIKE '%' || LOWER($SEARCH_TEXT) || '%'
|
||||||
|
OR LOWER(med."TherapeuticMoietyName") LIKE '%' || LOWER($SEARCH_TEXT) || '%'
|
||||||
|
OR med."ProductSnomedCode" = $SEARCH_TEXT
|
||||||
|
OR med."TherapeuticMoietySnomedCode" = $SEARCH_TEXT
|
||||||
|
OR med."MedicinalLatestSnomedCode" = $SEARCH_TEXT
|
||||||
|
)
|
||||||
|
AND ($BNF_PREFIX IS NULL OR med."BNFCode" LIKE $BNF_PREFIX || '%')
|
||||||
|
ORDER BY
|
||||||
|
med."TherapeuticMoietyName",
|
||||||
|
med."MedicinalLatestSnomedCode",
|
||||||
|
med."ProductLevel",
|
||||||
|
med."ProductDescription";
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
Current prescribing by VMP
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
Return patient-level prescribing records for all products under one
|
||||||
|
Virtual Medicinal Product (VMP).
|
||||||
|
|
||||||
|
Use this when a VTM is too broad and you need a specific formulation,
|
||||||
|
strength, or medicinal product family.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SET START_DATE = '2025-04-01';
|
||||||
|
SET END_DATE = '2026-03-31';
|
||||||
|
SET VMP_SNOMED_CODE = 'REPLACE_WITH_VMP_SNOMED_CODE';
|
||||||
|
|
||||||
|
WITH products AS (
|
||||||
|
-- Expands one VMP to all matching product SNOMED codes in the medicine dimension.
|
||||||
|
SELECT DISTINCT
|
||||||
|
"ProductSnomedCode",
|
||||||
|
"ProductDescription",
|
||||||
|
"ProductLevel",
|
||||||
|
"MedicinalLatestSnomedCode",
|
||||||
|
"TherapeuticMoietyName",
|
||||||
|
"BNFCode",
|
||||||
|
"BNFParagraphCode"
|
||||||
|
FROM DATA_HUB.DWH."DimMedicineAndDevice"
|
||||||
|
WHERE "MedicinalLatestSnomedCode" = $VMP_SNOMED_CODE
|
||||||
|
OR "ProductSnomedCode" = $VMP_SNOMED_CODE
|
||||||
|
),
|
||||||
|
practices AS (
|
||||||
|
-- Restricts output to active Norfolk and Suffolk parent GP practices.
|
||||||
|
SELECT DISTINCT
|
||||||
|
"OrganisationCode" AS "PracticeCode",
|
||||||
|
"OrganisationName" AS "PracticeName",
|
||||||
|
"PCNName",
|
||||||
|
"PlaceName",
|
||||||
|
"AllianceName"
|
||||||
|
FROM DATA_HUB.DWH."DimOrganisationAndSite"
|
||||||
|
WHERE "OrganisationSubType" = 'GP Practice'
|
||||||
|
AND "IsSiteActive" = 'Yes'
|
||||||
|
AND "IsSiteNorfolkAndSuffolk" = 'Yes'
|
||||||
|
AND "SiteCode" = "OrganisationCode"
|
||||||
|
)
|
||||||
|
SELECT DISTINCT
|
||||||
|
p."PracticeCode",
|
||||||
|
p."PracticeName",
|
||||||
|
p."PCNName",
|
||||||
|
p."PlaceName",
|
||||||
|
p."AllianceName",
|
||||||
|
rx."PersonKey",
|
||||||
|
rx."DateMedicationStart",
|
||||||
|
prod."ProductDescription",
|
||||||
|
prod."ProductLevel",
|
||||||
|
prod."TherapeuticMoietyName",
|
||||||
|
prod."BNFCode",
|
||||||
|
TRY_CAST(rx."Quantity" AS FLOAT) AS "Quantity",
|
||||||
|
rx."QuantityUnit",
|
||||||
|
rx."Directions",
|
||||||
|
rx."SourceSystem"
|
||||||
|
FROM REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable" rx
|
||||||
|
INNER JOIN products prod
|
||||||
|
ON rx."SNOMEDCode" = prod."ProductSnomedCode"
|
||||||
|
INNER JOIN practices p
|
||||||
|
ON rx."CurrentGeneralPractice" = p."PracticeCode"
|
||||||
|
WHERE rx."DateMedicationStart" BETWEEN $START_DATE AND $END_DATE
|
||||||
|
AND rx."PersonKey" IS NOT NULL
|
||||||
|
ORDER BY
|
||||||
|
p."PracticeName",
|
||||||
|
rx."PersonKey",
|
||||||
|
rx."DateMedicationStart";
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
Current prescribing by VTM
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
Return patient-level prescribing records for all products under one
|
||||||
|
Virtual Therapeutic Moiety (VTM).
|
||||||
|
|
||||||
|
Data source:
|
||||||
|
REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable"
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- VTM is useful when you want all products containing the same therapeutic
|
||||||
|
moiety, regardless of brand, strength, or pack.
|
||||||
|
- The practice CTE is deliberately visible. Change the geography filter
|
||||||
|
there if the report should not be Norfolk and Suffolk.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SET START_DATE = '2025-04-01';
|
||||||
|
SET END_DATE = '2026-03-31';
|
||||||
|
SET VTM_SNOMED_CODE = 'REPLACE_WITH_VTM_SNOMED_CODE';
|
||||||
|
|
||||||
|
WITH products AS (
|
||||||
|
-- Expands one VTM to all matching product SNOMED codes in the medicine dimension.
|
||||||
|
SELECT DISTINCT
|
||||||
|
"ProductSnomedCode",
|
||||||
|
"ProductDescription",
|
||||||
|
"TherapeuticMoietyName",
|
||||||
|
"BNFCode",
|
||||||
|
"BNFParagraphCode"
|
||||||
|
FROM DATA_HUB.DWH."DimMedicineAndDevice"
|
||||||
|
WHERE "TherapeuticMoietySnomedCode" = $VTM_SNOMED_CODE
|
||||||
|
),
|
||||||
|
practices AS (
|
||||||
|
-- Restricts output to active Norfolk and Suffolk parent GP practices.
|
||||||
|
SELECT DISTINCT
|
||||||
|
"OrganisationCode" AS "PracticeCode",
|
||||||
|
"OrganisationName" AS "PracticeName",
|
||||||
|
"PCNName",
|
||||||
|
"PlaceName",
|
||||||
|
"AllianceName"
|
||||||
|
FROM DATA_HUB.DWH."DimOrganisationAndSite"
|
||||||
|
WHERE "OrganisationSubType" = 'GP Practice'
|
||||||
|
AND "IsSiteActive" = 'Yes'
|
||||||
|
AND "IsSiteNorfolkAndSuffolk" = 'Yes'
|
||||||
|
AND "SiteCode" = "OrganisationCode"
|
||||||
|
)
|
||||||
|
SELECT DISTINCT
|
||||||
|
p."PracticeCode",
|
||||||
|
p."PracticeName",
|
||||||
|
p."PCNName",
|
||||||
|
p."PlaceName",
|
||||||
|
p."AllianceName",
|
||||||
|
rx."PersonKey",
|
||||||
|
rx."DateMedicationStart",
|
||||||
|
prod."ProductDescription",
|
||||||
|
prod."TherapeuticMoietyName",
|
||||||
|
prod."BNFCode",
|
||||||
|
TRY_CAST(rx."Quantity" AS FLOAT) AS "Quantity",
|
||||||
|
rx."QuantityUnit",
|
||||||
|
rx."Directions",
|
||||||
|
rx."IsRepeatPrescription",
|
||||||
|
rx."SourceSystem"
|
||||||
|
FROM REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable" rx
|
||||||
|
INNER JOIN products prod
|
||||||
|
ON rx."SNOMEDCode" = prod."ProductSnomedCode"
|
||||||
|
INNER JOIN practices p
|
||||||
|
ON rx."CurrentGeneralPractice" = p."PracticeCode"
|
||||||
|
WHERE rx."DateMedicationStart" BETWEEN $START_DATE AND $END_DATE
|
||||||
|
AND rx."PersonKey" IS NOT NULL
|
||||||
|
ORDER BY
|
||||||
|
p."PracticeName",
|
||||||
|
rx."PersonKey",
|
||||||
|
rx."DateMedicationStart";
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
Prescribing for a patient pseudonym
|
||||||
|
===================================
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
Pull a concise prescribing history for one pseudonym.
|
||||||
|
|
||||||
|
Use carefully:
|
||||||
|
- Do not commit real patient pseudonyms into shared repos.
|
||||||
|
- Keep row-level extracts out of git and shared folders unless there is a
|
||||||
|
clear information governance basis.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SET START_DATE = '2025-04-01';
|
||||||
|
SET END_DATE = '2026-03-31';
|
||||||
|
SET PATIENT_PSEUDONYM = 'REPLACE_WITH_PATIENT_PSEUDONYM';
|
||||||
|
|
||||||
|
SELECT DISTINCT
|
||||||
|
dp."PersonKey",
|
||||||
|
dp."PatientPseudonym",
|
||||||
|
gp."OrganisationName" AS "CurrentGeneralPracticeName",
|
||||||
|
rx."DateMedicationStart",
|
||||||
|
med."ProductDescription",
|
||||||
|
med."TherapeuticMoietyName",
|
||||||
|
med."BNFCode",
|
||||||
|
CAST(rx."Quantity" AS FLOAT) AS "Quantity",
|
||||||
|
rx."QuantityUnit",
|
||||||
|
rx."Directions",
|
||||||
|
rx."IsRepeatPrescription",
|
||||||
|
rx."SourceSystem"
|
||||||
|
FROM REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable" rx
|
||||||
|
INNER JOIN DATA_HUB.DWH."DimPerson" dp
|
||||||
|
ON rx."PersonKey" = dp."PersonKey"
|
||||||
|
LEFT JOIN DATA_HUB.DWH."DimMedicineAndDevice" med
|
||||||
|
ON rx."SNOMEDCode" = med."ProductSnomedCode"
|
||||||
|
LEFT JOIN DATA_HUB.DWH."DimOrganisationAndSite" gp
|
||||||
|
ON rx."CurrentGeneralPractice" = gp."OrganisationCode"
|
||||||
|
AND gp."SiteCode" = gp."OrganisationCode"
|
||||||
|
WHERE dp."PatientPseudonym" = $PATIENT_PSEUDONYM
|
||||||
|
AND rx."DateMedicationStart" BETWEEN $START_DATE AND $END_DATE
|
||||||
|
ORDER BY rx."DateMedicationStart", med."ProductDescription";
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
High-prescribing practice quintile template
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
Identify practices in the highest quintile for one or more prescribing
|
||||||
|
measures after standardising by registered population.
|
||||||
|
|
||||||
|
Based on the antidepressant high-prescribing analysis, but made generic:
|
||||||
|
- Replace medicine_products with the medicine definition you need.
|
||||||
|
- Add/remove measures in practice_counts and final_select.
|
||||||
|
- Keep the practice and base_population CTEs visible so geography and
|
||||||
|
denominator decisions are explicit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SET START_DATE = '2025-04-01';
|
||||||
|
SET END_DATE = '2026-03-31';
|
||||||
|
SET BNF_PREFIX = 'REPLACE_WITH_BNF_PREFIX';
|
||||||
|
SET REPORT_TITLE = 'REPLACE_WITH_REPORT_NAME';
|
||||||
|
|
||||||
|
WITH practices AS (
|
||||||
|
-- Practice list and hierarchy columns used in the final report.
|
||||||
|
SELECT DISTINCT
|
||||||
|
"OrganisationCode" AS "PracticeCode",
|
||||||
|
"OrganisationName" AS "PracticeName",
|
||||||
|
"PCNName",
|
||||||
|
"PlaceName",
|
||||||
|
"AllianceName",
|
||||||
|
"INTName",
|
||||||
|
"RegisteredPopulation" AS "OrganisationRegisteredPopulation",
|
||||||
|
"RegisteredPopulationSnapshotDate" AS "OrganisationPopulationSnapshotDate"
|
||||||
|
FROM DATA_HUB.DWH."DimOrganisationAndSite"
|
||||||
|
WHERE "OrganisationSubType" = 'GP Practice'
|
||||||
|
AND "IsSiteActive" = 'Yes'
|
||||||
|
AND "IsSiteNorfolkAndSuffolk" = 'Yes'
|
||||||
|
AND "SiteCode" = "OrganisationCode"
|
||||||
|
),
|
||||||
|
base_population AS (
|
||||||
|
-- Counted denominator: active, known, living patients currently registered to the practice.
|
||||||
|
SELECT
|
||||||
|
p."PracticeCode",
|
||||||
|
dp."PersonKey",
|
||||||
|
dp."PatientPseudonym",
|
||||||
|
dp."CurrentAge",
|
||||||
|
dp."BAME"
|
||||||
|
FROM DATA_HUB.DWH."DimPerson" dp
|
||||||
|
INNER JOIN practices p
|
||||||
|
ON dp."CurrentGeneralPractice" = p."PracticeCode"
|
||||||
|
WHERE dp."RecordStatus" = 'Active'
|
||||||
|
AND dp."PersonStatus" = 'Known'
|
||||||
|
AND dp."CurrentGeneralPractice" IS NOT NULL
|
||||||
|
AND dp."CurrentGeneralPractice" <> '*'
|
||||||
|
AND dp."YearMonthDeath" IS NULL
|
||||||
|
),
|
||||||
|
practice_population AS (
|
||||||
|
SELECT
|
||||||
|
"PracticeCode",
|
||||||
|
COUNT(DISTINCT "PersonKey") AS "RegisteredPatients"
|
||||||
|
FROM base_population
|
||||||
|
GROUP BY "PracticeCode"
|
||||||
|
),
|
||||||
|
medicine_products AS (
|
||||||
|
-- Replace this with a VTM/VMP/explicit-code definition if BNF is too broad.
|
||||||
|
SELECT DISTINCT
|
||||||
|
"ProductSnomedCode"
|
||||||
|
FROM DATA_HUB.DWH."DimMedicineAndDevice"
|
||||||
|
WHERE "ProductSnomedCode" IS NOT NULL
|
||||||
|
AND "BNFCode" LIKE $BNF_PREFIX || '%'
|
||||||
|
),
|
||||||
|
medicine_patients AS (
|
||||||
|
-- Patient-level numerator cohort before practice aggregation.
|
||||||
|
SELECT DISTINCT
|
||||||
|
bp."PracticeCode",
|
||||||
|
bp."PersonKey",
|
||||||
|
bp."PatientPseudonym",
|
||||||
|
bp."CurrentAge",
|
||||||
|
bp."BAME"
|
||||||
|
FROM REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable" rx
|
||||||
|
INNER JOIN base_population bp
|
||||||
|
ON rx."PersonKey" = bp."PersonKey"
|
||||||
|
INNER JOIN medicine_products mp
|
||||||
|
ON rx."SNOMEDCode" = mp."ProductSnomedCode"
|
||||||
|
WHERE rx."DateMedicationStart" BETWEEN $START_DATE AND $END_DATE
|
||||||
|
AND rx."PersonKey" IS NOT NULL
|
||||||
|
),
|
||||||
|
practice_counts AS (
|
||||||
|
-- Add or remove measure columns here, then mirror them in final_select.
|
||||||
|
SELECT
|
||||||
|
"PracticeCode",
|
||||||
|
COUNT(DISTINCT "PersonKey") AS "PatientsOnMedicine",
|
||||||
|
COUNT(DISTINCT CASE WHEN "CurrentAge" > 65 THEN "PersonKey" END) AS "PatientsOnMedicineAgedOver65",
|
||||||
|
COUNT(DISTINCT CASE WHEN "CurrentAge" > 85 THEN "PersonKey" END) AS "PatientsOnMedicineAgedOver85",
|
||||||
|
COUNT(DISTINCT CASE WHEN "BAME" = 'BAME' THEN "PersonKey" END) AS "PatientsOnMedicineEthnicMinority"
|
||||||
|
FROM medicine_patients
|
||||||
|
GROUP BY "PracticeCode"
|
||||||
|
),
|
||||||
|
final_select AS (
|
||||||
|
-- Per-1000 rates use the counted patient denominator from base_population.
|
||||||
|
SELECT
|
||||||
|
$REPORT_TITLE AS "ReportTitle",
|
||||||
|
$START_DATE::DATE AS "PeriodStartDate",
|
||||||
|
$END_DATE::DATE AS "PeriodEndDate",
|
||||||
|
p."PracticeCode",
|
||||||
|
p."PracticeName",
|
||||||
|
p."PCNName",
|
||||||
|
p."PlaceName",
|
||||||
|
p."AllianceName",
|
||||||
|
p."INTName",
|
||||||
|
pop."RegisteredPatients",
|
||||||
|
p."OrganisationRegisteredPopulation",
|
||||||
|
p."OrganisationPopulationSnapshotDate",
|
||||||
|
COALESCE(pc."PatientsOnMedicine", 0) AS "PatientsOnMedicine",
|
||||||
|
ROUND(1000.0 * COALESCE(pc."PatientsOnMedicine", 0) / NULLIF(pop."RegisteredPatients", 0), 2) AS "PatientsOnMedicinePer1000",
|
||||||
|
COALESCE(pc."PatientsOnMedicineAgedOver65", 0) AS "PatientsOnMedicineAgedOver65",
|
||||||
|
ROUND(1000.0 * COALESCE(pc."PatientsOnMedicineAgedOver65", 0) / NULLIF(pop."RegisteredPatients", 0), 2) AS "PatientsOnMedicineAgedOver65Per1000",
|
||||||
|
COALESCE(pc."PatientsOnMedicineAgedOver85", 0) AS "PatientsOnMedicineAgedOver85",
|
||||||
|
ROUND(1000.0 * COALESCE(pc."PatientsOnMedicineAgedOver85", 0) / NULLIF(pop."RegisteredPatients", 0), 2) AS "PatientsOnMedicineAgedOver85Per1000",
|
||||||
|
COALESCE(pc."PatientsOnMedicineEthnicMinority", 0) AS "PatientsOnMedicineEthnicMinority",
|
||||||
|
ROUND(1000.0 * COALESCE(pc."PatientsOnMedicineEthnicMinority", 0) / NULLIF(pop."RegisteredPatients", 0), 2) AS "PatientsOnMedicineEthnicMinorityPer1000"
|
||||||
|
FROM practices p
|
||||||
|
INNER JOIN practice_population pop
|
||||||
|
ON p."PracticeCode" = pop."PracticeCode"
|
||||||
|
LEFT JOIN practice_counts pc
|
||||||
|
ON p."PracticeCode" = pc."PracticeCode"
|
||||||
|
),
|
||||||
|
with_quintiles AS (
|
||||||
|
-- Quintile 5 is the highest rate in each measure.
|
||||||
|
SELECT
|
||||||
|
"ReportTitle",
|
||||||
|
"PeriodStartDate",
|
||||||
|
"PeriodEndDate",
|
||||||
|
"PracticeCode",
|
||||||
|
"PracticeName",
|
||||||
|
"PCNName",
|
||||||
|
"PlaceName",
|
||||||
|
"AllianceName",
|
||||||
|
"INTName",
|
||||||
|
"RegisteredPatients",
|
||||||
|
"OrganisationRegisteredPopulation",
|
||||||
|
"OrganisationPopulationSnapshotDate",
|
||||||
|
"PatientsOnMedicine",
|
||||||
|
"PatientsOnMedicinePer1000",
|
||||||
|
"PatientsOnMedicineAgedOver65",
|
||||||
|
"PatientsOnMedicineAgedOver65Per1000",
|
||||||
|
"PatientsOnMedicineAgedOver85",
|
||||||
|
"PatientsOnMedicineAgedOver85Per1000",
|
||||||
|
"PatientsOnMedicineEthnicMinority",
|
||||||
|
"PatientsOnMedicineEthnicMinorityPer1000",
|
||||||
|
NTILE(5) OVER (ORDER BY "PatientsOnMedicinePer1000") AS "PatientsOnMedicineQuintile",
|
||||||
|
NTILE(5) OVER (ORDER BY "PatientsOnMedicineAgedOver65Per1000") AS "AgedOver65Quintile",
|
||||||
|
NTILE(5) OVER (ORDER BY "PatientsOnMedicineAgedOver85Per1000") AS "AgedOver85Quintile",
|
||||||
|
NTILE(5) OVER (ORDER BY "PatientsOnMedicineEthnicMinorityPer1000") AS "EthnicMinorityQuintile"
|
||||||
|
FROM final_select
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
"ReportTitle",
|
||||||
|
"PeriodStartDate",
|
||||||
|
"PeriodEndDate",
|
||||||
|
"PracticeCode",
|
||||||
|
"PracticeName",
|
||||||
|
"PCNName",
|
||||||
|
"PlaceName",
|
||||||
|
"AllianceName",
|
||||||
|
"INTName",
|
||||||
|
"RegisteredPatients",
|
||||||
|
"OrganisationRegisteredPopulation",
|
||||||
|
"OrganisationPopulationSnapshotDate",
|
||||||
|
"PatientsOnMedicine",
|
||||||
|
"PatientsOnMedicinePer1000",
|
||||||
|
"PatientsOnMedicineQuintile",
|
||||||
|
"PatientsOnMedicineAgedOver65",
|
||||||
|
"PatientsOnMedicineAgedOver65Per1000",
|
||||||
|
"AgedOver65Quintile",
|
||||||
|
"PatientsOnMedicineAgedOver85",
|
||||||
|
"PatientsOnMedicineAgedOver85Per1000",
|
||||||
|
"AgedOver85Quintile",
|
||||||
|
"PatientsOnMedicineEthnicMinority",
|
||||||
|
"PatientsOnMedicineEthnicMinorityPer1000",
|
||||||
|
"EthnicMinorityQuintile"
|
||||||
|
FROM with_quintiles
|
||||||
|
WHERE "PatientsOnMedicineQuintile" = 5
|
||||||
|
OR "AgedOver65Quintile" = 5
|
||||||
|
OR "AgedOver85Quintile" = 5
|
||||||
|
OR "EthnicMinorityQuintile" = 5
|
||||||
|
ORDER BY
|
||||||
|
"PatientsOnMedicinePer1000" DESC,
|
||||||
|
"PracticeName";
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
Practice-level prescribing summary by BNF prefix
|
||||||
|
================================================
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
Produce a compact practice/month summary for prescribing under a BNF prefix.
|
||||||
|
|
||||||
|
Good first query for:
|
||||||
|
- "How much prescribing activity is there for this BNF section?"
|
||||||
|
- "Which practices have the most patients/items/cost for this medicine area?"
|
||||||
|
- A simple numerator for charts or practice packs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SET START_DATE = '2025-04-01';
|
||||||
|
SET END_DATE = '2026-03-31';
|
||||||
|
SET BNF_PREFIX = '0403';
|
||||||
|
|
||||||
|
WITH practices AS (
|
||||||
|
-- Default reporting geography: active Norfolk and Suffolk parent GP practices.
|
||||||
|
SELECT DISTINCT
|
||||||
|
"OrganisationCode" AS "PracticeCode",
|
||||||
|
"OrganisationName" AS "PracticeName",
|
||||||
|
"PCNName",
|
||||||
|
"PlaceName",
|
||||||
|
"AllianceName"
|
||||||
|
FROM DATA_HUB.DWH."DimOrganisationAndSite"
|
||||||
|
WHERE "OrganisationSubType" = 'GP Practice'
|
||||||
|
AND "IsSiteActive" = 'Yes'
|
||||||
|
AND "IsSiteNorfolkAndSuffolk" = 'Yes'
|
||||||
|
AND "SiteCode" = "OrganisationCode"
|
||||||
|
),
|
||||||
|
prescribing AS (
|
||||||
|
-- Aggregate after joining to the medicine dimension so BNF matching is dm+d-backed.
|
||||||
|
SELECT
|
||||||
|
DATE_TRUNC('MONTH', rx."DateMedicationStart")::DATE AS "MonthStartDate",
|
||||||
|
p."PracticeCode",
|
||||||
|
p."PracticeName",
|
||||||
|
p."PCNName",
|
||||||
|
p."PlaceName",
|
||||||
|
p."AllianceName",
|
||||||
|
med."BNFParagraphCode",
|
||||||
|
COUNT(DISTINCT rx."PersonKey") AS "Patients",
|
||||||
|
COUNT(*) AS "PrescriptionRows",
|
||||||
|
SUM(TRY_CAST(rx."Quantity" AS FLOAT)) AS "TotalQuantity",
|
||||||
|
SUM(rx."EstPrice") AS "EstimatedCost"
|
||||||
|
FROM REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable" rx
|
||||||
|
INNER JOIN DATA_HUB.DWH."DimMedicineAndDevice" med
|
||||||
|
ON rx."SNOMEDCode" = med."ProductSnomedCode"
|
||||||
|
AND med."BNFCode" LIKE $BNF_PREFIX || '%'
|
||||||
|
INNER JOIN practices p
|
||||||
|
ON rx."CurrentGeneralPractice" = p."PracticeCode"
|
||||||
|
WHERE rx."DateMedicationStart" BETWEEN $START_DATE AND $END_DATE
|
||||||
|
AND rx."PersonKey" IS NOT NULL
|
||||||
|
GROUP BY
|
||||||
|
DATE_TRUNC('MONTH', rx."DateMedicationStart")::DATE,
|
||||||
|
p."PracticeCode",
|
||||||
|
p."PracticeName",
|
||||||
|
p."PCNName",
|
||||||
|
p."PlaceName",
|
||||||
|
p."AllianceName",
|
||||||
|
med."BNFParagraphCode"
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
"MonthStartDate",
|
||||||
|
"PracticeCode",
|
||||||
|
"PracticeName",
|
||||||
|
"PCNName",
|
||||||
|
"PlaceName",
|
||||||
|
"AllianceName",
|
||||||
|
"BNFParagraphCode",
|
||||||
|
"Patients",
|
||||||
|
"PrescriptionRows",
|
||||||
|
"TotalQuantity",
|
||||||
|
"EstimatedCost"
|
||||||
|
FROM prescribing
|
||||||
|
ORDER BY
|
||||||
|
"MonthStartDate",
|
||||||
|
"PracticeName",
|
||||||
|
"BNFParagraphCode";
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
Prescribing spend by patient template
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
Rank patients by estimated prescribing cost over a selected period and
|
||||||
|
medicine definition.
|
||||||
|
|
||||||
|
Use this when looking for high-cost patients or checking the shape of cost
|
||||||
|
concentration before doing deeper clinical review.
|
||||||
|
|
||||||
|
Default source is the maintained unified prescribing table, which already
|
||||||
|
includes parsed quantity and estimated price. If that table is unavailable
|
||||||
|
or needs rebuilding, see 06_advanced_methods/product_price_and_quantity_parsing_template.sql.
|
||||||
|
|
||||||
|
Keep at least one medicine filter set. Leaving BNF, VTM, and VMP filters all
|
||||||
|
NULL can scan all prescribing and is usually not a useful starting point.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SET START_DATE = '2025-04-01';
|
||||||
|
SET END_DATE = '2026-03-31';
|
||||||
|
SET BNF_PREFIX = '0403';
|
||||||
|
SET VTM_SNOMED_CODE = NULL;
|
||||||
|
SET VMP_SNOMED_CODE = NULL;
|
||||||
|
SET TOP_N = 100;
|
||||||
|
|
||||||
|
WITH products AS (
|
||||||
|
-- Keep at least one of the filters below populated so the product set is intentional.
|
||||||
|
SELECT DISTINCT
|
||||||
|
"ProductSnomedCode",
|
||||||
|
"ProductDescription",
|
||||||
|
"TherapeuticMoietyName",
|
||||||
|
"BNFCode",
|
||||||
|
"BNFParagraphCode"
|
||||||
|
FROM DATA_HUB.DWH."DimMedicineAndDevice"
|
||||||
|
WHERE ($BNF_PREFIX IS NOT NULL AND "BNFCode" LIKE $BNF_PREFIX || '%')
|
||||||
|
OR ($VTM_SNOMED_CODE IS NOT NULL AND "TherapeuticMoietySnomedCode" = $VTM_SNOMED_CODE)
|
||||||
|
OR ($VMP_SNOMED_CODE IS NOT NULL AND "MedicinalLatestSnomedCode" = $VMP_SNOMED_CODE)
|
||||||
|
),
|
||||||
|
patient_costs AS (
|
||||||
|
-- Aggregate first at patient/practice level so ranking is not inflated by joins.
|
||||||
|
SELECT
|
||||||
|
rx."PersonKey",
|
||||||
|
rx."CurrentGeneralPractice" AS "PracticeCode",
|
||||||
|
COUNT(*) AS "PrescriptionRows",
|
||||||
|
COUNT(DISTINCT prod."ProductSnomedCode") AS "DistinctProducts",
|
||||||
|
SUM(COALESCE(rx."EstPrice", 0)) AS "EstimatedCost"
|
||||||
|
FROM REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable" rx
|
||||||
|
INNER JOIN products prod
|
||||||
|
ON rx."SNOMEDCode" = prod."ProductSnomedCode"
|
||||||
|
WHERE rx."DateMedicationStart" BETWEEN $START_DATE AND $END_DATE
|
||||||
|
AND rx."PersonKey" IS NOT NULL
|
||||||
|
GROUP BY rx."PersonKey", rx."CurrentGeneralPractice"
|
||||||
|
),
|
||||||
|
practice_lookup AS (
|
||||||
|
-- De-duplicated practice labels prevent site-level duplicates in the ranking output.
|
||||||
|
SELECT
|
||||||
|
"OrganisationCode" AS "PracticeCode",
|
||||||
|
MIN("OrganisationName") AS "PracticeName",
|
||||||
|
MIN("PCNName") AS "PCNName",
|
||||||
|
MIN("PlaceName") AS "PlaceName",
|
||||||
|
MIN("AllianceName") AS "AllianceName"
|
||||||
|
FROM DATA_HUB.DWH."DimOrganisationAndSite"
|
||||||
|
WHERE "OrganisationSubType" = 'GP Practice'
|
||||||
|
AND "IsSiteActive" = 'Yes'
|
||||||
|
AND "IsSiteNorfolkAndSuffolk" = 'Yes'
|
||||||
|
AND "SiteCode" = "OrganisationCode"
|
||||||
|
GROUP BY "OrganisationCode"
|
||||||
|
),
|
||||||
|
ranked AS (
|
||||||
|
SELECT
|
||||||
|
ROW_NUMBER() OVER (ORDER BY pc."EstimatedCost" DESC NULLS LAST) AS "Rank",
|
||||||
|
gp."PracticeName",
|
||||||
|
gp."PCNName",
|
||||||
|
gp."PlaceName",
|
||||||
|
gp."AllianceName",
|
||||||
|
pc."PersonKey",
|
||||||
|
pc."PracticeCode",
|
||||||
|
pc."PrescriptionRows",
|
||||||
|
pc."DistinctProducts",
|
||||||
|
pc."EstimatedCost"
|
||||||
|
FROM patient_costs pc
|
||||||
|
INNER JOIN practice_lookup gp
|
||||||
|
ON pc."PracticeCode" = gp."PracticeCode"
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
"Rank",
|
||||||
|
"PracticeName",
|
||||||
|
"PCNName",
|
||||||
|
"PlaceName",
|
||||||
|
"AllianceName",
|
||||||
|
"PersonKey",
|
||||||
|
"PracticeCode",
|
||||||
|
"PrescriptionRows",
|
||||||
|
"DistinctProducts",
|
||||||
|
"EstimatedCost"
|
||||||
|
FROM ranked
|
||||||
|
WHERE "Rank" <= $TOP_N
|
||||||
|
ORDER BY "Rank";
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
Clinical coding cluster lookup
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
List SNOMED codes attached to maintained clinical coding clusters.
|
||||||
|
|
||||||
|
Use maintained clusters where possible instead of free-text matching on
|
||||||
|
SNOMED descriptions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SET CLUSTER_ID = 'DEPR_COD';
|
||||||
|
|
||||||
|
SELECT DISTINCT
|
||||||
|
ccs."Cluster_ID",
|
||||||
|
ccs."SNOMEDCode",
|
||||||
|
ccs."SNOMEDDescription"
|
||||||
|
FROM DATA_HUB.PHM."ClinicalCodingClusterSnomedCodes" ccs
|
||||||
|
WHERE ccs."Cluster_ID" = $CLUSTER_ID
|
||||||
|
ORDER BY ccs."SNOMEDDescription", ccs."SNOMEDCode";
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
Monthly clinical event count by practice
|
||||||
|
========================================
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
Count distinct patients with a clinical code by month and practice, while
|
||||||
|
returning zero rows for months/practices with no events.
|
||||||
|
|
||||||
|
Good for:
|
||||||
|
- SMR-type activity counts.
|
||||||
|
- Condition or review-code monitoring.
|
||||||
|
- Building a complete month/practice grid for charts.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SET START_MONTH = '2024-07-01';
|
||||||
|
SET END_MONTH = CURRENT_DATE();
|
||||||
|
SET CLUSTER_ID = 'REPLACE_WITH_CLUSTER_ID';
|
||||||
|
|
||||||
|
WITH clinical_codes AS (
|
||||||
|
-- Maintained cluster definitions avoid fragile free-text SNOMED searches.
|
||||||
|
SELECT DISTINCT "SNOMEDCode"
|
||||||
|
FROM DATA_HUB.PHM."ClinicalCodingClusterSnomedCodes"
|
||||||
|
WHERE "Cluster_ID" = $CLUSTER_ID
|
||||||
|
),
|
||||||
|
practices AS (
|
||||||
|
-- Default to active Norfolk and Suffolk parent GP practices.
|
||||||
|
SELECT DISTINCT
|
||||||
|
"OrganisationCode" AS "PracticeCode",
|
||||||
|
"OrganisationName" AS "PracticeName",
|
||||||
|
"PCNName",
|
||||||
|
"PlaceName",
|
||||||
|
"AllianceName"
|
||||||
|
FROM DATA_HUB.DWH."DimOrganisationAndSite"
|
||||||
|
WHERE "IsSiteNorfolkAndSuffolk" = 'Yes'
|
||||||
|
AND "OrganisationSubType" = 'GP Practice'
|
||||||
|
AND "IsSiteActive" = 'Yes'
|
||||||
|
AND "SiteCode" = "OrganisationCode"
|
||||||
|
),
|
||||||
|
base_population AS (
|
||||||
|
-- Keeps the denominator/cohort rule visible before events are counted.
|
||||||
|
SELECT
|
||||||
|
p."PracticeCode",
|
||||||
|
dp."PersonKey",
|
||||||
|
dp."PatientPseudonym"
|
||||||
|
FROM DATA_HUB.DWH."DimPerson" dp
|
||||||
|
INNER JOIN practices p
|
||||||
|
ON dp."CurrentGeneralPractice" = p."PracticeCode"
|
||||||
|
WHERE dp."RecordStatus" = 'Active'
|
||||||
|
AND dp."PersonStatus" = 'Known'
|
||||||
|
AND dp."YearMonthDeath" IS NULL
|
||||||
|
),
|
||||||
|
month_numbers AS (
|
||||||
|
-- Generates up to 120 monthly rows; extend if a longer history is needed.
|
||||||
|
SELECT ROW_NUMBER() OVER (ORDER BY SEQ4()) - 1 AS n
|
||||||
|
FROM TABLE(GENERATOR(ROWCOUNT => 120))
|
||||||
|
),
|
||||||
|
months AS (
|
||||||
|
SELECT DATE_TRUNC('MONTH', DATEADD(MONTH, n, $START_MONTH::DATE))::DATE AS "MonthStartDate"
|
||||||
|
FROM month_numbers
|
||||||
|
WHERE DATEADD(MONTH, n, $START_MONTH::DATE) <= $END_MONTH::DATE
|
||||||
|
),
|
||||||
|
practice_month_grid AS (
|
||||||
|
SELECT
|
||||||
|
p."PracticeCode",
|
||||||
|
p."PracticeName",
|
||||||
|
p."PCNName",
|
||||||
|
p."PlaceName",
|
||||||
|
p."AllianceName",
|
||||||
|
m."MonthStartDate"
|
||||||
|
FROM practices p
|
||||||
|
CROSS JOIN months m
|
||||||
|
),
|
||||||
|
events AS (
|
||||||
|
SELECT
|
||||||
|
bp."PracticeCode",
|
||||||
|
DATE_TRUNC('MONTH', cc."EventDateTime")::DATE AS "MonthStartDate",
|
||||||
|
COUNT(DISTINCT bp."PersonKey") AS "PatientsWithEvent"
|
||||||
|
FROM DATA_HUB.PHM."PrimaryCareClinicalCoding" cc
|
||||||
|
INNER JOIN clinical_codes c
|
||||||
|
ON cc."SNOMEDCode" = c."SNOMEDCode"
|
||||||
|
INNER JOIN base_population bp
|
||||||
|
ON cc."PatientPseudonym" = bp."PatientPseudonym"
|
||||||
|
WHERE cc."EventDateTime"::DATE BETWEEN $START_MONTH::DATE AND $END_MONTH::DATE
|
||||||
|
GROUP BY
|
||||||
|
bp."PracticeCode",
|
||||||
|
DATE_TRUNC('MONTH', cc."EventDateTime")::DATE
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
pmg."PracticeCode",
|
||||||
|
pmg."PracticeName",
|
||||||
|
pmg."PCNName",
|
||||||
|
pmg."PlaceName",
|
||||||
|
pmg."AllianceName",
|
||||||
|
pmg."MonthStartDate",
|
||||||
|
COALESCE(e."PatientsWithEvent", 0) AS "PatientsWithEvent"
|
||||||
|
FROM practice_month_grid pmg
|
||||||
|
LEFT JOIN events e
|
||||||
|
ON pmg."PracticeCode" = e."PracticeCode"
|
||||||
|
AND pmg."MonthStartDate" = e."MonthStartDate"
|
||||||
|
ORDER BY
|
||||||
|
pmg."PracticeName",
|
||||||
|
pmg."MonthStartDate";
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
Cohort from prescribing plus clinical coding
|
||||||
|
============================================
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
Build a patient cohort where a medicine exposure is combined with a clinical
|
||||||
|
coding condition, for example patients prescribed a medicine who also have
|
||||||
|
a relevant diagnosis code in a lookback window.
|
||||||
|
|
||||||
|
Replace:
|
||||||
|
- BNF_PREFIX or use a VTM/VMP product CTE.
|
||||||
|
- CLUSTER_ID with the maintained cluster needed for the clinical condition.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SET PRESCRIBING_START_DATE = '2025-04-01';
|
||||||
|
SET PRESCRIBING_END_DATE = '2026-03-31';
|
||||||
|
SET CLINICAL_LOOKBACK_YEARS = -2;
|
||||||
|
SET BNF_PREFIX = '0403';
|
||||||
|
SET CLUSTER_ID = 'DEPR_COD';
|
||||||
|
|
||||||
|
WITH practices AS (
|
||||||
|
-- Default reporting geography: active Norfolk and Suffolk parent GP practices.
|
||||||
|
SELECT DISTINCT
|
||||||
|
"OrganisationCode" AS "PracticeCode",
|
||||||
|
"OrganisationName" AS "PracticeName",
|
||||||
|
"PCNName",
|
||||||
|
"PlaceName",
|
||||||
|
"AllianceName"
|
||||||
|
FROM DATA_HUB.DWH."DimOrganisationAndSite"
|
||||||
|
WHERE "OrganisationSubType" = 'GP Practice'
|
||||||
|
AND "IsSiteActive" = 'Yes'
|
||||||
|
AND "IsSiteNorfolkAndSuffolk" = 'Yes'
|
||||||
|
AND "SiteCode" = "OrganisationCode"
|
||||||
|
),
|
||||||
|
base_population AS (
|
||||||
|
-- Active, known, living patients registered to the selected practices.
|
||||||
|
SELECT
|
||||||
|
p."PracticeCode",
|
||||||
|
p."PracticeName",
|
||||||
|
p."PCNName",
|
||||||
|
p."PlaceName",
|
||||||
|
p."AllianceName",
|
||||||
|
dp."PersonKey",
|
||||||
|
dp."PatientPseudonym",
|
||||||
|
dp."CurrentAge"
|
||||||
|
FROM DATA_HUB.DWH."DimPerson" dp
|
||||||
|
INNER JOIN practices p
|
||||||
|
ON dp."CurrentGeneralPractice" = p."PracticeCode"
|
||||||
|
WHERE dp."RecordStatus" = 'Active'
|
||||||
|
AND dp."PersonStatus" = 'Known'
|
||||||
|
AND dp."YearMonthDeath" IS NULL
|
||||||
|
),
|
||||||
|
medicine_products AS (
|
||||||
|
-- Replace with VTM/VMP/explicit product logic if BNF prefix is too broad.
|
||||||
|
SELECT DISTINCT "ProductSnomedCode"
|
||||||
|
FROM DATA_HUB.DWH."DimMedicineAndDevice"
|
||||||
|
WHERE "BNFCode" LIKE $BNF_PREFIX || '%'
|
||||||
|
),
|
||||||
|
clinical_codes AS (
|
||||||
|
-- Maintained cluster definitions avoid fragile free-text SNOMED searches.
|
||||||
|
SELECT DISTINCT "SNOMEDCode"
|
||||||
|
FROM DATA_HUB.PHM."ClinicalCodingClusterSnomedCodes"
|
||||||
|
WHERE "Cluster_ID" = $CLUSTER_ID
|
||||||
|
),
|
||||||
|
prescribed_patients AS (
|
||||||
|
-- Medicine-exposed patients in the prescribing window.
|
||||||
|
SELECT DISTINCT
|
||||||
|
bp."PracticeCode",
|
||||||
|
bp."PracticeName",
|
||||||
|
bp."PCNName",
|
||||||
|
bp."PlaceName",
|
||||||
|
bp."AllianceName",
|
||||||
|
bp."PersonKey",
|
||||||
|
bp."PatientPseudonym",
|
||||||
|
bp."CurrentAge"
|
||||||
|
FROM REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable" rx
|
||||||
|
INNER JOIN base_population bp
|
||||||
|
ON rx."PersonKey" = bp."PersonKey"
|
||||||
|
INNER JOIN medicine_products mp
|
||||||
|
ON rx."SNOMEDCode" = mp."ProductSnomedCode"
|
||||||
|
WHERE rx."DateMedicationStart" BETWEEN $PRESCRIBING_START_DATE AND $PRESCRIBING_END_DATE
|
||||||
|
),
|
||||||
|
coded_patients AS (
|
||||||
|
-- Look back from the end of the prescribing period for matching clinical events.
|
||||||
|
SELECT DISTINCT
|
||||||
|
pp."PersonKey",
|
||||||
|
MIN(cc."EventDateTime"::DATE) AS "FirstMatchingClinicalEventDate",
|
||||||
|
MAX(cc."EventDateTime"::DATE) AS "LatestMatchingClinicalEventDate"
|
||||||
|
FROM prescribed_patients pp
|
||||||
|
INNER JOIN DATA_HUB.PHM."PrimaryCareClinicalCoding" cc
|
||||||
|
ON pp."PatientPseudonym" = cc."PatientPseudonym"
|
||||||
|
INNER JOIN clinical_codes c
|
||||||
|
ON cc."SNOMEDCode" = c."SNOMEDCode"
|
||||||
|
WHERE cc."EventDateTime"::DATE BETWEEN DATEADD('YEAR', $CLINICAL_LOOKBACK_YEARS, $PRESCRIBING_END_DATE::DATE)
|
||||||
|
AND $PRESCRIBING_END_DATE::DATE
|
||||||
|
GROUP BY pp."PersonKey"
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
pp."PracticeCode",
|
||||||
|
pp."PracticeName",
|
||||||
|
pp."PCNName",
|
||||||
|
pp."PlaceName",
|
||||||
|
pp."AllianceName",
|
||||||
|
pp."PersonKey",
|
||||||
|
pp."CurrentAge",
|
||||||
|
CASE WHEN cp."PersonKey" IS NOT NULL THEN 1 ELSE 0 END AS "HasClinicalCodeInLookback",
|
||||||
|
cp."FirstMatchingClinicalEventDate",
|
||||||
|
cp."LatestMatchingClinicalEventDate"
|
||||||
|
FROM prescribed_patients pp
|
||||||
|
LEFT JOIN coded_patients cp
|
||||||
|
ON pp."PersonKey" = cp."PersonKey"
|
||||||
|
ORDER BY
|
||||||
|
pp."PracticeName",
|
||||||
|
pp."PersonKey";
|
||||||
@@ -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";
|
||||||
@@ -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";
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
Human-readable prescribing detail
|
||||||
|
=================================
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
Return row-level prescribing detail with medicine and organisation codes
|
||||||
|
replaced by useful names.
|
||||||
|
|
||||||
|
Use this after an aggregate measure finds a cohort that needs checking.
|
||||||
|
Keep the output explicit. Avoid SELECT rx.* in shared audit extracts.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SET START_DATE = '2025-04-01';
|
||||||
|
SET END_DATE = '2026-03-31';
|
||||||
|
SET BNF_PREFIX = '0501';
|
||||||
|
|
||||||
|
WITH practices AS (
|
||||||
|
-- Default reporting geography: active Norfolk and Suffolk parent GP practices.
|
||||||
|
SELECT
|
||||||
|
"OrganisationCode",
|
||||||
|
MIN("OrganisationName") AS "OrganisationName",
|
||||||
|
MIN("PCNName") AS "PCNName",
|
||||||
|
MIN("PlaceName") AS "PlaceName",
|
||||||
|
MIN("AllianceName") AS "AllianceName"
|
||||||
|
FROM DATA_HUB.DWH."DimOrganisationAndSite"
|
||||||
|
WHERE "OrganisationSubType" = 'GP Practice'
|
||||||
|
AND "IsSiteActive" = 'Yes'
|
||||||
|
AND "IsSiteNorfolkAndSuffolk" = 'Yes'
|
||||||
|
AND "SiteCode" = "OrganisationCode"
|
||||||
|
GROUP BY "OrganisationCode"
|
||||||
|
),
|
||||||
|
organisations AS (
|
||||||
|
-- Broader organisation lookup for prescribers/providers that are not GP practices.
|
||||||
|
SELECT
|
||||||
|
"OrganisationCode",
|
||||||
|
MIN("OrganisationName") AS "OrganisationName"
|
||||||
|
FROM DATA_HUB.DWH."DimOrganisationAndSite"
|
||||||
|
GROUP BY "OrganisationCode"
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
prescribing_org."OrganisationName" AS "PrescribingOrganisationName",
|
||||||
|
registered_gp."OrganisationName" AS "RegisteredPracticeName",
|
||||||
|
registered_gp."PCNName",
|
||||||
|
registered_gp."PlaceName",
|
||||||
|
registered_gp."AllianceName",
|
||||||
|
rx."PersonKey",
|
||||||
|
med."ProductDescription" AS "ProductName",
|
||||||
|
med."TherapeuticMoietyName",
|
||||||
|
med."BNFCode",
|
||||||
|
rx."DateMedicationStart",
|
||||||
|
rx."Name" AS "SourceProductName",
|
||||||
|
rx."Directions",
|
||||||
|
rx."Quantity",
|
||||||
|
rx."QuantityUnit",
|
||||||
|
rx."IsRepeatPrescription",
|
||||||
|
rx."MedicinalControlledDrugStatus",
|
||||||
|
rx."EstPrice",
|
||||||
|
rx."SourceSystem",
|
||||||
|
rx."DataHubCreatedDate",
|
||||||
|
rx."SourceRowKey"
|
||||||
|
FROM REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable" rx
|
||||||
|
INNER JOIN DATA_HUB.DWH."DimMedicineAndDevice" med
|
||||||
|
ON med."ProductSnomedCode" = rx."SNOMEDCode"
|
||||||
|
AND med."BNFCode" LIKE $BNF_PREFIX || '%'
|
||||||
|
INNER JOIN practices registered_gp
|
||||||
|
ON registered_gp."OrganisationCode" = rx."CurrentGeneralPractice"
|
||||||
|
LEFT JOIN organisations prescribing_org
|
||||||
|
ON prescribing_org."OrganisationCode" = rx."OrgCode"
|
||||||
|
WHERE rx."DateMedicationStart" BETWEEN $START_DATE AND $END_DATE
|
||||||
|
AND rx."PersonKey" IS NOT NULL
|
||||||
|
ORDER BY
|
||||||
|
registered_gp."OrganisationName",
|
||||||
|
rx."PersonKey",
|
||||||
|
rx."DateMedicationStart";
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
Product price and quantity parsing template
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
Reusable reference CTEs for estimating cost when working from raw EMIS or
|
||||||
|
TPP prescribing extracts rather than the maintained unified prescribing
|
||||||
|
table.
|
||||||
|
|
||||||
|
Prefer REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable"
|
||||||
|
where possible. Use this file when you need to understand or rebuild the
|
||||||
|
price/quantity logic.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SET START_DATE = '2025-04-01';
|
||||||
|
SET END_DATE = '2026-03-31';
|
||||||
|
|
||||||
|
WITH pack_level_data AS (
|
||||||
|
-- Pack-level records carry the most direct tariff/indicative unit prices.
|
||||||
|
SELECT
|
||||||
|
"ProductSnomedCode",
|
||||||
|
"ParentPresentationSnomedCode",
|
||||||
|
"MedicinalLatestSnomedCode",
|
||||||
|
"ProductLevel",
|
||||||
|
"PackUnitDescription",
|
||||||
|
COALESCE(
|
||||||
|
"DrugTariffPricePerUnit",
|
||||||
|
"IndicativePricePerUnit",
|
||||||
|
CASE WHEN "AnnualQuantity" > 0 THEN "AnnualCost" / "AnnualQuantity" END
|
||||||
|
) / CASE WHEN LOWER("PackUnitDescription") IN ('litre', 'litres') THEN 1000 ELSE 1 END AS "PricePerUnit"
|
||||||
|
FROM DATA_HUB.DWH."DimMedicineAndDevice"
|
||||||
|
WHERE "ProductLevel" IN ('VMPP', 'AMPP')
|
||||||
|
),
|
||||||
|
vmp_family_prices AS (
|
||||||
|
-- Fallback average where a pack has no direct price but belongs to a VMP family.
|
||||||
|
SELECT
|
||||||
|
"MedicinalLatestSnomedCode" AS "VmpCode",
|
||||||
|
AVG("PricePerUnit") AS "PricePerUnit"
|
||||||
|
FROM pack_level_data
|
||||||
|
WHERE "PricePerUnit" IS NOT NULL
|
||||||
|
GROUP BY "MedicinalLatestSnomedCode"
|
||||||
|
),
|
||||||
|
product_prices AS (
|
||||||
|
-- Returns one product-to-unit-price lookup across pack and presentation levels.
|
||||||
|
SELECT "ProductSnomedCode", "PricePerUnit"
|
||||||
|
FROM pack_level_data
|
||||||
|
WHERE "PricePerUnit" IS NOT NULL
|
||||||
|
|
||||||
|
UNION ALL
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
pld."ProductSnomedCode",
|
||||||
|
vfp."PricePerUnit"
|
||||||
|
FROM pack_level_data pld
|
||||||
|
INNER JOIN vmp_family_prices vfp
|
||||||
|
ON pld."MedicinalLatestSnomedCode" = vfp."VmpCode"
|
||||||
|
WHERE pld."PricePerUnit" IS NULL
|
||||||
|
|
||||||
|
UNION ALL
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
parent."ProductSnomedCode",
|
||||||
|
COALESCE(direct_avg."PricePerUnit", vfp."PricePerUnit") AS "PricePerUnit"
|
||||||
|
FROM DATA_HUB.DWH."DimMedicineAndDevice" parent
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT
|
||||||
|
"ParentPresentationSnomedCode" AS "ParentCode",
|
||||||
|
AVG("PricePerUnit") AS "PricePerUnit"
|
||||||
|
FROM pack_level_data
|
||||||
|
WHERE "PricePerUnit" IS NOT NULL
|
||||||
|
GROUP BY "ParentPresentationSnomedCode"
|
||||||
|
) direct_avg
|
||||||
|
ON direct_avg."ParentCode" = parent."ProductSnomedCode"
|
||||||
|
LEFT JOIN vmp_family_prices vfp
|
||||||
|
ON parent."MedicinalLatestSnomedCode" = vfp."VmpCode"
|
||||||
|
WHERE parent."ProductLevel" IN ('VMP', 'AMP')
|
||||||
|
AND COALESCE(direct_avg."PricePerUnit", vfp."PricePerUnit") IS NOT NULL
|
||||||
|
),
|
||||||
|
tpp_quantity_parsed AS (
|
||||||
|
-- Parse common TPP free-text quantity patterns before estimating cost.
|
||||||
|
SELECT
|
||||||
|
med."IDPatient",
|
||||||
|
med."IDOrganisation",
|
||||||
|
med."IDMultiLexDMD" AS "ProductSnomedCode",
|
||||||
|
CAST(med."DateMedicationStart" AS DATE) AS "DateMedicationStart",
|
||||||
|
med."MedicationQuantity" AS "SourceQuantityText",
|
||||||
|
COALESCE(
|
||||||
|
CASE
|
||||||
|
WHEN REGEXP_SUBSTR(LOWER(med."MedicationQuantity"), '([0-9]+)\\s*packs?\\s+of\\s+([0-9]+)', 1, 1, 'e', 1) IS NOT NULL
|
||||||
|
THEN TRY_CAST(REGEXP_SUBSTR(LOWER(med."MedicationQuantity"), '([0-9]+)\\s*packs?\\s+of', 1, 1, 'e', 1) AS FLOAT)
|
||||||
|
* TRY_CAST(REGEXP_SUBSTR(LOWER(med."MedicationQuantity"), 'of\\s+([0-9]+)', 1, 1, 'e', 1) AS FLOAT)
|
||||||
|
END,
|
||||||
|
CASE
|
||||||
|
WHEN REGEXP_SUBSTR(med."MedicationQuantity", '^([0-9]+)\\s*\\*\\s*([0-9]+)', 1, 1, 'e', 1) IS NOT NULL
|
||||||
|
THEN TRY_CAST(REGEXP_SUBSTR(med."MedicationQuantity", '^([0-9]+)', 1, 1, 'e', 1) AS FLOAT)
|
||||||
|
* TRY_CAST(REGEXP_SUBSTR(med."MedicationQuantity", '\\*\\s*([0-9]+)', 1, 1, 'e', 1) AS FLOAT)
|
||||||
|
END,
|
||||||
|
CASE
|
||||||
|
WHEN REGEXP_SUBSTR(med."MedicationQuantity", '^1\\s*x\\s*([0-9]+\\.?[0-9]*)', 1, 1, 'e', 1) IS NOT NULL
|
||||||
|
THEN TRY_CAST(REGEXP_SUBSTR(med."MedicationQuantity", '^1\\s*x\\s*([0-9]+\\.?[0-9]*)', 1, 1, 'e', 1) AS FLOAT)
|
||||||
|
END,
|
||||||
|
CASE
|
||||||
|
WHEN REGEXP_SUBSTR(TRIM(med."MedicationQuantity"), '^[0-9]+\\.?[0-9]*$') IS NOT NULL
|
||||||
|
THEN TRY_CAST(TRIM(med."MedicationQuantity") AS FLOAT)
|
||||||
|
END,
|
||||||
|
CASE
|
||||||
|
WHEN REGEXP_SUBSTR(med."MedicationQuantity", '^([0-9]+\\.?[0-9]*)') IS NOT NULL
|
||||||
|
THEN TRY_CAST(REGEXP_SUBSTR(med."MedicationQuantity", '^([0-9]+\\.?[0-9]*)', 1, 1, 'e', 1) AS FLOAT)
|
||||||
|
END
|
||||||
|
) AS "ParsedQuantity"
|
||||||
|
FROM PRIMARY_CARE.TPP."SRPrimaryCareMedication" med
|
||||||
|
WHERE med."DateMedicationStart" BETWEEN $START_DATE AND $END_DATE
|
||||||
|
),
|
||||||
|
example_tpp_output AS (
|
||||||
|
-- Example consumer query; adapt this CTE for a specific medicine/cohort.
|
||||||
|
SELECT
|
||||||
|
dp."PersonKey",
|
||||||
|
tpp."IDOrganisation" AS "OrgCode",
|
||||||
|
tpp."ProductSnomedCode",
|
||||||
|
tpp."DateMedicationStart",
|
||||||
|
tpp."SourceQuantityText",
|
||||||
|
tpp."ParsedQuantity",
|
||||||
|
pp."PricePerUnit",
|
||||||
|
ROUND(tpp."ParsedQuantity" * pp."PricePerUnit", 2) AS "EstimatedPrice"
|
||||||
|
FROM tpp_quantity_parsed tpp
|
||||||
|
INNER JOIN PRIMARY_CARE.TPP."SRPatient" pat
|
||||||
|
ON tpp."IDPatient" = pat."IDPatient"
|
||||||
|
INNER JOIN DATA_HUB.DWH."DimPerson" dp
|
||||||
|
ON pat."PatientPseudonym" = dp."PatientPseudonym"
|
||||||
|
LEFT JOIN product_prices pp
|
||||||
|
ON tpp."ProductSnomedCode" = pp."ProductSnomedCode"
|
||||||
|
WHERE pat."PatientPseudonym" IS NOT NULL
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
"PersonKey",
|
||||||
|
"OrgCode",
|
||||||
|
"ProductSnomedCode",
|
||||||
|
"DateMedicationStart",
|
||||||
|
"SourceQuantityText",
|
||||||
|
"ParsedQuantity",
|
||||||
|
"PricePerUnit",
|
||||||
|
"EstimatedPrice"
|
||||||
|
FROM example_tpp_output
|
||||||
|
LIMIT 100;
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
# Snowflake Medicines Optimisation Query Templates
|
||||||
|
|
||||||
|
Curated Snowflake SQL templates for medicines optimisation analysis. The aim is to give a new analyst a clean starting point without copying the whole working query folder, including old experiments and one-off scripts.
|
||||||
|
|
||||||
|
The templates are written for analysts who already understand medicines datasets and reporting concepts, but who may not have pharmacy training. Clinical judgement, formulary interpretation, and patient-level action should still be checked with the relevant clinical lead.
|
||||||
|
|
||||||
|
## Start Here
|
||||||
|
|
||||||
|
1. Use `docs/data_sources_and_join_patterns.md` to understand the main tables and joins.
|
||||||
|
2. Use `01_medicine_lookups/medicine_reference_lookup.sql` to identify the right BNF, VTM, VMP, or product codes.
|
||||||
|
3. Read `docs/sql_style_and_validation_guardrails.md` when adapting a template for the first time.
|
||||||
|
4. Check `docs/template_validation_status.md` to see what was validated against Snowflake.
|
||||||
|
5. Pick the closest template folder below.
|
||||||
|
6. Replace the visible `SET` values and any `REPLACE_WITH...` placeholders.
|
||||||
|
7. Run a small test first, then check output columns before using the result in a report.
|
||||||
|
|
||||||
|
## Folder Guide
|
||||||
|
|
||||||
|
`00_copied_reference/`
|
||||||
|
|
||||||
|
Original files copied from the working repo because they were already template-like. Use them as reference, not as the preferred starting point.
|
||||||
|
|
||||||
|
`01_medicine_lookups/`
|
||||||
|
|
||||||
|
Lookup and extraction templates for medicines by VTM, VMP, BNF, dispensing product, or patient pseudonym.
|
||||||
|
|
||||||
|
`02_prescribing_analysis/`
|
||||||
|
|
||||||
|
Practice-level prescribing summaries, high-prescribing quintiles, and patient-level cost ranking.
|
||||||
|
|
||||||
|
`03_cohorts_and_clinical_coding/`
|
||||||
|
|
||||||
|
Templates for combining prescribing exposure with clinical coding, maintained SNOMED clusters, and month/practice event grids.
|
||||||
|
|
||||||
|
`04_rolling_and_pqs/`
|
||||||
|
|
||||||
|
Rolling-period, long-format, baseline-vs-evaluation, and latest-data templates. These are useful for PQS-style reporting and repeatable monthly outputs.
|
||||||
|
|
||||||
|
`05_audit_detail/`
|
||||||
|
|
||||||
|
Row-level audit extract pattern with medicine and organisation names added. Use this after an aggregate query identifies records worth checking.
|
||||||
|
|
||||||
|
`06_advanced_methods/`
|
||||||
|
|
||||||
|
More technical reference logic, currently including raw TPP quantity parsing and product price lookup. Prefer maintained tables unless you need to rebuild or audit the method.
|
||||||
|
|
||||||
|
`docs/`
|
||||||
|
|
||||||
|
Plain-language notes on data sources, joins, common medicines-analysis terms, SQL guardrails, and the copied introductory SQL/Snowflake training programme.
|
||||||
|
|
||||||
|
## Common Defaults
|
||||||
|
|
||||||
|
For Norfolk/Suffolk practice reporting, templates use:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
WHERE "OrganisationSubType" = 'GP Practice'
|
||||||
|
AND "IsSiteActive" = 'Yes'
|
||||||
|
AND "IsSiteNorfolkAndSuffolk" = 'Yes'
|
||||||
|
AND "SiteCode" = "OrganisationCode"
|
||||||
|
```
|
||||||
|
|
||||||
|
Change this deliberately if the report is Norfolk and Waveney only, branch-site level, provider-level, or national.
|
||||||
|
|
||||||
|
## Practical Checks Before Sharing Outputs
|
||||||
|
|
||||||
|
- Confirm whether the question needs prescribing data or dispensing data.
|
||||||
|
- Check latest available dates before setting the reporting period.
|
||||||
|
- Keep denominator logic visible in the SQL.
|
||||||
|
- Use maintained coding clusters before text-searching SNOMED descriptions.
|
||||||
|
- Avoid `SELECT *` in shared audit extracts.
|
||||||
|
- Do not commit patient pseudonyms, row-level extracts, CSVs, or spreadsheets.
|
||||||
|
|
||||||
|
## Template Sources
|
||||||
|
|
||||||
|
The cleaned templates were derived from recurring patterns in the working query repo, including:
|
||||||
|
|
||||||
|
- VTM/VMP prescribing and dispensing checks.
|
||||||
|
- Practice-level high-prescribing analysis.
|
||||||
|
- Prescribing plus clinical coding cohorts.
|
||||||
|
- SMR/frailty-style monthly practice grids.
|
||||||
|
- PQS rolling-period and long-format outputs.
|
||||||
|
- Human-readable audit extracts using medicine and organisation dimensions.
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
# Data Sources And Join Patterns
|
||||||
|
|
||||||
|
This repo assumes access to the Norfolk and Suffolk Snowflake environment used for medicines optimisation analysis.
|
||||||
|
|
||||||
|
## Core Medicines Sources
|
||||||
|
|
||||||
|
`REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable"`
|
||||||
|
|
||||||
|
Use this for current prescribing analysis when available. It combines EMIS and TPP prescribing into a single shape with `PersonKey`, `SNOMEDCode`, `DateMedicationStart`, quantity, estimated price, source system, prescribing organisation, and current registered GP.
|
||||||
|
|
||||||
|
`NATIONAL.GPMED."MedicinesDispensedInPrimarycare"`
|
||||||
|
|
||||||
|
Use this for official dispensing activity. It is usually slower to refresh than prescribing but is better aligned to dispensing/payment concepts. Key columns include `ProcessingPeriodDate`, `PatientPseudonym`, `PaiddmdCode`, `PaidBNFCode`, `CostCentreODSCode`, `ItemCount`, `PaidQuantity`, and `TotalPaidGross`.
|
||||||
|
|
||||||
|
`DATA_HUB.DWH."DimMedicineAndDevice"`
|
||||||
|
|
||||||
|
Use this as the medicine reference table. It links SNOMED product codes to BNF, VTM, VMP, product descriptions, routes, strengths, and indicative price fields.
|
||||||
|
|
||||||
|
`DATA_HUB.DWH."DimOrganisationAndSite"`
|
||||||
|
|
||||||
|
Use this for practice names and hierarchy columns such as PCN, Place, Alliance, and INT. For Norfolk/Suffolk practice reports, the common filter is:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
WHERE "OrganisationSubType" = 'GP Practice'
|
||||||
|
AND "IsSiteActive" = 'Yes'
|
||||||
|
AND "IsSiteNorfolkAndSuffolk" = 'Yes'
|
||||||
|
AND "SiteCode" = "OrganisationCode"
|
||||||
|
```
|
||||||
|
|
||||||
|
`DATA_HUB.DWH."DimPerson"`
|
||||||
|
|
||||||
|
Use this for registered GP, age, demographic fields, and pseudonym-to-person links. For Suffolk-inclusive work, avoid old Norfolk-and-Waveney-only registration filters unless the report is explicitly Norfolk and Waveney only.
|
||||||
|
|
||||||
|
`DATA_HUB.PHM."PrimaryCareClinicalCoding"`
|
||||||
|
|
||||||
|
Use this for clinical coding events. Join on `PatientPseudonym`, then filter by `SNOMEDCode` and `EventDateTime`.
|
||||||
|
|
||||||
|
`DATA_HUB.PHM."ClinicalCodingClusterSnomedCodes"`
|
||||||
|
|
||||||
|
Use maintained clinical coding clusters where possible. This is usually safer than searching SNOMED descriptions with text matching.
|
||||||
|
|
||||||
|
## Common Joins
|
||||||
|
|
||||||
|
Prescribing to medicine:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
INNER JOIN DATA_HUB.DWH."DimMedicineAndDevice" med
|
||||||
|
ON rx."SNOMEDCode" = med."ProductSnomedCode"
|
||||||
|
```
|
||||||
|
|
||||||
|
Prescribing to registered practice:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
INNER JOIN DATA_HUB.DWH."DimOrganisationAndSite" gp
|
||||||
|
ON rx."CurrentGeneralPractice" = gp."OrganisationCode"
|
||||||
|
AND gp."SiteCode" = gp."OrganisationCode"
|
||||||
|
```
|
||||||
|
|
||||||
|
Dispensing to medicine:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
INNER JOIN DATA_HUB.DWH."DimMedicineAndDevice" med
|
||||||
|
ON gpm."PaiddmdCode" = med."ProductSnomedCode"
|
||||||
|
```
|
||||||
|
|
||||||
|
Clinical coding to maintained cluster:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
INNER JOIN DATA_HUB.PHM."ClinicalCodingClusterSnomedCodes" c
|
||||||
|
ON cc."SNOMEDCode" = c."SNOMEDCode"
|
||||||
|
AND c."Cluster_ID" = 'REPLACE_WITH_CLUSTER_ID'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Choosing The Date Field
|
||||||
|
|
||||||
|
Use `ProcessingPeriodDate` for dispensing.
|
||||||
|
|
||||||
|
Use `DateMedicationStart` for prescribing activity windows.
|
||||||
|
|
||||||
|
Use `DateEventRecorded` as a conservative freshness marker for TPP prescribing extracts when checking whether the latest full month is safe to report.
|
||||||
|
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# Glossary For Medicines Analysts
|
||||||
|
|
||||||
|
This is a practical glossary for analysts working with medicines data. It is not clinical guidance.
|
||||||
|
|
||||||
|
## Medicine Coding
|
||||||
|
|
||||||
|
`dm+d`: Dictionary of medicines and devices. The source of SNOMED product codes used for medicines.
|
||||||
|
|
||||||
|
`SNOMEDCode`: A coded identifier. In medicines queries this is usually a dm+d product code. In clinical coding queries it is usually a clinical event code.
|
||||||
|
|
||||||
|
`VTM`: Virtual Therapeutic Moiety. Broad ingredient-level grouping, useful when you want all products for a medicine substance.
|
||||||
|
|
||||||
|
`VMP`: Virtual Medicinal Product. More specific product family, useful when strength or formulation matters.
|
||||||
|
|
||||||
|
`AMP`: Actual Medicinal Product. Branded or supplier-specific product.
|
||||||
|
|
||||||
|
`VMPP` / `AMPP`: Pack-level products.
|
||||||
|
|
||||||
|
`BNFCode`: British National Formulary hierarchy code. Useful for broad prescribing sections such as antibiotics or antidepressants.
|
||||||
|
|
||||||
|
## Activity Sources
|
||||||
|
|
||||||
|
`Prescribing`: Records from GP clinical systems showing prescriptions/issues. More current, but not the same as dispensed supply.
|
||||||
|
|
||||||
|
`Dispensing`: BSA/GPMeds data showing items dispensed and paid. Better for payment-style reporting, usually with a lag.
|
||||||
|
|
||||||
|
`ProcessingPeriodDate`: The month attached to dispensing data.
|
||||||
|
|
||||||
|
`DateMedicationStart`: The prescribing date used in the unified prescribing table.
|
||||||
|
|
||||||
|
## People And Organisations
|
||||||
|
|
||||||
|
`PersonKey`: Internal person identifier used for linked analysis. Prefer this for patient counts where available.
|
||||||
|
|
||||||
|
`PatientPseudonym`: Pseudonymised patient identifier. Needed for some joins to clinical coding and dispensing.
|
||||||
|
|
||||||
|
`CurrentGeneralPractice`: Practice code attached to the patient or prescribing row.
|
||||||
|
|
||||||
|
`OrganisationCode` / `SiteCode`: Organisation and site identifiers. For practice-level reporting, use the parent practice row where `SiteCode = OrganisationCode` unless branch-level reporting is intended.
|
||||||
|
|
||||||
|
`PCN`, `Place`, `Alliance`, `INT`: Organisation hierarchy fields used for grouping practice outputs.
|
||||||
|
|
||||||
|
## Analysis Terms
|
||||||
|
|
||||||
|
`Cohort`: A defined set of patients meeting criteria.
|
||||||
|
|
||||||
|
`Denominator`: The population used to calculate a rate, for example registered patients at a practice.
|
||||||
|
|
||||||
|
`Numerator`: The count meeting the measure, for example patients prescribed a medicine.
|
||||||
|
|
||||||
|
`Quintile`: One of five ranked groups. Quintile 5 is often used for highest prescribing when ranking from low to high.
|
||||||
|
|
||||||
|
`Long format`: Output where each indicator is a row rather than a separate column. This is useful for appending measures and charting.
|
||||||
|
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# SQL Style And Validation Guardrails
|
||||||
|
|
||||||
|
These notes are extracted from repeated medicines optimisation query work. They are intended to prevent common Snowflake and medicines-data errors.
|
||||||
|
|
||||||
|
## Snowflake Syntax
|
||||||
|
|
||||||
|
- Double-quote table and column identifiers, especially mixed-case columns such as `"PatientPseudonym"` and `"ProcessingPeriodDate"`.
|
||||||
|
- Quote aliases that will be consumed by Excel, Power BI, Python, or another SQL layer: `COUNT(*) AS "PatientCount"`.
|
||||||
|
- Use `CURRENT_DATE()` or `CURRENT_TIMESTAMP()` rather than T-SQL functions such as `GETDATE()`.
|
||||||
|
- Use `LIMIT` for quick checks.
|
||||||
|
- Cast long-format output values to a consistent numeric type before `UNION ALL`.
|
||||||
|
|
||||||
|
## Medicines Table Choices
|
||||||
|
|
||||||
|
- Use `REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable"` for current prescribing analysis when available.
|
||||||
|
- Use `NATIONAL.GPMED."MedicinesDispensedInPrimarycare"` for official dispensed/paid activity.
|
||||||
|
- Do not treat prescribing and dispensing as interchangeable. They answer related but different questions.
|
||||||
|
- Map prescribing SNOMED codes to BNF through `DATA_HUB.DWH."DimMedicineAndDevice"`.
|
||||||
|
- Use `"ProductDescription"` for medicine names from `DimMedicineAndDevice`. Do not assume a `"ProductName"` column.
|
||||||
|
|
||||||
|
## Geography And Denominators
|
||||||
|
|
||||||
|
- Keep the practice CTE visible in each report.
|
||||||
|
- For Norfolk/Suffolk GP practice outputs, use `DATA_HUB.DWH."DimOrganisationAndSite"` with `"IsSiteNorfolkAndSuffolk" = 'Yes'`.
|
||||||
|
- Only use older Norfolk-and-Waveney flags when the report is explicitly Norfolk and Waveney only.
|
||||||
|
- Be explicit about whether you are using organisation registered population, a counted active patient denominator, or another denominator.
|
||||||
|
|
||||||
|
## Clinical Coding
|
||||||
|
|
||||||
|
- Prefer maintained clusters in `DATA_HUB.PHM."ClinicalCodingClusterSnomedCodes"` over text searching SNOMED descriptions.
|
||||||
|
- Use `DATA_HUB.PHM."PrimaryCareClinicalCoding"` for unified clinical coding across systems.
|
||||||
|
- Join clinical coding to patients through `PatientPseudonym`, then to `DimPerson` when person or practice fields are needed.
|
||||||
|
- Make lookback windows visible in `SET` variables or a date CTE.
|
||||||
|
|
||||||
|
## Validation Before Sharing
|
||||||
|
|
||||||
|
- Check latest data dates before selecting a period.
|
||||||
|
- Run a limited version first and inspect row counts.
|
||||||
|
- Check the output column list before handing results to someone else.
|
||||||
|
- Avoid `SELECT *` in audit/detail outputs.
|
||||||
|
- Do not commit patient pseudonyms, CSV exports, spreadsheets, images, or local tooling files.
|
||||||
|
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
# Template Validation Status
|
||||||
|
|
||||||
|
Last reviewed: 2026-05-12
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
The reusable SQL templates in folders `01_medicine_lookups` through
|
||||||
|
`06_advanced_methods` were checked with the Snowflake MCP against live table
|
||||||
|
metadata and representative parameter values. Templates that use `SET`
|
||||||
|
variables were validated by substituting safe example literals into the final
|
||||||
|
`SELECT` statement before running `describe_query`.
|
||||||
|
|
||||||
|
The `00_copied_reference` folder and `docs/training_intro_snowflake_sql` are
|
||||||
|
historic/reference material. They are retained for learning and comparison,
|
||||||
|
not as the preferred starting point for new analysis.
|
||||||
|
|
||||||
|
## Live Metadata Checked
|
||||||
|
|
||||||
|
- `REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable"`
|
||||||
|
- `NATIONAL.GPMED."MedicinesDispensedInPrimarycare"`
|
||||||
|
- `DATA_HUB.DWH."DimMedicineAndDevice"`
|
||||||
|
- `DATA_HUB.DWH."DimOrganisationAndSite"`
|
||||||
|
- `DATA_HUB.DWH."DimPerson"`
|
||||||
|
- `DATA_HUB.PHM."ClinicalCodingClusterSnomedCodes"`
|
||||||
|
- `DATA_HUB.PHM."PrimaryCareClinicalCoding"`
|
||||||
|
- `PRIMARY_CARE.TPP."SRPrimaryCareMedication"`
|
||||||
|
- `PRIMARY_CARE.TPP."SRPatient"`
|
||||||
|
|
||||||
|
## Query Compilation Checks
|
||||||
|
|
||||||
|
All files below passed Snowflake MCP `describe_query` validation:
|
||||||
|
|
||||||
|
- `01_medicine_lookups/medicine_reference_lookup.sql`
|
||||||
|
- `01_medicine_lookups/prescribing_by_vtm.sql`
|
||||||
|
- `01_medicine_lookups/prescribing_by_vmp.sql`
|
||||||
|
- `01_medicine_lookups/dispensing_by_vtm_or_vmp.sql`
|
||||||
|
- `01_medicine_lookups/prescribing_for_patient_pseudonym.sql`
|
||||||
|
- `02_prescribing_analysis/practice_level_bnf_prescribing_summary.sql`
|
||||||
|
- `02_prescribing_analysis/high_prescribing_practices_quintile_template.sql`
|
||||||
|
- `02_prescribing_analysis/prescribing_spend_by_patient_template.sql`
|
||||||
|
- `03_cohorts_and_clinical_coding/cluster_code_lookup.sql`
|
||||||
|
- `03_cohorts_and_clinical_coding/monthly_clinical_event_count_by_practice.sql`
|
||||||
|
- `03_cohorts_and_clinical_coding/prescribing_plus_clinical_code_cohort.sql`
|
||||||
|
- `04_rolling_and_pqs/rolling_period_generator.sql`
|
||||||
|
- `04_rolling_and_pqs/latest_data_dates.sql`
|
||||||
|
- `04_rolling_and_pqs/baseline_vs_evaluation_template.sql`
|
||||||
|
- `04_rolling_and_pqs/dual_source_long_format_measure_template.sql`
|
||||||
|
- `05_audit_detail/human_readable_prescribing_detail.sql`
|
||||||
|
- `06_advanced_methods/product_price_and_quantity_parsing_template.sql`
|
||||||
|
|
||||||
|
## Freshness Probe
|
||||||
|
|
||||||
|
The `latest_data_dates.sql` query was also executed with Snowflake MCP. At the
|
||||||
|
time of review it returned:
|
||||||
|
|
||||||
|
- `NATIONAL.GPMED."MedicinesDispensedInPrimarycare"` latest
|
||||||
|
`ProcessingPeriodDate`: `2025-07-01`
|
||||||
|
- `PRIMARY_CARE.TPP."SRPrimaryCareMedication"` latest `DateEventRecorded`
|
||||||
|
within the recent-window probe: `2026-03-28`
|
||||||
|
- `REPORTING_DATASETS_ICB.SCRATCHPAD."MEDS__UnifiedPrescribingTable"` latest
|
||||||
|
non-future `DateMedicationStart`: `2026-05-12`
|
||||||
|
|
||||||
Reference in New Issue
Block a user