Files
medicines-snowflake/02_prescribing_analysis/high_prescribing_practices_quintile_template.sql
T
Andrew Charlwood 647d1bfa7f initial commit
2026-05-12 16:40:03 +01:00

188 lines
7.2 KiB
SQL

/*
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";