From a5397b3576afe7deef37f33f475ed673f1983e87 Mon Sep 17 00:00:00 2001 From: Muhammad Anas Farooqui Date: Wed, 15 Apr 2026 11:58:41 +0530 Subject: [PATCH] added views --- dbt_project.yml | 4 ++ models/views/_views.yml | 55 +++++++++++++++++++ models/views/vw_department_daily_census.sql | 42 ++++++++++++++ .../views/vw_patient_summary_deidentified.sql | 43 +++++++++++++++ .../vw_provider_readmission_overview.sql | 41 ++++++++++++++ 5 files changed, 185 insertions(+) create mode 100644 models/views/_views.yml create mode 100644 models/views/vw_department_daily_census.sql create mode 100644 models/views/vw_patient_summary_deidentified.sql create mode 100644 models/views/vw_provider_readmission_overview.sql diff --git a/dbt_project.yml b/dbt_project.yml index 83852e3..06dd45a 100644 --- a/dbt_project.yml +++ b/dbt_project.yml @@ -44,6 +44,10 @@ models: +meta: contains_pii: true compliance_framework: 'HIPAA' + views: + +materialized: view + +schema: views + +tags: ['views'] seeds: medflow_analytics: diff --git a/models/views/_views.yml b/models/views/_views.yml new file mode 100644 index 0000000..66ffce0 --- /dev/null +++ b/models/views/_views.yml @@ -0,0 +1,55 @@ +version: 2 + +models: + - name: vw_patient_summary_deidentified + description: > + De-identified patient summary view on top of mart_patient_360. + Strips all PII/PHI fields so clinical analysts can safely query + patient demographics, encounters, and diagnoses without HIPAA-restricted access. + columns: + - name: patient_hash_id + description: "MD5 hash of patient name for anonymous linkage" + - name: date_of_birth + description: "Patient date of birth" + - name: age + description: "Calculated patient age in years" + - name: diagnosis_code + description: "Diagnosis code from the encounter" + + - name: vw_department_daily_census + description: > + Daily department occupancy snapshot aggregated from mart_department_utilization. + Shows active patient and encounter counts per department per day. + columns: + - name: department_id + description: "Department identifier" + - name: department_name + description: "Department name" + - name: floor + description: "Building floor" + - name: cost_center + description: "Department cost center" + - name: census_date + description: "Date of the census snapshot" + - name: active_patients + description: "Count of distinct patients active on this day" + - name: active_encounters + description: "Count of distinct encounters active on this day" + + - name: vw_provider_readmission_overview + description: > + Provider-level readmission summary from mart_provider_scorecard. + Aggregates total encounters, readmissions, and readmission rate per provider. + columns: + - name: attending_physician_id + description: "Provider identifier" + - name: primary_diagnosis_code + description: "Primary diagnosis for the encounter group" + - name: department_id + description: "Department identifier" + - name: total_encounters + description: "Total distinct encounters for this provider" + - name: total_readmissions + description: "Total distinct 30-day readmission encounters" + - name: readmission_rate_pct + description: "Readmission rate as a percentage" diff --git a/models/views/vw_department_daily_census.sql b/models/views/vw_department_daily_census.sql new file mode 100644 index 0000000..2ee528b --- /dev/null +++ b/models/views/vw_department_daily_census.sql @@ -0,0 +1,42 @@ +{{ config( + materialized='view', + tags=['views'] +) }} + +/* + View: vw_department_daily_census + + Use case: Daily department occupancy snapshot for operations dashboards. + Counts active patients per department on each calendar day based on + admission and discharge dates from mart_department_utilization. +*/ + +with utilization as ( + + select * from {{ ref('mart_department_utilization') }} + +), + +final as ( + + select + department_id, + department_name, + floor, + cost_center, + admission_date as census_date, + count(distinct patient_id) as active_patients, + count(distinct encounter_id) as active_encounters + from utilization + where discharge_date is null + or discharge_date >= admission_date + group by + department_id, + department_name, + floor, + cost_center, + admission_date + +) + +select * from final diff --git a/models/views/vw_patient_summary_deidentified.sql b/models/views/vw_patient_summary_deidentified.sql new file mode 100644 index 0000000..aeebed7 --- /dev/null +++ b/models/views/vw_patient_summary_deidentified.sql @@ -0,0 +1,43 @@ +{{ config( + materialized='view', + tags=['views', 'deidentified'], + meta={ + 'contains_pii': false, + 'owner': 'clinical-analytics', + 'use_case': 'De-identified patient summary for clinical and analytics teams' + } +) }} + +/* + View: vw_patient_summary_deidentified + + Use case: Provides a de-identified patient summary on top of mart_patient_360. + Strips all PII/PHI fields (name, SSN, phone, email, address) so that clinical + analysts and data scientists can query patient encounter and diagnosis data + without requiring HIPAA-restricted access to the marts_pii schema. +*/ + +with patient_360 as ( + + select * from {{ ref('mart_patient_360') }} + +), + +final as ( + + select + -- Masked patient identifier (hashed for linkage without exposing PII) + md5(cast(full_name as varchar)) as patient_hash_id, + + -- Demographics (non-PII) + date_of_birth, + floor(datediff('year', date_of_birth, current_date)) as age, + + -- Clinical + diagnosis_code + + from patient_360 + +) + +select * from final diff --git a/models/views/vw_provider_readmission_overview.sql b/models/views/vw_provider_readmission_overview.sql new file mode 100644 index 0000000..345f3fd --- /dev/null +++ b/models/views/vw_provider_readmission_overview.sql @@ -0,0 +1,41 @@ +{{ config( + materialized='view', + tags=['views'] +) }} + +/* + View: vw_provider_readmission_overview + + Use case: Quick provider-level readmission summary for quality reporting. + Aggregates encounter counts and readmission counts per provider from + mart_provider_scorecard. +*/ + +with scorecard as ( + + select * from {{ ref('mart_provider_scorecard') }} + +), + +final as ( + + select + attending_physician_id, + primary_diagnosis_code, + department_id, + count(distinct encounter_id) as total_encounters, + count(distinct readmission_encounter_id) as total_readmissions, + round( + count(distinct readmission_encounter_id)::numeric + / nullif(count(distinct encounter_id), 0) * 100, + 2 + ) as readmission_rate_pct + from scorecard + group by + attending_physician_id, + primary_diagnosis_code, + department_id + +) + +select * from final