initial commit

This commit is contained in:
Andrew Charlwood
2026-05-12 16:40:03 +01:00
commit 647d1bfa7f
38 changed files with 2715 additions and 0 deletions
@@ -0,0 +1,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";