-
Notifications
You must be signed in to change notification settings - Fork 25
Cooking with CQL Q&A Index Measure Logic in CQL Category
AgeInYearsAt(): Which is recommended; use patient directly or patient.birthdatetime? (Session 29 - 10/25/18)
- For the simplest case of determining the age of the patient in years, use the
AgeInYearsAt()
function directly.
Allergy vs Allergy Intolerance - Diagnosis: Why are we using diagnosis to represent allergy instead of allergy intolerance? (Session 16 - 7/20/17)
- The QDM supports the description of an allergy/intolerance to provide more detailed information than is available in a Diagnosis alone. However, this flexibility means there is the potential for underlying systems to provide the data as both a Diagnosis or as an Allergy/Intolerance. Measure authors can express the allergy in both ways to cover this possibility. For example, to address the type of reaction that meets the measure criteria, the measure can indicate “Diagnosis: Anaphylactic reaction to penicillin” using a precoordinated SNOMED CT concept, or use a post-coordinated approach “Allergy/Intolerance: Penicillin (type: anaphylaxis).” The latter approach may be more consistent with the way an allergy or intolerance is managed using non-measure transactions in HL7 V2, V3, and FHIR, except that FHIR uses the metadata element “reaction” to address the QDM attribute “type.”
Ambulatory Numerator: In the example below, N (line 8) is the alias of Ambulatory Numerator. Does that definition return a list of the dates?
define "Ambulatory Numerator Days":
"Ambulatory Numerator" N
return date from start of N.relevantPeriod
define OneEncounterPerDay:
"Ambulatory Numerator Days" D
return Last(
"Ambulatory Numerator" N
where N.relevantPeriod starts same day as D
sort by end of relevantPeriod
)
(Session 43 - 4/23/20)
define "Ambulatory Numerator Days":
"Ambulatory Numerator" N
return date from start of N.relevantPeriod
define OneEncounterPerDay:
"Ambulatory Numerator Days" D
return Last(
"Ambulatory Numerator" N
where N.relevantPeriod starts same day as D
sort by end of relevantPeriod
)
- Ambulatory Numerator is an alias in the CQL using list of elements, each described by a QDM “Encounter, Performed”. In the first line of the example, the Ambulatory Numerator Days definition is used to range over the days that had an encounter that ended. Since we are dealing with ambulatory, it’s unlikely that the encounter will be more than one day, but it is a possibility.
Ambulatory Numerator: When using the Quality Data Model (QDM) 5.5 as shown in the example, does this return a date?(Session 43 - 4/23/20)
define "Ambulatory Numerator Days":
"Ambulatory Numerator" N
return date from start of N.relevantPeriod
- Yes, the return is saying for every entry in the "Ambulatory Numerator" N input, return this date from start of N.relevantPeriod output. Since the Ambulatory Numerator is a list of encounters, this expression will be evaluated for each encounter in that list so you’ll get the dates. The result of that expression is then a list of System.Date as shown in the popup:
define "Ambulatory Numerator Days":
"Ambulatory Numerator" N
return date from start of N.relevantPeriod
list<System.Date>
Attribute Result vs Attribute Component: I see there is an attribute result. How does this differ from the attribute component? (Session 25 - 5/31/18)
- The attribute component is the list of results. This example illustrates that. For example, a diagnostic study performed may have a single result or a result and a code. It is a way to represent both components within the QDM datatype.
library StudyComponents
using QDM version '5.3'
valueset "Macular Exam": '1.1' // { ME001: Macular Exam }
valueset "Retinopathy Severity Finding": '2.1' // { F001: Retinopathy Severity }
valueset "Level of Severity of Retinopathy Findings": '3.1' // { Mild: Mild Retinopathy, Moderate: Moderate Retinopathy, Severe: Severe Retinopathy }
valueset "Macular Edema Finding": '2.2' // { F002: Macular Edema Finding }
valueset "Macular Edema Findings Absent": '3.2' // { Absent: No macular edema findings }
valueset "Macular Edema Findings Present": '3.3' // { Present: Macular edema findings present }
parameter "Measurement Period" Interval<DateTime>
context Patient
define "Appropriate Macular Exam":
["Diagnostic Study, Performed": "Macular Exam"] Study
where exists ( Study.components component1
where component1.code in "Macular Exam"
and component1.result in "Level of Severity of Retinopathy Findings"
)
and exists ( Study.components component2
where component2.code in "Macular Exam"
and ( component2.result in "Macular Edema Findings Absent"
or component2.result in "Macular Edema Findings Present"
)
)
define "Retinopathy Findings":
["Diagnostic Study, Performed": "Macular Exam"] Study
where Study.result in "Level of Severity of Retinopathy Findings"
define "Macular Edema Findings":
["Diagnostic Study, Performed": "Macular Exam"] Study
where Study.result in "Macular Edema Findings Absent"
or Study.result in "Macular Edema Findings Present"
Blood Pressure as an Observation vs Component of an Observation: Is blood pressure identified as an observation or as a component of an observation? (Session 28 - 9/27/18)
- For blood pressure, there is a physical exam result or components result and the challenge depends on what you're looking for. It is a single observation, but it depends on how it is recorded.
CalculateAgeInYearsAt(): For the calculate age in years expression, do we have to add the date from patient birth time and the date from start of measurement period? (Session 29 - 10/25/18)
CalculateAgeInYearsAt(date from Patient.birthDatetime, date from start of "Measurement Period")
Change of Status from Outpatient to Inpatient: Does the logic shown cover a scenario where the patient goes from outpatient status directly to inpatient?
define function "Hospitalization with Observation"(Encounter "Encounter, Performed" ):
Encounter E
let
ObsVisit: Last(["Encounter, Performed": "Observation"] O
where O.relevantPeriod ends 1 hour or less on or before start of E.relevantPeriod
sort by end of relevantPeriod),
VisitStart: Coalesce(start of ObsVisit.relevantPeriod, start of E.relevantPeriod),
EDVisit: Last(["Encounter, Performed": "Emergency Department Visit"] ED
where ED.relevantPeriod ends 1 hour or less on or before VisitStart
sort by end of relevantPeriod
)
return Interval[Coalesce(start of EDVisit.relevantPeriod, VisitStart), end of E.RelevantPeriod]
(Session 28 - 7/26/18)
define function "Hospitalization with Observation"(Encounter "Encounter, Performed" ):
Encounter E
let
ObsVisit: Last(["Encounter, Performed": "Observation"] O
where O.relevantPeriod ends 1 hour or less on or before start of E.relevantPeriod
sort by end of relevantPeriod),
VisitStart: Coalesce(start of ObsVisit.relevantPeriod, start of E.relevantPeriod),
EDVisit: Last(["Encounter, Performed": "Emergency Department Visit"] ED
where ED.relevantPeriod ends 1 hour or less on or before VisitStart
sort by end of relevantPeriod
)
return Interval[Coalesce(start of EDVisit.relevantPeriod, VisitStart), end of E.RelevantPeriod]
- Yes, because there would be no observation or ED visit. The outpatient visit can be compared to the start of the encounter’s relevant period.
Coalesce with Data Types and Attributes: Did you have to use Coalesce since you are using two different data types or are the attributes the same? (Session 22 - 2/22/18)
- Coalesce is used when the attributes differ to give preference to a particular value if it is present. For Procedure, Performed, we have both an authorDatetime and a relevantPeriod, but for Immunization, Administered, we only have an authorDatetime, so the Coalesce in this case is saying “Use the start of the relevantPeriod if it’s present, otherwise use the authorDatetime.”
Coalesce Patterns: Is there a preferred pattern to use if not using Coalesce? (Session 22 - 2/22/18)
- It depends how often the definition needs to be used in subsequent logic. If the definition is used often, and the Coalesce pattern is required for each usage, then it makes sense to change the definition so that it returns the same kinds of tuples, so that subsequent references can just reference a single attribute and not have to use the Coalesce pattern.
Combining Several Definitions into 1: For the measure CMS646, Bladder Cancer (https://oncprojectracking.healthit.gov/support/browse/CQLIT-206), how do you express specific references for bladder cancer and combine several definitions into one? (Session 40 - 12/5/19)
- The clinical workflow presented by the measure developer is that bladder cancer is diagnosed and then the tumor is staged and coded with either Ta HG (noninvasive papillary carcinoma – high grade), Tis (carcinoma in situ), or T1 (tumor has spread to the connective tissue). Bacillus Calmette-Guerin (BCG) is the standard immunotherapy drug (regardless of tumor stage) for bladder cancer and will be administered up to six times, but for this measure we are only interested in the first administration. The intent of this measure is to assure that staging occurs prior to the first BCG administration. The measure only looks at the first BCG administration, not at BCG dose/frequency/etc., even if the staging occurred up to six months prior; we are interested in the first encounter after the bladder cancer diagnosis within the measurement period. Note, the diagnosis must overlap the measurement period. The first BCG given is associated with the staging and obviously the encounter. We are specifically checking that the BCG administered happened after the staging.
The suggested approach is to look for any qualifying encounter that occurred during the submission period and we define Qualifying Encounter, Initial Population, Bladder Cancer Staging, Bladder Cancer Diagnosis, and First BCG Administered as:
Qualifying Encounter:
define "Qualifying Encounter":
["Encounter, Performed": "Office Visit"] Encounter
where Encounter.relevantPeriod during "Measurement Period"
Initial Population:
define "Initial Population:
exists ( "Bladder Cancer Diagnosis" )
and "Most Recent Bladder Cancer Staging Tumor Ta HG, Tis, T1"
and exists "Qualifying Encounter"
Bladder Cancer Staging:
Define "Most Recent Bladder Cancer Staging Tumor Ta HG, Tis, T1":
"Bladder Cancer Staging".result ~ "T1: Tumor invades lamina propria or submucosa (finding)"
or "Bladder Cancer Staging".result ~ "Ta: Noninvasive papillary carcinoma (urinary tract) (finding)"
or "Bladder Cancer Staging".result in ( "Bladder Cancer Staging Tis for Urology Care" )
Bladder Cancer Diagnosis:
Define "Bladder Cancer Diagnosis":
["Diagnosis": "Bladder Cancer for Urology Care"] BladderCancer
where BladderCancer.prevalencePeriod starts same day or before
end "Measurement Period"
First BCG Administered:
define "First BCG Administered":
First(["Medication, Administered": "BCG Bacillus Calmette Guerin for Urology Care"] BCG
with "Bladder Cancer Diagnosis" BladderCancer
such that BCG.relevantPeriod starts 6 months or less after start BladderCancer.prevalencePeriod
and BCG.relevantPeriod overlaps "Measurement Period"
sort by start of relevantPeriod
)
Solutions:
- Use exists() function to provide Boolean (true/false) results for Initial Population definitions.
- Remove singleton from office visit expression since timing requirements addressed by other definitions.
- Use ~ equivalence function for code but use in() function to Value Set Authority Center object identifiers for tumor staging definition.
Computation of Measures/strong>:If there are differences regarding the computation of measures, can you walk through how the measure is computed and point out differences? (Session 23 - 3/29/18)
*We will add this as a topic for a future Cooking with CQL session.
Contraception.code: “Most or Moderately Effective Contraception Provided” Contraception Return Contraception.code This will return different types of contraceptives including counseling. Do they need to be listed independently or can a definition be used in the supplemental element? (Session 26 - 6/28/18)
- The supplemental data element definition can just return the code, even though that will, in general, return multiple different types of contraceptives. For each actual instance, the specific code in the reporting system will be returned. In a summary report, these would be aggregated by code. In an individual report, the data for this individual would be returned.
Datetime Return: What unit is returned in this example?
Define function “Arrival and Departure Time” (Encounter “Encounter, Performed”):
Interval
[
First(Encounter.facilityLocations Location
Return start of Location.locationPeriod sort ascending),
Last(Encounter.facilityLocations location
Return end of Location.locationPeriod sort ascending)
]
(Session 18 - 9/21/17)
Define function “Arrival and Departure Time” (Encounter “Encounter, Performed”):
Interval
[
First(Encounter.facilityLocations Location
Return start of Location.locationPeriod sort ascending),
Last(Encounter.facilityLocations location
Return end of Location.locationPeriod sort ascending)
]
- The interval would return a full Datetime, e.g., the first return would be locationPeriod: 10:30..11:21
Define Function: Can the ‘define function’ pattern be used to customize measures where an outpatient visit is not to be considered as an episode of care? (Session 28 - 7/26/18)
- Yes, in that case, you would use the Hospitalization with Observation function rather than the Hospitalization with Outpatient function. In addition, measures that did not consider observation status to be part of the episode of care would continue to use the current Hospitalization function.
Definitions vs Parameters: What is the difference between using definitions vs. parameters when expressing a measure? (Session 19 - 10/26/17)
- Parameters are external values that are provided when the measure is evaluated, whereas definitions are used to organize criteria within the measure.
Denominator in Patient-based and Non-Patient-based Measures: Is the statement, “The denominator is always a subset of the initial population, so the criteria entered to define ‘Initial Population’ does not have to be duplicated for define ‘Denominator’” only true for patient-based measures? (Session 24 - 4/26/18)
- No, it is true for both patient-based and non-patient based measures. However, for non-patient based measures, because the criteria expression has to return the same type as the rest of the measure population criteria, it is often easiest to just reference the “Initial Population”.
Diagnosis Appears in Both the Encounter Diagnosis and in the Present on Admission Indicator and a Diagnosis Record: In the example measure on Pressure Injury, how would the code for diagnosis display the information if the diagnosis appears in both the Encounter diagnosis and in the Present on Admission indicator and a diagnosis record? It seems that you would say there is a diagnosis record and it has the same code as the diagnosis code in the encounter diagnosis. (Session 36 - 6/27/19)
- When you’re talking about a pressure ulcer like this, the location is not necessarily in a pre-coordinated SNOMED term, it’s just pressure ulcer, but there are some ICD-10 codes that have a location attached. The Encounter diagnosis attribute includes some components, but it doesn’t specify anatomical location as a component. However, the CQL expression could reference a diagnosis with anatomical location = right (or left) and that diagnosis.id could be used to reference the Encounter diagnosis. Thus, the CQL can allow further definition of the Encounter diagnosis to address laterality, as needed, for this measure. Alternatively, you could use the pre-coordinated code (i.e., ICD-10 with location attached).
You can incorporate a definition for Pressure Injury Diagnosis and would name the anatomical location site with Pressure Injury Diagnosis as part of the New Pressure Injury measure.
[“Diagnosis”: “Pressure Injury”]
“Denominator” EncounterWithQualityingAge
with “Pressure Injury Diagnosis” PressureInjury
such that PressureInjury.prevalencePeriod during EncounterWithQualifyingAge.relevantPeriod
and exists (“Pressure Injury Diagnosis” SeparateInjury
where separateInjury.prevelancePeriod during EncounterWithQualifyingAge.relevancePeriod and
PressureInjury.anatomicalSiteLocation !~ SeparateInjury.anatomicalSiteLocation
Difference Between “Encounter With ED Visit Less Than Two Days” and “ED Visit Less Than Two Days”:: What is the difference in the query order between:
a) Define “Encounter With ED Visit Less Than Two Days”:
“Encounter with Ischemic Stroke” E
with “ED visit” ED
And
b) Define “ED Visit Less Than Two Days”:
“ED Visit” ED
with “Encounter With Ischemic Stroke” E
(Session 14 - 5/18/17)
a) Define “Encounter With ED Visit Less Than Two Days”:
“Encounter with Ischemic Stroke” E
with “ED visit” ED
b) Define “ED Visit Less Than Two Days”:
“ED Visit” ED
with “Encounter With Ischemic Stroke” E
- A. Query (a) is returning the inpatient encounters, not the ED visits. What should be counted in this measure is inpatient encounters. We are interested in a case where there was a prior ED visit to consider as part of the encounter. Query (b) is returning the ED visits immediately following an inpatient encounter.
Different Results That Have the Same Types of Values: Referring to the example that uses the code of each component within a Diagnostic Study to identify different results, would this mean an additional setup/implementation will be required for healthcare systems to "map" to these additional codes around a newly created component1 or component 2? (Session 18 - 9/21/17)
- If there is a need to distinguish different results that have the same types of values, then yes, there would need to be some way to map that content from the source system. However, for cases that do not need to distinguish different results (e.g., because the result values are precoordinated, so no two components could have the same result value), then the code layer can be ignored. It depends on the use case. The structure and logic support both approaches.
Encounter with Pressure Injury: CMS826v0 - Hospital Harm - Pressure Injury – How would you express an encounter with a new harmful pressure injury? (Session 40 - 12/5/19)
- Paraphrased description of the measure: This measure assesses the proportion of inpatient encounters of patients 18 years of age or older at admission, who have a pressure ulcer present on admission (POA) and suffer the harm of developing a new pressure injury (stage 2, stage 3, stage 4, deep tissue pressure injury, or nonstageable pressure injury) subsequent to admission. The measure does not consider the number of new pressure injuries per encounter, it is only concerned about a new pressure injury in patients admitted with an existing pressure injury. Thus, the measure must identify a pressure injury that is POA and a new pressure injury in a different anatomical location identified at least 24 hours after arrival. This new harmful pressure injury’s prevalence period overlaps, but starts after an existing pressure ulcer.
For this particular encounter, the measure is looking for the presence of an Encounter diagnosis consistent with codes in a specific value set ‘diagnosis: Pressure Ulcer Stage’ with a ‘Pressure injury stage’ (e.g., containing values: stage 2, stage 3, stage 4, nonstageable pressure ulcer, pressure injury of deep tissue). This approach will set up an alias for pressure injury POA where that diagnosis (harmful pressure injury) has a POA indicator. Next, we are looking for a ‘harmful pressure injury’ during the hospitalization period where the anatomical location site is not the same as the one that was POA and it starts more than 24 hours after the start of hospitalization.
Option 1 (using ‘let’):
define "Encounter With New Harmful Pressure Injury":
"Denominator" EncounterWithQualifyingAge
let PressureInjuryPOA:
"Harmful Pressure Injury" PressureInjury
where PressureInjury.prevalencePeriod
during "Hospitalization, Potentially Starting in Emergency Department and
or with Observation"(EncounterWithQualifyingAge)
and exists (
EncounterWithQualifyingAge.diagnoses EncounterDiagnosis
where EncounterDiagnosis.code ~ PressureInjury.code // Best
approximation in QDM, no way to link encounter diagnoses directly to Diagnosis elements
and EncounterDiagnosis.presentOnAdmissionIndicator ~ "y"
)
where exists ("Harmful Pressure Injury" PressureInjury
where PressureInjury.prevalencePeriod during "Hospitalization, Potentially Starting in Emergency
Department and or with Observation"(EncounterWithQualifyingAge)
and AllTrue(
PressureInjuryPOA POA
where PressureInjury.prevalencePeriod starts more than 24 hours after
start of "Hospitalization, Potentially Starting in Emergency Department and or with Observation"
(EncounterWithQualifyingAge)
and PressureInjury.anatomicalLocationSite !~
POA.anatomicalLocationSite
return true
)
)
Option 2 (using a ‘with’ statement in place of the ‘let’ and include a ‘such that’ statement, only if there is one condition):
define "Encounter With New Harmful Pressure Injury":
"Denominator" EncounterWithQualifyingAge
with (
"Harmful Pressure Injury" PressureInjury
where PressureInjury.prevalencePeriod
during "Hospitalization, Potentially Starting in Emergency Department and or with
Observation"(EncounterWithQualifyingAge)
and exists (
EncounterWithQualifyingAge.diagnoses EncounterDiagnosis
where EncounterDiagnosis.code ~ PressureInjury.code // Best
approximation in QDM, no way to link encounter diagnoses directly to Diagnosis elements
and EncounterDiagnosis.presentOnAdmissionIndicator ~ "y"
)
) PressureInjuryPOA
such that exists ("Harmful Pressure Injury" PressureInjury
where PressureInjury.prevalencePeriod during "Hospitalization,
Potentially Starting in Emergency Department and or with Observation"(EncounterWithQualifyingAge)
and AllTrue(
PressureInjuryPOA POA
where PressureInjury.prevalencePeriod starts more
than 24 hours after start of "Hospitalization, Potentially Starting in Emergency Department and or with Observation"
(EncounterWithQualifyingAge)
and PressureInjury.anatomicalLocationSite
!~ POA.anatomicalLocationSite
return true
)
)
The difference between the ‘with’ and ‘let’ is that the ‘let’ introduces “PressureInjuryPOA” so you can talk about it in multiple places throughout the query, whereas the ‘with’ only lets you talk about it within ‘such that’. If you need to talk about it in a subsequent ‘with’ or ‘where’ then the ‘let’ permits you to repeatedly talk about the same expression. The ‘with’ only references the Pressure Injury POA within the ‘such that’ condition. The scope of the ‘let’ variable goes on after the initial ‘where’ or filtering that is done. As far as performance, expressing it as a ‘with’ or a ‘let’ depends on how the underlying implementation decides to deal with it because it might translate into a ‘join’ in a structured query language database environment vs. an ‘apply’. It is up to the optimizer of the target system to determine how best to run it.
Regardless of whether the expression uses ‘let’ or ‘with’, the following issue may represent a challenge in testing and evaluating this measure. A potential challenge with this approach is the terminology used when recording an anatomical site. For example, if the anatomical location site is recorded as hip ulcer, but didn’t specify laterality (right or left) and then a new hip ulcer developed on the other hip, the straight code comparison here wouldn’t differentiate the two. Conversely, if the existing ulcer code indicates “greater trochanter,” and a separate reference to the same pressure ulcer used the code “hip,” the result might suggest there are two pressure ulcers when only one exists. Thus coding variation could lead to missing a new pressure ulcer or over-counting an existing pressure ulcer as newly developed. A possible solution would be to develop very specific value sets that distinguish the encounter.
Episode of Care - Measure 72: Is measure 72, which defines exceptions for antithrombotic therapy, an example that could be simplified in logic to reference an episode of care? (Session 9 - 11/17/16)
- Yes, it could reference an episode of care where the exclusions were associated with any encounter in that episode of care.
Estimation of Due Date: To estimate due date, do you take the return of a record, within physical exam performed estimated due date codes that would have access to all the actual fields and cast it to datetime? (Session 10 - 1/26/17)
- Yes. You can find further information about this example on the CQL Formatting and Usage Wiki - Cooking with CQL examples Link: https://github.com/esacinc/CQL-Formatting-and-Usage-Wiki/tree/master/Source/Cooking%20With%20CQL/10
“gestational age at birth”: When define “gestational age at birth”: 280 – (days between “Estimated Due Date” and “Time of Delivery”) div 7 is entered into the MAT, is it entered as a function or a definition? (Session 10 - 1/26/17)
- In this expression, it is entered as a definition, but you could also define a gestational age at birth function. define "Estimated Due Date": Last( ["Physical Exam, Performed": Vx."Estimated Due Date"] Exam sort by start of relevantPeriod ).result as DateTime define "Gestational Age in Days at Birth": (280 - (duration in days between "Estimated Due Date" and "Birth Date")) div 7 Link: https://github.com/esacinc/CQL-Formatting-and-Usage-Wiki/tree/master/Source/Cooking%20With%20CQL/10
Hepatitis B Immunizations Procedure - Value Set or Definition?: Is the Hepatitis B immunizations procedure a value set or definition? (Session 22 - 2/22/18)
- It is a definition. Value set declarations are defined in the CQL header and are local identifiers for value sets stored in a terminology service like the Value Set Authority Center. Definitions are defined in the body of the CQL library and specify chunks of logic that can be used throughout the library or within the measure as population criteria.
Hospitalization Function: What does the hospitalization function mean? (Session 16 - 7/20/17)
- The hospitalization function has been considered as an approach to identifying an encounter plus the time immediately prior to the emergency department visit. In a lot of the current hospital measures, they are looking for that pattern because there is an inpatient encounter with an immediately prior ED visit. In previous logic, those cases had to be considered independently. The hospitalization function gives us the duration, the interval from the start to the end of either the encounter or the immediately prior ED visit. It collapses that logic for determining what the overall duration of the hospitalization is, and by using this function, then we pass an encounter and it tells us from admission to discharge. Note, to determine arrival time within the hospitalization function requires use of the Encounter, Performed location attribute.
Hospitalization Function - "if null": In the hospitalization function where it says, “if null,” does it mean that if there is no ED encounter, it will start counting from the inpatient encounter? (Session 16 - 7/20/17)
- Yes.
Inpatient Encounters: You used the definition called “Inpatient Encounters” throughout the measure, but I thought it only had the length of stay and end string measurement period? (Session 15 - 6/15/17)
- That’s correct, it’s better to use “AMI Encounter” because it has all the necessary criteria.
Intersecting Inpatient Encounters with Another Category: We tried to use “Inpatient Encounters” and intersect it with something else, but it would not work. Why is that? (Session 15 - 6/15/17)
- The Intersect operator takes two lists and returns only those elements that are in both lists, so the lists should have the same kinds of values, such as lists of encounters. You cannot intersect encounters and orders.
Median Admit Decision Time to ED Departure Time for Admitted Patients: CMS111, Median Admit Decision Time to ED Departure Time for Admitted Patients (https://oncprojectracking.healthit.gov/support/browse/CQLIT-207), we are having a measure observation calculation issue, where some duration calculation results are based on the ending interval (end time of encounter). If the emergency department (ED) encounter does not include the facility location, it should not calculate a "Visit" encounter for the measure observation time. If the ED facility location departure time is missing, a measure observation time should not be calculated, but in Bonnie this does occur. Is this due to the logic below? Should we add a null clause in the Initial Population to indicate if there is no ED facility location departure time the encounter will not be included?(Session 40 - 12/5/19)
Global.HospitalizationLocations (Encounter "Encounter, Performed") Encounter Visit
let EDVisit: Last(["Encounter, Performed": "Emergency Department Visit"] LastED
where LastED.relevantPeriod ends 1 hour or less on or before start of
Visit.relevantPeriod
sort by end of relevantPeriod)
return if EDVisit is null then Visit.facilityLocations
else flatten
{ EDVisit.facilityLocations, Visit.facilityLocations }
- The measure intent is to capture the median time interval from when the admit decision is made (represented by an AssessmentPerformed.relevantDatetime or by an AdmitOrder.authorDatetime) to when the patient leaves the ED (represented by the end of HospitalLocation.locationPeriod).
define function "AdmitDecisionUsingAssessment"(Encounter "Encounter, Performed" ):
Last(["Assessment, Performed": "ED Evaluation"] EDEvaluation
where EDEvaluation.relevantDatetime during "RelatedEDVisit"(Encounter).relevantPeriod
and EDEvaluation.result in "Admit Inpatient"
sort by relevantDatetime
)
The “EDDepartureTime”(“RelatedEDVisit”(Encounter)) is represented by the end of HospitalLocations.locationPeriod. However, if HospitalLocations.code is present (ED Department), but the end of the locationPeriod is missing (null), then the time interval calculation would continue to infinity. If the ED Location EndTime was not noted, the measure performs the calculation until infinity, or the end of time, instead of to zero. To address this calculation issue, the initial encounter is expressed so that it includes an EDEncounter code and could not be null for the EDDepartureTime. In this case, the only ones passing through the measure would have an observation measure time.
define “Initial Population”:
Global."Inpatient Encounter" EncounterInpatient
with "ED Encounter with Decision to Admit" EDAdmit
such that EDAdmit.relevantPeriod 1 hour or less before or on start of EncounterInpatient.relevantPeriod
define “ED Encounter with Decision to Admit”:
( ( Global."ED Encounter" EDVisit where "AdmitDecisionUsingAssessmentDuringRelatedEDBeforeDeparture"
(EDVisit).relevantDatetime
during EDVisit.relevantPeriod)
union ( Global."ED Encounter" EDVisit where "AdmitDecisionUsingEncounterOrderDuringRelatedEDandBeforeDeparture"
(EDVisit).authorDatetime
during EDVisit.relevantPeriod
) ) EDVisitAdmit
where EDVisitAdmit.facilityLocations.locationPeriod is not null
If an ED visit is followed by an inpatient encounter, it’s safe to assume there’s missing data that wasn’t reported so you could assert that the end of the location period where it isn’t specified is the start of the inpatient encounter that wasn’t specified. Another thing you could do is to introduce a stratification that would detect the cases where EDFacilityLocation doesn’t have an ending date. This is a way to get the measure to indicate how many we’re getting that don’t have an end date documented. The measure observation would still be calculated but the AdmitTime would take place of the EDDepatureTime.
Medication Present on Admission: What is the best way to specify in Clinical Quality Language (CQL) that a medication was present on admission for an inpatient encounter? There have been conversations recently about a "presentOnAdmissionIndicator" for diagnoses in Quality Data Model (QDM) 5.5, but not something equivalent for medications. (Session 37 - 7/25/19)
- This will be documented as “Medication Active at Admission”.
define "Medications Active at Admission":
["Medication, Active"] M
with ["Encounter, Performed"] E
such that M.relevantPeriod contains start of E.relevantPeriod
The Medication, Active must have a relevant period that includes the start date of the encounter. Note also that this is only addressing the simplest case of an inpatient admission. It may need to be expanded to account for an immediately preceding emergency department visit, depending on measure intent. Also note that the Quality Data Model (QDM) specifies relevant period start for a Medication, Active as the time when the patient is first known to have been taking the medication. Whether this is captured by the electronic health records is a question for investigation.
No End Date: If you have overlapping depression periods with no end-date in the measurement period, do you get a query with all the diagnoses? (Session 30 - 12/6/18)
- That's correct because when you don't have an end to the prevalence period and it’s characterized with a closed brace, which is typically how they are characterized, then that means it goes to the end of time. So, when we intersect that with the measurement period, we only get the portion of the prevalence period that is entirely within the measurement period. For example, if you have a diagnosis that starts in March and another that starts in April and they both have no end-date then you'll just get one result.
Occurrences: Are occurrences still a concept that will be used? (Session 20 - 11/30/17)
- CQL takes a different approach to representing what specific occurrences were achieving, namely identifying a specific instance and associating criteria with that instance. Because CQL can describe queries and their results, and then use those results in subsequent operations, specific occurrences are not required to tie the different appearances of a data element together throughout the measure definition. Rather, with CQL, additional criteria are applied to specific instances of a data element by referencing the same expressions. For more information and examples, see the Specific Occurrences topic in the Formatting and Usage Wiki - https://github.com/cqframework/CQL-Formatting-and-Usage-Wiki/wiki/Specific-Occurrences.
Opened vs Closed Boundaries: In the specifications, is it necessary to specify that the boundary is closed or open? (Session 24 - 4/26/18)
- No, whether a boundary is closed or open is an aspect of the value, not the type. The systems providing the information indicate whether they are giving an interval that has closed or open boundaries.
"or" vs "and": In the Encounter Diagnoses example below, can “or” be changed to “and” and still provide the two diagnoses?
define “Single Live Birth Encounter or Gestational Diabetes”:
“Inpatient-Encounter” Encounter
where exists (Encounter.diagnoses Diagnosis
where Diagnosis in “Single Live Birth”
or Diagnosis in Gestational Diabetes”
)
(Session 18 - 9/21/17)
define “Single Live Birth Encounter or Gestational Diabetes”:
“Inpatient-Encounter” Encounter
where exists (Encounter.diagnoses Diagnosis
where Diagnosis in “Single Live Birth”
or Diagnosis in Gestational Diabetes”
)
- No because it indicates you want any diagnosis in the inpatient encounter that has a diagnosis code of “Single Live Birth” and “Gestational Diabetes”. The single code cannot satisfy both those requirements at the same time.
Present Upon Arrival with an Active Diagnosis Record: In discussing CLONE Hospital Harm – Pressure Injury Draft 0.00, the measure assesses the proportion of inpatient encounters for patients 18 years and older upon admission and the presence of stage 2, 3, or 4 deep tissue pressure injury or unstageable deep tissue pressure injury. This measure documents deep tissue pressure injury upon arrival or 24 hours after admission. (May be a need to create value sets for anatomical sites to support this measure.) The measure code will be written (continued in the answer). (Session 36 - 6/27/19)
- The measure code will be written:
“Denominator” EncounterwithQualifyingAge
with [“Diagnosis”: “Pressure Ulcer Stage”] PressureInjuryStage
such that (PressureInjuryStage.code ~ Pressure Ulcer Stage 2 (disorder)”
or PressureInjuryStage.code ~ Pressure Ulcer Stage 3 (disorder)”
or PressureInjuryStage.code ~ Pressure Ulcer Stage 4 (disorder)”
or PressureInjuryStage.code ~ Nonstageable Pressure Ulcer(disorder)”
or PressureInjuryStage.code ~ Pressure Injury of Deep Tissue (disorder)”
and PressureInjuryStage.prevelancePeriod starts more than 24 hours after start of “Hospitalization, Potentially Starting in
Emergency Department and or with Observation” (EncounterwithQualifyingAge)
and PressureInjuryStage.prevelancePeriod during “Hospitalization, Potentially Starting in Emergency Department and or with
Observation” (EncounterwithQualifyingAge)
The primary issue seems to be a need to relate a diagnosis that is indicated as present upon arrival with an active Diagnosis record and be able to reliably ensure they are the “same” diagnosis. How do you accomplish this?
ANSWER: This is done by comparing the codes of the diagnosis to the diagnosis as seen upon arrival. The diagnosis code is written as:
“Denominator” EncounterwithQualifyingAge
where [“Diagnosis”: “Pressure Ulcer Stage”] PressureInjuryStage
such that (PressureInjuryStage.code ~ Pressure Ulcer Stage 2 (disorder)”
or PressureInjuryStage.code ~ Pressure Ulcer Stage 3 (disorder)”
or PressureInjuryStage.code ~ Pressure Ulcer Stage 4 (disorder)”
or PressureInjuryStage.code ~ Nonstageable Pressure Ulcer(disorder)”
or PressureInjuryStage.code ~ Pressure Injury of Deep Tissue (disorder)”
and PressureInjuryStage.prevelancePeriod starts more than 24 hours after start of “Hospitalization, Potentially Starting in
Emergency Department and or with Observation” (EncounterwithQualifyingAge)
Notice that “with” has been changed to “where”.
The code for a Pressure Injury Present On Admission is as:
“Initial Population” Encounter
with [Diagnosis] Dx
such that Dx.prevelencePeriod overlaps Encounter.relevantPeriod
and Dx.code in (Encounter.diagnoses D return D.code)
where exists (Encounter.diagnosis EncounterDiagnosis where EncounterDiagnosis.code in “Pressure Injury” and
EncounterDiagnosis.presentOnAdmissionIndicator ~ “Y”)
This “Pressure Injury” will return an error since it does not have the value sets.
Note that in QDM 5.5, we added support for “PresentOnAdmission” using the model:
define “Encounter with “Ischemic Stroke Diagnosis Present On Admission”:
[“Encounter. Performed”: “Inpatient”] E
where exists (E.diagnoses D where D.code in “Ischemic Stroke”
and D.presentOnAdmissionIndicator ~” Y”)
QDM Medication Elements: In calculating methods for determining doses per day using the QDM medication elements, can active medications be used instead of ordered, assuming the patient is taking the medication as directed? (Session 28 - 9/27/18)
- If the frequency is available, then the QDM medication elements calculation would work, but if you are using the supply and the relevant periods to back into a daily value, that might not work because there is no certainty that supply is correlated with the relevant period. Refer to the Cooking with CQL presentation for this session for examples on how to calculate using both methods: https://github.com/esacinc/CQL-Formatting-and-Usage-Wiki/blob/master/Source/Cooking%20With%20CQL/28/68_DosesPerDayCalculations.cql
QDM Length of Stay Attribute: What is the recommendation for measure developers regarding the QDM length of stay attribute? Should they use the attribute or should they indicate length of stay using CQL expression without invoking the attribute? (Session 16 - 7/20/17)
- Because length of stay is an attribute of the encounter, it doesn’t work for defining the overall length of stay in the case where we want to consider the encounter immediately prior to the emergency department visit. Using the CQL expression is more general and it allows you to handle that case transparently. The length of stay attribute of Encounter, Performed can be used to define the time from admission to discharge for a specific encounter. However, if the measure developer needs to express the time from admission to a previous, but related encounter (i.e., an Emergency Department visit), the length of stay attribute would not be sufficient and a CQL expression provides such ability. Note, that to determine the arrival time at the previous Emergency Department visit, the measure needs to address the Encounter, Performed location attribute.
Risk Adjustment: What value is returned in risk adjustment? Is it different between EP measures vs. EH measures? (Session 30 - 12/6/18)
- No, risk adjustment variables can return any value. They are presented in the context of the patient and can return anything. For example, consider this risk adjustment variable definition from the TestRiskAdj_CQL example measure from the CQL-Based HQMF IG:
define "Bilirubin Test": ["Laboratory Test, Performed": "Bilirubin"] L
with "CABG_Open and Endoscopic During Encounter" C
such that L.relevantPeriod starts before start of C.relevantPeriod
with "Encounter Inpatient 365" E
such that L.relevantPeriod starts during E.relevantPeriod
where L.result as Quantity > 2 'mg/dL'
This returns all Bilirubin Tests for the patient that occurred during an Open and Endoscopic CABG during a qualifying encounter and with a result > 2 'mg/dL'.
Structured Query Language (SQL) joins: How do you represent Structured Query Language (SQL) joins in Clinical Quality Language (CQL)? (Session 37 - 7/25/19)
- In Structured Query Language (SQL), joins are used to combine data from multiple tables. In Clinical Quality Language (CQL), the focus is on simplest possible expression of single-source queries. But multi-source queries are possible as well. Some examples:
define "Semi-join Example":
["Encounter, Performed": "Outpatient"] Encounter
with ["Laboratory Test, Performed": "Streptococcus Test"] Test
such that Test.resultDatetime during Encounter.relevantPeriod
define "Semi-minus Example":
["Encounter, Performed": "Outpatient"] Encounter
without ["Laboratory Test, Performed": "Streptococcus Test"] Test
such that Test.resultDatetime during Encounter.relevantPeriod
define "Join Example":
from
["Encounter, Performed": "Outpatient"] Encounter,
["Laboratory Test, Performed": "Streptococcus Test"] Test
where Test.resultDatetime during Encounter.relevantPeriod
return { Encounter: Encounter, Test: Test }
define "Join Example with Select":
from
["Encounter, Performed": "Outpatient"] Encounter,
["Laboratory Test, Performed": "Streptococcus Test"] Test
where Test.resultDatetime during Encounter.relevantPeriod
return {
encounterId: Encounter.id,
encounterCode: Encounter.code,
encounterRelevantPeriod: Encounter.relevantPeriod
testId: Test.id,
testCode: Test.code,
testResultDatetime: Test.resultDatetime,
testResult: Test.result
}
define "Cartesian-product Example":
from
["Encounter, Performed": "Outpatient"] Encounter,
["Laboratory Test, Performed": "Streptococcus Test"] Test
The Default result from a multi-source query is a tuple with an element for each query source { Encounter: "Encounter, Performed", Test: "Laboratory Test, Performed" }
define "Left-outer-join Example":
["Encounter, Performed": "Outpatient"] Encounter
let Test: singleton from (["Laboratory Test, Performed": "Streptococcus Test"] LabTest
where LabTest.resultDatetime during Encounter.relevantPeriod)
return { Encounter: Encounter, Test: Test }
Note, there is an open source project that allows you to translate CQL to SQL. It was a pilot project in the Healthe-Decisions initiative. It is available on the Clinical Quality Framework Repository. It’s a little outdated, but the structure is there.
You can have a native environment that runs SQL directly. There are vendor systems that can do this and three open source implementations of a SQL engine that runs SQL directly. On the GitHub Wiki, there is a community projects page that has links to all of those open source implementations.
Unions in ED Encounter Expression: In the ED encounter observation expression, can the union be used with both option 1 (use of an Encounter code to model observation) and option 2 (use of an Encounter facility location to model observation)?
/*
O) As a different type of Encounter, separate from the Inpatient and Emergency Department encounters:
*/
define "Observation (Approach O)":
["Encounter, Performed": "Observation"]
/*
P) As a different location within the Inpatient Encounter:
*/
define "Observation (Approach P)":
["Encounter, Performed": "Encounter Inpatient"] E
return E.facilityLocations L where L.code in "Observation"
/*
NOTE: Observation beds are often scattered throughout the hospital and are not
necessarily designated as observation beds
(Session 27 - 7/26/18)
/*
O) As a different type of Encounter, separate from the Inpatient and Emergency Department encounters:
*/
define "Observation (Approach O)":
["Encounter, Performed": "Observation"]
/*
P) As a different location within the Inpatient Encounter:
*/
define "Observation (Approach P)":
["Encounter, Performed": "Encounter Inpatient"] E
return E.facilityLocations L where L.code in "Observation"
/*
NOTE: Observation beds are often scattered throughout the hospital and are not
necessarily designated as observation beds
- The “union” in this question is referring to the common use of unions to bring together encounters from different value sets in to a single expression for consideration. With option 1, because the observation status is determined by looking at a facility code, the encounter codes are still used in the way that they are now (i.e. to represent the type of encounter: inpatient, outpatient, etc.). With option 2, however, “Observation” is represented as another type of encounter, so you wouldn’t be able to distinguish other types of encounters within Observation.
Time Duration Calculations: How are time durations calculated in CQL? (session 10 - 1/26/17)
- Time durations in CQL are always in terms of a single duration. If it was necessary to say 32 weeks and 1 day, you would define it in days (or use addition to add 32 weeks + 1 day). Link: https://ecqi.healthit.gov/system/files/eCQM-Logic-and-Guidance-2018-0504.pdf.
Timing - Less Than 30 days: Explain why, if the timing is less than 30 days, 29 days is used in the CQL expression? (session 12 - 3/16/17)
- Because the timing phrase in 1.1 doesn’t have a way to say, “less than 30 days”, only “29 days or less”. The 1.2 version of CQL will introduce the ability to say, “less than 30 days”.
Troponin Continuous Variable Measure - multiple Toponin tests and communication: The Troponin Continuous Variable measure is a pathology-driven quality measure under development that relates to critical value reporting and is seeking the time interval in minutes from the time the results for troponin tests are determined and when the laboratory communicates the critical troponin levels to the responsible provider using the electronic health record (EHR) as the source of the data. The measure observation evaluates only the first troponin test followed by a communication (e.g., email, fax) during the encounter. The communication should be completed after the test and should be related to the test for which it is attributed. The issue is in trying to create the logic to relate the communication about a specific test when there are multiple troponin tests during an encounter. As an example, during an encounter we have two troponin tests and one communication:
-The first troponin test result date time: 2/12/2019 1100
-The second troponin test result date time: 2/12/2019 1205
-The first communication sent date time: 2/12/2019 1305
The measure should be comparing the communication to test result to which it corresponds. The current logic relates the communication to the first troponin test in the example. How can one address a scenario in which there are multiple toponin tests and related each communication to its respective test result? (session 44 - 5/28/20)
- Using Quality Data Model (QDM) version 5.5, there are several approaches to consider. The approach depends on the availability of information about the relationship between the communication and the troponin lab test id and whether there is information in the EHR that can link the communication with the lab test.
Expression 1: The first expression is a multi-source query that says “for every encounter, for every troponin test performed, and for every communication performed, only consider the tests that were performed in the relevant period. The communication should be related to the id.”
define function "Minutes between results and communication by id"(Encounter "Encounter, Performed"):
Min(
from
["Laboratory Test, Performed": "Cardiac Troponin"] T,
["Communication, Performed": "Lab Communications"] C
where T.resultDatetime during Encounter.relevantPeriod
and C.sentDatetime during Encounter.relevantPeriod
and C.relatedTo includes T.id
return minutes between T.resultDatetime and C.sentDatetime
)
Expression 2: The second approach is performed based on timing. The second expression says, “for every laboratory test during this encounter, return the minutes between the result date time and the dateTime the communication is sent.” Using this expression for every laboratory test, it will look for the first communication after that laboratory test. It will return the duration in minutes between availability of the test result and the time the communication is sent so you will get the length of time for every test before a communication came back.
define function "Minutes between results and communication by timing"(Encounter "Encounter, Performed"):
Min(
["Laboratory Test, Performed": "Cardiac Troponin"] T
let
Communication: First(
["Communication, Performed": "Lab Communications"] C
where C.sentDatetime during Encounter.relevantPeriod
and C.sentDatetime after T.resultDatetime
sort by sentDatetime
)
return minutes between T.resultDatetime and Communication.sentDatetime
)
Expression 3: The third expression returns the minutes between communications for the first test and a second test if there are no relatedTo elements in the communications or the relatedTo includes the id. If the EHR is able to provide information whether the communication is relatedTo a specific troponin test, then it will come back as the first and only communication. However, if the EHR is not able to provide the relationship between the communication and the test result, then it will find the first ‘sent’ time of a communication during the encounter that came after the result retrieved.
define function "Minutes between results and communication by id or timing"(Encounter "Encounter, Performed"):
Min(
["Laboratory Test, Performed": "Cardiac Troponin"] T
let
Communication: First(
["Communication, Performed": "Lab Communications"] C
where C.sentDatetime during Encounter.relevantPeriod
and C.sentDatetime after T.resultDatetime
and (not exists (C.relatedTo) or C.relatedTo includes T.id)
sort by sentDatetime
)
return minutes between T.resultDatetime and Communication.sentDatetime
)
Two Encounters in the same Measurement Period: If the Enc1 is in June, the previous one is still in the measurement period. Could you move the age to separate statement instead of a where? (session 19 - 10/26/17)
- Yes, the age criteria is independent of the other conditions here, so it could be moved to a separate definition, especially if the intent was to reuse that component in other definitions. Review the full expression in the CQL Formatting and Usage Wiki - https://github.com/cqframework/CQL-Formatting-and-Usage-Wiki/blob/master/Source/Cooking%20With%20CQL/19/49_CMS161.cql#L69.
Union - Unique codes for Multiple Diagnoses: Does union return a unique code for both diagnosis of asthma and other illness? (session 9 - 11/17/16)
- Yes, in the new version of CQL 1.2, distinctions will not be necessary because duplicates will be automatically eliminated.
Using a Subset of an Existing Value Set: When developing a new measure and I want to use an existing value set, how do I pull out specific codes, a subset of the existing value set, in a new value set? E.g. pulling one contraceptive from a list. (session 23 - 3/29/18)
- If you need to reference only a subset of the codes from an existing value set, this can be done two ways; 1) define another value set with only that code in it or, 2) reference a specific code. In general, if the use case clearly identifies a specific code to reference, you can use it as a direct reference code. However, if there are multiple codes necessary, a new value set is needed.
Note that although CQL does provide set operations that could be used to compute the subset of a value set using some expressive criteria, performing calculations involving value sets is not recommended for several reasons:
- Terminology operations, such as membership, are communicated in the machine-readable file in specific ways that enable implementations to make use of terminology servers. Performing calculations on value sets requires the use of expansion, which is not required for membership testing when that testing is done by the terminology server. As a result, using value sets in calculation would impose an additional implementation burden on vendors consuming the measure.
- The definition of terminology is by design a separate aspect of quality measure development. This separation of concerns has multiple benefits, including that the maintenance and governance of value sets can be performed independent of the maintenance and governance of the measures.
- Value set definition often involves operations that are specific to the terminologies involved, so there is a great deal of variability in the way that these expressions are represented.
Using Exist and Unions: In the example below, does using exist have any impact when also using the union to define the numerator?
Define “Numerator”:
“Encounter With Antithrombotic Therapy”
union “Encounter With ED Visit With Antithrombotic Therapy”
(session 14 - 5/18/17)
Define “Numerator”:
“Encounter With Antithrombotic Therapy”
union “Encounter With ED Visit With Antithrombotic Therapy”
- A. Yes, and it depends on whether we are defining a patient-based or encounter-based measure. For an encounter based measure, what we are returning from all the criteria are lists of encounters. In a patient-based measure, what we are returning from all the criteria is true or false. So, in a patient-based measure you use exist to get a list to be true or false. In an episode-based measure, we are returning lists, so we don’t use exist.
Using "with" in the "such that" Expression: When using “with” in the “such that” expression, do you have to put it before all the such that’s or is there a significance to the order? (session 10 - 1/26/17)
- Each “with” needs a “such that” to describe the relationship of the “with” source to the “primary” source. https://github.com/esacinc/CQL-Formatting-and-Usage-Wiki/tree/master/Source/Cooking%20With%20CQL/10
Using "within": When using within to make the range clearer, does that mean the 60 days can be either side? (session 19 - 10/26/17)
- Yes, within 60 days can be before or after.
"Where" Clause: When the “where” clause is used in the example; does it mean that the ‘let…’ statement can only be assigned one line of code?
let procedure: (
“Total Hip Total Knee Procedure” (QualifyingEncounters) P
where P.ordinality in “Principal”
)
(Session 24 - 4/26/18)
let procedure: (
“Total Hip Total Knee Procedure” (QualifyingEncounters) P
where P.ordinality in “Principal”
)
- No, the “where” clause in a query will not change the result type of the query.
Authoring Patterns - QICore v4.1.1
Authoring Patterns - QICore v5.0.0
Authoring Patterns - QICore v6.0.0
Cooking with CQL Q&A All Categories
Additional Q&A Examples
Developers Introduction to CQL
Specifying Population Criteria