From b280ee597362f2068cde3deb18b12fbf4a4c68a6 Mon Sep 17 00:00:00 2001 From: sarah-tuva Date: Wed, 11 Dec 2024 15:47:53 -0700 Subject: [PATCH 1/4] Make person_id changes --- docs/connectors/input-layer.md | 22 ++++++--- docs/core-data-model/condition.md | 2 + docs/core-data-model/eligibility.md | 5 +- docs/core-data-model/encounter.md | 2 +- docs/core-data-model/lab-result.md | 1 + docs/core-data-model/medical-claim.md | 3 +- docs/core-data-model/medication.md | 1 + docs/core-data-model/observation.md | 1 + docs/core-data-model/patient.md | 2 +- docs/core-data-model/pharmacy-claim.md | 3 +- docs/core-data-model/procedure.md | 2 + docs/data-marts/ahrq-measures.md | 6 +-- docs/data-marts/ccsr.md | 6 +-- docs/data-marts/chronic-conditions.md | 26 +++++----- docs/data-marts/cms-hccs.md | 8 ++-- docs/data-marts/ed-classification.md | 30 ++++++------ docs/data-marts/encounter-types.md | 4 +- docs/data-marts/financial-pmpm.md | 26 +++++----- docs/data-marts/hcc-suspecting.md | 2 +- docs/data-marts/pharmacy.md | 28 +++++------ docs/data-marts/quality-measures.md | 2 +- docs/data-marts/readmissions.md | 6 +-- docs/data-quality/atomic-level.md | 48 +++++++++---------- docs/getting-started/mapping-guide.md | 2 +- docs/guides/data-source-setup/mapping.md | 2 +- .../claims-data-fundamentals/member-months.md | 4 +- docs/knowledge/hospital-readmissions.md | 4 +- 27 files changed, 135 insertions(+), 113 deletions(-) diff --git a/docs/connectors/input-layer.md b/docs/connectors/input-layer.md index 1d85a109..f98b8016 100644 --- a/docs/connectors/input-layer.md +++ b/docs/connectors/input-layer.md @@ -16,10 +16,13 @@ The `Input Layer` is designed to accomodate both claims and clinical data source The eligibility table includes information about a patient's health insurance coverage and demographics (note: we use the word patient as a synonym for member). Every claims dataset should include some sort of eligibility data, otherwise it's impossible to calculate member months, which are needed to calculate measures like PMPM. Each record in the table is intended to represent a unique eligibility (i.e. enrollment) span for a patient with a specific health plan. **Primary Key:** - * patient_id - * plan - * enrollment_start_date - * enrollment_end_date + * person_id + * member_id + * enrollment_start_date + * enrollment_end_date + * payer + * plan + * data_source @@ -32,7 +35,7 @@ The medical_claim table contains information on healthcare services and supplies * claim_line_number **Foreign Keys:** - * patient_id + * person_id * member_id @@ -46,7 +49,7 @@ The pharmacy_claim table includes information about retail and specialty drug pr * claim_line_number **Foreign Keys:** - * patient_id + * person_id * member_id @@ -62,6 +65,7 @@ The condition table contains information related to medical conditions patients **Foreign Keys:** * patient_id + * person_id * encounter_id @@ -75,6 +79,7 @@ The encounter table contains information about patients visits (i.e. encounters) **Foreign Keys:** * patient_id + * person_id @@ -87,6 +92,7 @@ The lab result table contains information about lab test results, including the **Foreign Keys:** * patient_id + * person_id * encounter_id @@ -109,6 +115,7 @@ The medication table contains information on medications ordered and/or administ **Foreign Keys:** * patient_id + * person_id * encounter_id @@ -122,6 +129,7 @@ The observation table contains information on measurements other than lab tests **Foreign Keys:** * patient_id + * person_id * encounter_id @@ -132,6 +140,7 @@ The patient table contains demographic and geographic information on patients. **Primary Key:** * patient_id + * person_id @@ -153,6 +162,7 @@ The procedure table contains information on procedures that were performed on pa **Foreign Keys:** * patient_id + * person_id * encounter_id * practitioner_id diff --git a/docs/core-data-model/condition.md b/docs/core-data-model/condition.md index 6385f8a8..cc9db7a4 100644 --- a/docs/core-data-model/condition.md +++ b/docs/core-data-model/condition.md @@ -19,6 +19,8 @@ have an encounter_id). * condition_id **Foreign Keys:** + * person_id + * member_id * patient_id * encounter_id diff --git a/docs/core-data-model/eligibility.md b/docs/core-data-model/eligibility.md index 20a54280..a925c14d 100644 --- a/docs/core-data-model/eligibility.md +++ b/docs/core-data-model/eligibility.md @@ -12,9 +12,12 @@ otherwise it's impossible to calculate member months, which are needed to calculate measures like PMPM. **Primary Keys:** - * patient_id + * person_id * member_id * enrollment_start_date * enrollment_end_date + * payer + * plan + * data_source \ No newline at end of file diff --git a/docs/core-data-model/encounter.md b/docs/core-data-model/encounter.md index 20805bd5..df39c6b0 100644 --- a/docs/core-data-model/encounter.md +++ b/docs/core-data-model/encounter.md @@ -20,6 +20,6 @@ this important information in a single table. * encounter_id **Foreign Keys:** - * patient_id + * person_id \ No newline at end of file diff --git a/docs/core-data-model/lab-result.md b/docs/core-data-model/lab-result.md index 12f4ec11..decb40d4 100644 --- a/docs/core-data-model/lab-result.md +++ b/docs/core-data-model/lab-result.md @@ -13,6 +13,7 @@ result. * lab_result_id **Foreign Keys:** + * person_id * patient_id * encounter_id diff --git a/docs/core-data-model/medical-claim.md b/docs/core-data-model/medical-claim.md index 95e65bcb..89607064 100644 --- a/docs/core-data-model/medical-claim.md +++ b/docs/core-data-model/medical-claim.md @@ -17,9 +17,10 @@ category and encounter that are useful for analytics. **Primary Keys:** * claim_id * claim_line_number + * data_source **Foreign Keys:** - * patient_id + * person_id * member_id * encounter_id diff --git a/docs/core-data-model/medication.md b/docs/core-data-model/medication.md index c6f88145..11f818e4 100644 --- a/docs/core-data-model/medication.md +++ b/docs/core-data-model/medication.md @@ -12,6 +12,7 @@ administered during a patient encounter. * medication_id **Foreign Keys:** + * person_id * patient_id * encounter_id diff --git a/docs/core-data-model/observation.md b/docs/core-data-model/observation.md index 1d3baf2e..039299fa 100644 --- a/docs/core-data-model/observation.md +++ b/docs/core-data-model/observation.md @@ -12,6 +12,7 @@ tests e.g. blood pressure, height, and weight. * observation_id **Foreign Keys:** + * person_id * patient_id * encounter_id diff --git a/docs/core-data-model/patient.md b/docs/core-data-model/patient.md index ed61cb71..41be51cc 100644 --- a/docs/core-data-model/patient.md +++ b/docs/core-data-model/patient.md @@ -11,6 +11,6 @@ analytics use cases involve analyzing things that happen to patients, so it's critical to have a clean patient table that contains this information. **Primary Keys:** - * patient_id + * person_id \ No newline at end of file diff --git a/docs/core-data-model/pharmacy-claim.md b/docs/core-data-model/pharmacy-claim.md index 253ee782..0529babe 100644 --- a/docs/core-data-model/pharmacy-claim.md +++ b/docs/core-data-model/pharmacy-claim.md @@ -12,9 +12,10 @@ paid by an insurer. The pharmacy_claim table is at the claim-line grain. **Primary Keys:** * claim_id * claim_line_number + * data_source **Foreign Keys:** - * patient_id + * person_id * member_id \ No newline at end of file diff --git a/docs/core-data-model/procedure.md b/docs/core-data-model/procedure.md index 85ddf85b..81bd89e2 100644 --- a/docs/core-data-model/procedure.md +++ b/docs/core-data-model/procedure.md @@ -14,6 +14,8 @@ ICD-10-PCS and HCPCS. * procedure_id **Foreign Keys:** + * person_id + * member_id * patient_id * encounter_id * practitioner_id diff --git a/docs/data-marts/ahrq-measures.md b/docs/data-marts/ahrq-measures.md index 28d73d62..f85e87f0 100644 --- a/docs/data-marts/ahrq-measures.md +++ b/docs/data-marts/ahrq-measures.md @@ -84,7 +84,7 @@ This data mart computes the PQIs. The individual measures and definitions as of This model contains a row for each patient and data_source combination that is eligible for each pqi each year. **Primary Key:** - * patient_id + * person_id * data_source * pqi_number * year_number @@ -109,7 +109,7 @@ This model contains a list of all the exclusions an encounter qualified for. An ### pqi_num_long -This model contains a list of all encounters that qualified for a pqi. The patient_id and data_source are brought in for reference as well. +This model contains a list of all encounters that qualified for a pqi. The person_id and data_source are brought in for reference as well. **Primary Key:** * data_source @@ -241,7 +241,7 @@ with num as ( data_source , year_number , pqi_number - , count(patient_id) as denom_count + , count(person_id) as denom_count from ahrq_measures.pqi_denom_long group by data_source diff --git a/docs/data-marts/ccsr.md b/docs/data-marts/ccsr.md index 4cbac2b8..25f61dc5 100644 --- a/docs/data-marts/ccsr.md +++ b/docs/data-marts/ccsr.md @@ -22,7 +22,7 @@ rows than the Tuva condition model. The model is equivalent to the CCSR's Output Option 1 - Vertical File Output. **Primary Keys:** - * patient_id + * person_id * normalized_code * ccsr_category @@ -40,7 +40,7 @@ mapping of an ICD-10 code to a CCSR category. The model is equivalent to the CCSR's Output Option 1 - Vertical File Output. **Primary Keys:** - * patient_id + * person_id * normalized_code * ccsr_category @@ -55,7 +55,7 @@ This model contains only the CCSR's default category assignment for the ICD-10 code, and only for the first-listed ICD-10 code (`diagnosis_code = 1`). **Primary Keys:** - * patient_id + * person_id * ccsr_category **Foreign Keys:** diff --git a/docs/data-marts/chronic-conditions.md b/docs/data-marts/chronic-conditions.md index b8510dba..f103d51c 100644 --- a/docs/data-marts/chronic-conditions.md +++ b/docs/data-marts/chronic-conditions.md @@ -27,7 +27,7 @@ This table is created by running the CMS chronic conditions data mart on data that's been mapped to the core data model. **Primary Keys:** - * patient_id + * person_id * condition **Foreign Keys:** @@ -43,7 +43,7 @@ particular chronic condition they will have a 1 in that particular column and 0 otherwise. **Primary Keys:** - * patient_id + * person_id @@ -56,7 +56,7 @@ recent diagnosis, and the total count of diagnosis codes that were recorded that are relevant for the condition. **Primary Keys:** - * patient_id + * person_id * condition @@ -69,7 +69,7 @@ particular chronic condition they will have a 1 in that particular column and 0 otherwise. **Primary Keys:** - * patient_id + * person_id @@ -83,8 +83,8 @@ In this query we show how often each chronic condition occurs in the patient pop ```sql select condition -, count(distinct patient_id) as total_patients -, cast(count(distinct patient_id) * 100.0 / (select count(distinct patient_id) from core.patient) as numeric(38,2)) as percent_of_patients +, count(distinct person_id) as total_patients +, cast(count(distinct person_id) * 100.0 / (select count(distinct person_id) from core.patient) as numeric(38,2)) as percent_of_patients from chronic_conditions.tuva_chronic_conditions_long group by 1 order by 3 desc @@ -101,8 +101,8 @@ In this query we show how often each chronic condition occurs in the patient pop select condition_category , condition -, count(distinct patient_id) as total_patients -, cast(count(distinct patient_id) * 100.0 / (select count(distinct patient_id) from core.patient) as numeric(38,2)) as percent_of_patients +, count(distinct person_id) as total_patients +, cast(count(distinct person_id) * 100.0 / (select count(distinct person_id) from core.patient) as numeric(38,2)) as percent_of_patients from chronic_conditions.cms_chronic_conditions_long group by 1,2 order by 4 desc @@ -117,22 +117,22 @@ In this query we show how many patients have 0 chronic conditions, how many pati ```sql with patients as ( -select patient_id +select person_id from core.patient ) , conditions as ( select distinct - a.patient_id + a.person_id , b.condition from patients a left join chronic_conditions.tuva_chronic_conditions_long b - on a.patient_id = b.patient_id + on a.person_id = b.person_id ) , condition_count as ( select - patient_id + person_id , count(distinct condition) as condition_count from conditions group by 1 @@ -141,7 +141,7 @@ group by 1 select condition_count , count(1) -, cast(100 * count(distinct patient_id)/sum(count(distinct patient_id)) over() as numeric(38,1)) as percent +, cast(100 * count(distinct person_id)/sum(count(distinct person_id)) over() as numeric(38,1)) as percent from condition_count group by 1 order by 1 diff --git a/docs/data-marts/cms-hccs.md b/docs/data-marts/cms-hccs.md index 77fecbfb..0f0740f9 100644 --- a/docs/data-marts/cms-hccs.md +++ b/docs/data-marts/cms-hccs.md @@ -26,7 +26,7 @@ In the diagram below we provide an overview explanation of how the data mart wor In order to run the CMS-HCC data mart you need to map the following data elements to the [Input Layer](../connectors/input-layer). These are the only data elements required. **Eligibility:** -- patient_id +- person_id - gender - birth_date - death_date @@ -40,7 +40,7 @@ In order to run the CMS-HCC data mart you need to map the following data element - claim_id - claim_line_number - claim_type -- patient_id +- person_id - claim_start_date - claim_end_date - bill_type_code @@ -102,7 +102,7 @@ and payment risk score for each enrollee in the payment year. ```sql select - count(distinct patient_id) as patient_count + count(distinct person_id) as patient_count , avg(blended_risk_score) as average_blended_risk_score , avg(normalized_risk_score) as average_normalized_risk_score , avg(payment_risk_score) as average_payment_risk_score @@ -121,7 +121,7 @@ select , avg(risk.payment_risk_score) as average_payment_risk_score from cms_hcc.patient_risk_scores as risk inner join core.patient as patient - on risk.patient_id = patient.patient_id + on risk.person_id = patient.person_id group by patient.state , patient.city diff --git a/docs/data-marts/ed-classification.md b/docs/data-marts/ed-classification.md index e33d5510..b6b1f624 100644 --- a/docs/data-marts/ed-classification.md +++ b/docs/data-marts/ed-classification.md @@ -60,7 +60,7 @@ order by visit_count desc; ```sql with encounter as ( select - e.patient_id + e.person_id , left(year_month,4) as year_nbr , data_source , count(distinct e.encounter_id) as potentially_preventable @@ -73,7 +73,7 @@ with encounter as ( , 'Non-Emergent' , 'Emergent, ED Care Needed, Preventable/Avoidable') group by - e.patient_id + e.person_id , data_source , left(year_month,4) ) @@ -82,7 +82,7 @@ with encounter as ( select distinct data_source , left(year_month,4) as year_nbr - , patient_id + , person_id from financial_pmpm.pmpm_prep pmpm ) @@ -97,7 +97,7 @@ from member_year as my left join encounter as enc on my.year_nbr = enc.year_nbr and enc.data_source = my.data_source - and enc.patient_id = my.patient_id + and enc.person_id = my.person_id group by my.data_source , my.year_nbr; @@ -227,18 +227,18 @@ order by with visits as ( select data_source - , patient_id + , person_id , count(*) as ed_visits from core.encounter where encounter_type = 'emergency department' group by data_source - , patient_id + , person_id ) , members as ( select distinct - patient_id + person_id , data_source from financial_pmpm.member_months ) @@ -250,12 +250,12 @@ with visits as ( , members_with_visits as ( select - m.patient_id + m.person_id , m.data_source , coalesce(v.ed_visits,0) as ed_visits from members m left join visits v - on m.patient_id = v.patient_id + on m.person_id = v.person_id and m.data_source = v.data_source ) @@ -367,23 +367,23 @@ Since members often have more than one chronic condition, encounters are duplica ```sql with chronic_condition_members as ( select distinct - patient_id + person_id from chronic_conditions.tuva_chronic_conditions_long ) , chronic_conditions as ( - select patient_id + select person_id , condition from chronic_conditions.tuva_chronic_conditions_long union - select p.patient_id + select p.person_id , 'No Chronic Conditions' as condition from core.patient p left join chronic_condition_members ccm - on p.patient_id=ccm.patient_id - where ccm.patient_id is null + on p.person_id=ccm.person_id + where ccm.person_id is null ) select @@ -393,7 +393,7 @@ select , cast(sum(e.paid_amount)/count(*) as decimal(18,2))as paid_per_visit from core.encounter e left join chronic_conditions cc - on e.patient_id = cc.patient_id + on e.person_id = cc.person_id where encounter_type = 'emergency department' group by cc.condition order by visit_count desc; diff --git a/docs/data-marts/encounter-types.md b/docs/data-marts/encounter-types.md index a41a8c90..6ae75ff7 100644 --- a/docs/data-marts/encounter-types.md +++ b/docs/data-marts/encounter-types.md @@ -77,7 +77,7 @@ The date field used in the encounter algorithm is determined using the following ### Inpatient -Inpatient encounters are created when an institutional claim with the service category corresponding to one of the inpatient encounter types occurs. The Date/NPI continuity algorithm checks if a claim overlaps with another claim, with the same facility NPI, patient_id, and data_source. It also adds a specific check for the case where the end date and start date of two claims are within a day, checking if the discharge disposition code is 30 (still patient). This logic is in place to avoid grouping together claims where a patient is discharged and readmitted on the same day. +Inpatient encounters are created when an institutional claim with the service category corresponding to one of the inpatient encounter types occurs. The Date/NPI continuity algorithm checks if a claim overlaps with another claim, with the same facility NPI, person_id, and data_source. It also adds a specific check for the case where the end date and start date of two claims are within a day, checking if the discharge disposition code is 30 (still patient). This logic is in place to avoid grouping together claims where a patient is discharged and readmitted on the same day. Each inpatient encounter type is listed below with the algorithm, anchor, and anchor claim type. @@ -117,7 +117,7 @@ These claims would not be joined together since the discharge code indicates the ### Outpatient -Most outpatient encounters are formed with the combination of a patient_id, data_source, and date, with the exception being radiology, which contains only the claim lines associated with a specific imaging code. This will group together the institutional claim for the imaging event, and the professional claim with the read. This can then be used for rate analysis and compared to other sites of service (including professional locations). +Most outpatient encounters are formed with the combination of a person_id, data_source, and date, with the exception being radiology, which contains only the claim lines associated with a specific imaging code. This will group together the institutional claim for the imaging event, and the professional claim with the read. This can then be used for rate analysis and compared to other sites of service (including professional locations). diff --git a/docs/data-marts/financial-pmpm.md b/docs/data-marts/financial-pmpm.md index 93887c81..997c2057 100644 --- a/docs/data-marts/financial-pmpm.md +++ b/docs/data-marts/financial-pmpm.md @@ -15,10 +15,10 @@ The Financial PMPM data mart computes member months and stratifies population pa ### pmpm_prep -A table that computes all the paid and allowed statistics for every patient_id and year_month combination. +A table that computes all the paid and allowed statistics for every person_id and year_month combination. **Primary Keys:** - * patient_id + * person_id * year_month * plan * data_source @@ -107,7 +107,7 @@ with member_month as ( , cast(sum(mc.paid_amount) as decimal(18, 2)) as paid_amount from core.medical_claim as mc inner join core.member_months as mm - on mc.patient_id = mm.patient_id + on mc.person_id = mm.person_id and mc.data_source = mm.data_source and to_char(mc.claim_start_date, 'yyyymm') = mm.year_month group by @@ -144,41 +144,41 @@ Here we calculate PMPM by chronic condition. Since members can and do have more ```sql with chronic_condition_members as ( select distinct - patient_id + person_id from chronic_conditions.tuva_chronic_conditions_long ) , chronic_conditions as ( select - patient_id + person_id , condition from chronic_conditions.tuva_chronic_conditions_long union select - p.patient_id + p.person_id , 'No Chronic Conditions' as condition from core.patient as p left join chronic_condition_members as ccm - on p.patient_id = ccm.patient_id - where ccm.patient_id is null + on p.person_id = ccm.person_id + where ccm.person_id is null ) , medical_claims as ( select mc.data_source - , mc.patient_id + , mc.person_id , to_char(mc.claim_start_date, 'yyyymm') as year_month , cast(sum(mc.paid_amount) as decimal(18, 2)) as paid_amount from core.medical_claim as mc inner join core.member_months as mm - on mc.patient_id = mm.patient_id + on mc.person_id = mm.person_id and mc.data_source = mm.data_source and to_char(mc.claim_start_date, 'yyyymm') = mm.year_month group by mc.data_source - , mc.patient_id + , mc.person_id , to_char(mc.claim_start_date, 'yyyymm') ) @@ -190,9 +190,9 @@ select , cast(sum(mc.paid_amount) / count(*) as decimal(18, 2)) as medical_pmpm from core.member_months as mm left join chronic_conditions as cc - on mm.patient_id = cc.patient_id + on mm.person_id = cc.person_id left join medical_claims as mc - on mm.patient_id = mc.patient_id + on mm.person_id = mc.person_id and mm.year_month = mc.year_month and mm.data_source = mc.data_source group by diff --git a/docs/data-marts/hcc-suspecting.md b/docs/data-marts/hcc-suspecting.md index c078effe..ffef3083 100644 --- a/docs/data-marts/hcc-suspecting.md +++ b/docs/data-marts/hcc-suspecting.md @@ -97,7 +97,7 @@ order by reason; ```sql select - patient_id + person_id , patient_birth_date , patient_age , patient_sex diff --git a/docs/data-marts/pharmacy.md b/docs/data-marts/pharmacy.md index 2c3a5e6b..26cbbb6d 100644 --- a/docs/data-marts/pharmacy.md +++ b/docs/data-marts/pharmacy.md @@ -81,22 +81,22 @@ with pharmacy_claim as ( select data_source - , patient_id + , person_id , to_char(paid_date, 'YYYYMM') AS year_month , cast(sum(paid_amount) as decimal(18,2)) AS paid_amount from core.pharmacy_claim GROUP BY data_source -, patient_id +, person_id , to_char(paid_date, 'YYYYMM') ) select mm.data_source , mm.year_month -, sum(case when mc.patient_id is not null then 1 else 0 end) as members_with_claims +, sum(case when mc.person_id is not null then 1 else 0 end) as members_with_claims , count(*) as total_member_months -, cast(sum(case when mc.patient_id is not null then 1 else 0 end) / count(*) as decimal(18,2)) as percent_members_with_claims +, cast(sum(case when mc.person_id is not null then 1 else 0 end) / count(*) as decimal(18,2)) as percent_members_with_claims from core.member_months mm -left join pharmacy_claim mc on mm.patient_id = mc.patient_id +left join pharmacy_claim mc on mm.person_id = mc.person_id and mm.data_source = mc.data_source and @@ -115,25 +115,25 @@ order by data_source with pharmacy_claim as ( select data_source - , patient_id + , person_id , cast(sum(paid_amount) as decimal(18,2)) AS paid_amount from core.pharmacy_claim GROUP BY data_source -, patient_id +, person_id ) , members as ( -select distinct patient_id +select distinct person_id ,data_source from core.member_months ) select mm.data_source -,sum(case when mc.patient_id is not null then 1 else 0 end) as members_with_claims +,sum(case when mc.person_id is not null then 1 else 0 end) as members_with_claims ,count(*) as members -,sum(case when mc.patient_id is not null then 1 else 0 end) / count(*) as percentage_with_claims +,sum(case when mc.person_id is not null then 1 else 0 end) / count(*) as percentage_with_claims from members mm -left join pharmacy_claim mc on mc.patient_id = mm.patient_id +left join pharmacy_claim mc on mc.person_id = mm.person_id and mc.data_source = mm.data_source group by mm.data_source @@ -148,11 +148,11 @@ group by mm.data_source ```sql select mc.data_source - , sum(case when mm.patient_id is not null then 1 else 0 end) as claims_with_enrollment + , sum(case when mm.person_id is not null then 1 else 0 end) as claims_with_enrollment , count(*) as claims - , cast(sum(case when mm.patient_id is not null then 1 else 0 end) / count(*) as decimal(18,2)) as percentage_claims_with_enrollment + , cast(sum(case when mm.person_id is not null then 1 else 0 end) / count(*) as decimal(18,2)) as percentage_claims_with_enrollment from core.pharmacy_claim mc -left join core.member_months mm on mc.patient_id = mm.patient_id +left join core.member_months mm on mc.person_id = mm.person_id and mc.data_source = mm.data_source and diff --git a/docs/data-marts/quality-measures.md b/docs/data-marts/quality-measures.md index fa59f3aa..666ded6c 100644 --- a/docs/data-marts/quality-measures.md +++ b/docs/data-marts/quality-measures.md @@ -107,7 +107,7 @@ order by performance_rate desc select measure_id , exclusion_reason - , count(patient_id) as patient_count + , count(person_id) as patient_count from quality_measures.summary_long where exclusion_flag = 1 group by diff --git a/docs/data-marts/readmissions.md b/docs/data-marts/readmissions.md index 008643b9..b3c572db 100644 --- a/docs/data-marts/readmissions.md +++ b/docs/data-marts/readmissions.md @@ -53,12 +53,12 @@ The Hospital-wide Measure can be implemented on either EHR data or claims data. The data elements needed to process the readmission measure are listed below. - patient - - patient_id + - person_id - gender - birth_date - encounter - encounter_id - - patient_id + - person_id - encounter_start_date - encounter_end_date - discharge_disposition_code @@ -207,7 +207,7 @@ The `readmission_summary` table is at the encounter grain, but we exclude encoun **Foreign Keys:** - encounter_id (join to core.encounter) -- patient_id (join to core.patient) +- person_id (join to core.patient) diff --git a/docs/data-quality/atomic-level.md b/docs/data-quality/atomic-level.md index 51c8fd2d..90722aa6 100644 --- a/docs/data-quality/atomic-level.md +++ b/docs/data-quality/atomic-level.md @@ -41,19 +41,19 @@ from data_quality.primary_key_check In the example above the pharmacy_claim table has 100 distinct claims that have multiple records with the same values for the primary key fields. If any result in this table is non-zero you need to correct the mapping to fix it. -### Patient ID +### Person ID -The patient is at the center of the vast majority of the analyses we're interested in. Therefore it's important that we check a few things related to the `patient_id` field on every medical claim, specifically: +The patient is at the center of the vast majority of the analyses we're interested in. Therefore it's important that we check a few things related to the `person_id` field on every medical claim, specifically: -1. Does every line on each claim have a value for `patient_id` populated? -2. Is there more than one value for `patient_id` within a single claim (there shouldn't be)? -3. Does the `patient_id` value indicated on the claim have corresponding valid eligibility during the time period when claim was rendered? +1. Does every line on each claim have a value for `person_id` populated? +2. Is there more than one value for `person_id` within a single claim (there shouldn't be)? +3. Does the `person_id` value indicated on the claim have corresponding valid eligibility during the time period when claim was rendered? -The `medical_claim_patient_id` table verifies whether any of these data quality problems occur in the `medical_claim` table. You can query it as follows: +The `medical_claim_person_id` table verifies whether any of these data quality problems occur in the `medical_claim` table. You can query it as follows: ```sql select * -from data_quality.medical_claim_patient_id +from data_quality.medical_claim_person_id ``` This query returns the number of unique claim IDs that have each of these data quality problems. @@ -62,8 +62,8 @@ This query returns the number of unique claim IDs that have each of these data q In the example table above we observe the following: -1. patient_id is populated for every single record in the medical_claim table -2. 50 claim IDs have more than 1 patient_id. This can occur when two or more distinct lines on the claim have different values for patient_id. +1. person_id is populated for every single record in the medical_claim table +2. 50 claim IDs have more than 1 person_id. This can occur when two or more distinct lines on the claim have different values for person_id. 3. 1,000 claim IDs are considered "orphaned claims". This means that the claim_start_date or claim_end_date occur during a month when the patient does not have insurance eligibility. If any of these problems occur in your data you should attempt to correct them in mapping. However the specific techniques to do this will vary by dataset and it may not be possible to correct the problems. If the problems can't be correct we still include these records in the dataset, but there will be limitations in terms of how useful they are for analytics. @@ -254,19 +254,19 @@ select * from data_quality.primary_keys ``` -### Patient ID +### Person ID -Similar to the medical_claim table, the patient is at the center of the vast majority of the analyses we're interested in. Therefore it's important that we check a few things related to the `patient_id` field on every pharmacy claim, specifically: +Similar to the medical_claim table, the patient is at the center of the vast majority of the analyses we're interested in. Therefore it's important that we check a few things related to the `person_id` field on every pharmacy claim, specifically: -1. Does every line on each claim have a value for `patient_id` populated? -2. Is there more than one value for `patient_id` within a single claim? -3. Does the `patient_id` value indicated on the claim have corresponding valid eligibility during the time period when claim was rendered? +1. Does every line on each claim have a value for `person_id` populated? +2. Is there more than one value for `person_id` within a single claim? +3. Does the `person_id` value indicated on the claim have corresponding valid eligibility during the time period when claim was rendered? -The `pharmacy_claim_patient_id` table verifies whether any of these data quality problems occur in the `pharmacy_claim` table. You can query it as follows: +The `pharmacy_claim_person_id` table verifies whether any of these data quality problems occur in the `pharmacy_claim` table. You can query it as follows: ```sql select * -from data_quality.pharmacy_claim_patient_id +from data_quality.pharmacy_claim_person_id ``` This query returns a table with one row per check and the count of unique claim IDs that have that particular data quality issue @@ -275,8 +275,8 @@ This query returns a table with one row per check and the count of unique claim In the example table above we observe the following: -1. patient_id is populated for every single record in the pharmacy_claim table -2. 50 claim IDs have more than 1 patient_id. This can occur when two or more distinct lines on the claim have different values for patient_id. +1. person_id is populated for every single record in the pharmacy_claim table +2. 50 claim IDs have more than 1 person_id. This can occur when two or more distinct lines on the claim have different values for person_id. 3. 1,000 claim IDs are considered "orphaned claims". This means that the paid_date or the dispensing_date occurs during a month when the patient does not have insurance eligibility. If any of these problems occur in your data you should attempt to correct them in mapping. However the specific techniques to do this will vary by dataset and it may not be possible to correct the problems. If the problems can't be correct we still include these records in the dataset, but there will be limitations in terms of how useful they are for analytics. @@ -419,23 +419,23 @@ from data_quality.primary_key_check In the example above the pharmacy_claim table has 100 distinct claims that have multiple records with the same values for the primary key fields. If any result in this table is non-zero you need to correct the mapping to fix it. -### Patient ID +### Person ID -Does every row of eligibility have a `patient_id` populated? +Does every row of eligibility have a `person_id` populated? -The `eligibility_missing_patient_id` table verifies whether any rows do not have a `patient_id`. You can query it as follows: +The `eligibility_missing_person_id` table verifies whether any rows do not have a `person_id`. You can query it as follows: ```sql select * -from data_quality.eligibility_missing_patient_id +from data_quality.eligibility_missing_person_id ``` -This query returns the number of rows in the eligibility table that do not have a `patient_id`. If this number is greater than 0, +This query returns the number of rows in the eligibility table that do not have a `person_id`. If this number is greater than 0, you need to correct the mapping to fix it. ![Eligibility Patient ID](/img/data_quality_eligibility_patient_id.jpg) -In the example table above we observe that all rows in the source data have a `patient_id`. +In the example table above we observe that all rows in the source data have a `person_id`. ### Date Fields diff --git a/docs/getting-started/mapping-guide.md b/docs/getting-started/mapping-guide.md index 95981c70..326da8e4 100644 --- a/docs/getting-started/mapping-guide.md +++ b/docs/getting-started/mapping-guide.md @@ -547,7 +547,7 @@ is consistent across all lines for a given `claim_id`.
Primary Key -- The primary key for the pharmacy_claim table is patient_id, enrollment_start_date, enrollment_end_date, and data_source. +- The primary key for the pharmacy_claim table is person_id, member_id, enrollment_start_date, enrollment_end_date, and data_source. - There are two commonly used data formats for eligibility (also known as enrollment) data: the eligibility span format and the member month format. - The eligibility span format has one record per member eligibility span. An eligibility span is a time period when a member was enrolled with and therefore had insurance coverage by a health plan. An eligibility span has a start date and an end date. A person can have multiple eligibility spans. - The member month format has one record per member per month of enrollment. For example, a person with a single eligibility span from 1/1/2020 through 3/31/2020 would have a single eligibility span record, but 3 member month records, one for each month. diff --git a/docs/guides/data-source-setup/mapping.md b/docs/guides/data-source-setup/mapping.md index 4f75dca4..27f6478d 100644 --- a/docs/guides/data-source-setup/mapping.md +++ b/docs/guides/data-source-setup/mapping.md @@ -547,7 +547,7 @@ is consistent across all lines for a given `claim_id`.
Primary Key -- The primary key for the pharmacy_claim table is patient_id, enrollment_start_date, enrollment_end_date, and data_source. +- The primary key for the pharmacy_claim table is person_id, member_id, enrollment_start_date, enrollment_end_date, and data_source. - There are two commonly used data formats for eligibility (also known as enrollment) data: the eligibility span format and the member month format. - The eligibility span format has one record per member eligibility span. An eligibility span is a time period when a member was enrolled with and therefore had insurance coverage by a health plan. An eligibility span has a start date and an end date. A person can have multiple eligibility spans. - The member month format has one record per member per month of enrollment. For example, a person with a single eligibility span from 1/1/2020 through 3/31/2020 would have a single eligibility span record, but 3 member month records, one for each month. diff --git a/docs/knowledge/claims-data-fundamentals/member-months.md b/docs/knowledge/claims-data-fundamentals/member-months.md index 2ce71fd9..7fbef1d9 100644 --- a/docs/knowledge/claims-data-fundamentals/member-months.md +++ b/docs/knowledge/claims-data-fundamentals/member-months.md @@ -23,7 +23,7 @@ In this section we use an example to describe how to calculate member months. T To calculate member months, you need to convert each patient's eligibility record (with start and end dates) into multiple records, with one record for each month of eligibility. Let's take an example. Suppose member A1234 has coverage from Aetna from January 1st to June 15th of 2022. They lose coverage on June 16th and they regain coverage on August 10th. Further suppose member B2468 has coverage from January 1st through the entire year of 2022. These two members would have eligibility spans that look like the data below: -| patient_id | payer | enrollment_start_date | enrollment_end_date | +| person_id | payer | enrollment_start_date | enrollment_end_date | | --- | --- | --- | --- | | A1234 | Aetna | 01-01-2022 | 06-15-2022 | | A1234 | Aetna | 08-10-2022 | | @@ -41,7 +41,7 @@ Partial eligibility occurs whenever a patient does not have eligibility for an e After converting the above enrollment spans to member months (e.g. by using the SQL at the end of this section), the data would look like this: -| patient_id | year_month | payer | +| person_id | year_month | payer | | --- | --- | --- | | A1234 | 2022-01 | Aetna | | A1234 | 2022-02 | Aetna | diff --git a/docs/knowledge/hospital-readmissions.md b/docs/knowledge/hospital-readmissions.md index 46a28996..fd84166b 100644 --- a/docs/knowledge/hospital-readmissions.md +++ b/docs/knowledge/hospital-readmissions.md @@ -46,12 +46,12 @@ The Hospital-wide Measure can be implemented on either EHR data or claims data. The data elements needed to process the readmission measure are listed below. - patient - - patient_id + - person_id - gender - birth_date - encounter - encounter_id - - patient_id + - person_id - encounter_start_date - encounter_end_date - discharge_disposition_code From 28a6991f7e1962b75b9ba1580b50231a441a188e Mon Sep 17 00:00:00 2001 From: sarah-tuva Date: Wed, 11 Dec 2024 15:48:14 -0700 Subject: [PATCH 2/4] Add new person_id_crosswalk to core data model --- docs/core-data-model/person_id_crosswalk.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 docs/core-data-model/person_id_crosswalk.md diff --git a/docs/core-data-model/person_id_crosswalk.md b/docs/core-data-model/person_id_crosswalk.md new file mode 100644 index 00000000..760b1a7e --- /dev/null +++ b/docs/core-data-model/person_id_crosswalk.md @@ -0,0 +1,19 @@ +--- +id: patient +title: "Patient" +--- + +import { JsonDataTable } from '@site/src/components/JsonDataTable'; + +The person_id_crosswalk table contains all source patient identifiers from +the input layer for claims and/or clinical. + +**Primary Keys:** + * person_id + * patient_id + * member_id + * payer + * plan + * data_source + + From c419b0df560b0817df7f1ac6b2035977099555ed Mon Sep 17 00:00:00 2001 From: sarah-tuva Date: Wed, 11 Dec 2024 16:54:21 -0700 Subject: [PATCH 3/4] Add new person_id mapping --- docs/connectors/input-layer.md | 7 +++++++ docs/getting-started/mapping-guide.md | 13 +++++++++++++ docs/guides/data-source-setup/mapping.md | 3 ++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/connectors/input-layer.md b/docs/connectors/input-layer.md index f98b8016..bb2222ca 100644 --- a/docs/connectors/input-layer.md +++ b/docs/connectors/input-layer.md @@ -54,6 +54,10 @@ The pharmacy_claim table includes information about retail and specialty drug pr +### person_id +A new patient identifier field named `person_id` has been added to the Tuva data model for both claims and clinical sources. This is a required field and cannot be null. If you bought the Tuva MPI Engine or have your own patient matching solution, this field should be populated with the UUID (Universally Unique Identifier). If you do not have a UUID, we recommend mapping the source patient identifier to this field (`member_id` for claims, patient_id for `clincal`). + + ## Clinical Input ### condition @@ -167,3 +171,6 @@ The procedure table contains information on procedures that were performed on pa * practitioner_id + +### person_id +A new patient identifier field named `person_id` has been added to the Tuva data model for both claims and clinical sources. This is a required field and cannot be null. If you bought the Tuva MPI Engine or have your own patient matching solution, this field should be populated with the UUID (Universally Unique Identifier). If you do not have a UUID, we recommend mapping the source patient identifier to this field (`member_id` for claims, patient_id for `clincal`). diff --git a/docs/getting-started/mapping-guide.md b/docs/getting-started/mapping-guide.md index 326da8e4..92039cf1 100644 --- a/docs/getting-started/mapping-guide.md +++ b/docs/getting-started/mapping-guide.md @@ -145,6 +145,11 @@ consistent across all lines for a given `claim_id`. +#### person_id +A new patient identifier field named `person_id` has been added to the Tuva data model for both claims and clinical sources. This is a required field and cannot be null. If you bought the Tuva MPI Engine or have your own patient matching solution, this field should be populated with the UUID (Universally Unique Identifier). If you do not have a UUID, we recommend mapping the source patient identifier to this field (`member_id` for claims, patient_id for `clincal`). + + + #### plan This field is a string that links every row to the name of the health plan. @@ -446,6 +451,11 @@ consistent across all lines for a given `claim_id`. +#### person_id +A new patient identifier field named `person_id` has been added to the Tuva data model for both claims and clinical sources. This is a required field and cannot be null. If you bought the Tuva MPI Engine or have your own patient matching solution, this field should be populated with the UUID (Universally Unique Identifier). If you do not have a UUID, we recommend mapping the source patient identifier to this field (`member_id` for claims, patient_id for `clincal`). + + + #### plan This field is a string that links every row to the name of the health plan. @@ -544,6 +554,9 @@ is consistent across all lines for a given `claim_id`. ### eligibility +#### person_id +A new patient identifier field named `person_id` has been added to the Tuva data model for both claims and clinical sources. This is a required field and cannot be null. If you bought the Tuva MPI Engine or have your own patient matching solution, this field should be populated with the UUID (Universally Unique Identifier). If you do not have a UUID, we recommend mapping the source patient identifier to this field (`member_id` for claims, patient_id for `clincal`). +
Primary Key diff --git a/docs/guides/data-source-setup/mapping.md b/docs/guides/data-source-setup/mapping.md index 27f6478d..c41c9587 100644 --- a/docs/guides/data-source-setup/mapping.md +++ b/docs/guides/data-source-setup/mapping.md @@ -557,4 +557,5 @@ is consistent across all lines for a given `claim_id`. ## Clinical Input Layer - +#### person_id +A new patient identifier field named `person_id` has been added to the Tuva data model for both claims and clinical sources. This is a required field and cannot be null. If you bought the Tuva MPI Engine or have your own patient matching solution, this field should be populated with the UUID (Universally Unique Identifier). If you do not have a UUID, we recommend mapping the source patient identifier to this field (`member_id` for claims, patient_id for `clincal`). From 9ccb226c23339349cc7dbd026817bb54b272ba5b Mon Sep 17 00:00:00 2001 From: sarah-tuva Date: Thu, 12 Dec 2024 13:54:50 -0700 Subject: [PATCH 4/4] Add person_id_crosswalk to sidebar --- docs/core-data-model/person_id_crosswalk.md | 4 ++-- sidebars.js | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/core-data-model/person_id_crosswalk.md b/docs/core-data-model/person_id_crosswalk.md index 760b1a7e..08f28479 100644 --- a/docs/core-data-model/person_id_crosswalk.md +++ b/docs/core-data-model/person_id_crosswalk.md @@ -1,6 +1,6 @@ --- -id: patient -title: "Patient" +id: person_id_crosswalk +title: "Person ID Crosswalk" --- import { JsonDataTable } from '@site/src/components/JsonDataTable'; diff --git a/sidebars.js b/sidebars.js index 8a235927..4ba2fa95 100644 --- a/sidebars.js +++ b/sidebars.js @@ -63,6 +63,7 @@ const sidebars = "core-data-model/medication", "core-data-model/observation", "core-data-model/patient", + "core-data-model/person_id_crosswalk", "core-data-model/pharmacy-claim", "core-data-model/practitioner", "core-data-model/procedure",