initial commit
This commit is contained in:
@@ -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 |
|
||||
-- ==============================================================================
|
||||
Reference in New Issue
Block a user