-
Notifications
You must be signed in to change notification settings - Fork 24
Cooking with CQL Q&A Index Queries in CQL Category
Each Q&A has the Cooking with CQL session number and date. For the most current and accurate information, please check the CQL Qs&As for a more recent answer to your question.
Cross-Context Query for a Related Person: Looking at the solution for the connection of the mother and baby, is the capability for a cross-context query for a related person new to CQL? (Session 33 - 3/28/19)
- Yes, it is new. We would like feedback in order to gain further understanding of the "operator" and how it is being used.
FHIRHelpers.ToDate(Patient.birthDate) - Global Common Library v5.0 to calculate age: (Session 55 - 6/24/21)
- Yes, the change to remove age calculation functions from Global Common Library v6 means that when the system-defined Age calculation functions are used, the FHIRHelpers.ToDate function will be applied as part of the tooling. More specifically, one of the functions in CQL is the ability to calculate the age of the patient. The CQL model information understands the patient context and knows how to retrieve the patient birthdate. Therefore, the measure developers do not need to write the FHIRHelpers.ToDate(Patient.birthDate) function in the logic expression, since the function is included in the generated code to transform the birthdate expressed as a FHIR date into a CQL date. Example Logic Expression using Global Common Library v5
define "HPV Test Within 5 Years for Women Age 30 and Older (124)":
[Observation: "HPV Test"] HPVTest
where HPVTest.value is not null
and HPVTest.status in { 'final', 'amended', 'corrected', 'preliminary' }
and Global."CalendarAgeInYearsAt"(FHIRHelpers.ToDate(Patient.birthDate), start of Global."Normalize Interval"(HPVTest.effective)) >= 30
and Global."Normalize Interval"(HPVTest.effective) ends 5 years or less on or before end of "Measurement Period"
Example Logic Expression using Global Common Library v6
define "HPV Test Within 5 Years for Women Age 30 and Older (124) (Global v6)":
[Observation: "HPV Test"] HPVTest
where HPVTest.value is not null
and HPVTest.status in { 'final', 'amended', 'corrected', 'preliminary' }
And AgeInYearsAt(start of Global6."Normalize Interval"(HPVTest.effective)) >= 30
and Global6."Normalize Interval"(HPVTest.effective) ends 5 years or less on or before end of "Measurement Period"
'from' vs 'with' with 2 sources: Is 'from' required when setting up a relationship between more than two sources and 'with' when setting up a relationship with only two sources? (Session 32 - 2/28/19)
- Yes, that’s correct, ‘from’ is used to set up a “multi-source” query where you want to be able to talk about more than two sources at once. If you have a “single-source” query, you can use ‘with’ and ‘without’ to establish relationships between the primary source of the query and one other source at a time.
immune check inhibitor (ICI) therapy Bins - expand operator: When defining the immune checkpoint inhibitor (ICI) therapy Bins, the expand operator was used to create a list. Since the return point from X will return an integer, are we able to subtract since it is an integer and not a list anymore?
define "ICI Therapy Bins":
// expand Interval[1, "Required Bins"] // { 1, 2, 3, 4, 5 }
(expand { Interval[1, "Required Bins"] }) X
return point from X
(Session 53 - 4/22/21)
define "ICI Therapy Bins":
// expand Interval[1, "Required Bins"] // { 1, 2, 3, 4, 5 }
(expand { Interval[1, "Required Bins"] }) X
return point from X
- The expand operator expression will always be used to create a list but it can be a list of integers or a list of integer intervals, depending on whether you pass it a single interval, or a list of intervals. The single interval option was introduced in CQL 1.5, so in 1.4, you need to use the syntax to 1) provide the Interval from 1 to Required Bins to the expand as a list (using the braces), and 2) return the result of each interval returned from the expand as a single point (using the return point from X):
define "ICI Therapy Bins":
// expand Interval[1, "Required Bins"] // { 1, 2, 3, 4, 5 }
(expand { Interval[1, "Required Bins"] }) X
return point from X
immune check inhibitor (ICI) therapy with Thyroid Stimulating Hormone (TSH) testing in overlapping measurement periods: For patients receiving immune checkpoint inhibitor (ICI) therapy for the treatment of cancer, and need thyroid-stimulating hormone (TSH) testing every eight weeks, how do you write an expression to capture appropriate TSH testing during ICI therapy administration where the first ICI treatment period starts within the measurement period? An ICI treatment period is defined as consecutive ICI administrations no more than eight weeks apart.
The example below illustrates a patient with three ICI treatment periods in the lines under the designation of the years: one beginning in the previous measurement year (2019), one beginning in the current measurement year (2020), and one beginning in the following year (2021). The 2nd treatment period is selected because it is the first treatment period that starts within the measurement period of 2020.
2019 2020 2021
|------------------------|---------------------|--------------------|
|--|--|--|---|---|---| |---|----|---|---|----| |---|---|--|
(Session 53 - 4/22/21)
2019 2020 2021
|------------------------|---------------------|--------------------|
|--|--|--|---|---|---| |---|----|---|---|----| |---|---|--|
- To create the logic expression for the 2022 measurement period, scan across all the ICI therapies and find the first 8-week course interval that has an administration start date in the intended measurement period (August 2021). Exclude the 8-week course of therapy that was captured in the previous measurement period and that overlaps into the current measurement period (October 2020 – March 2021). The expression is:
define "ICI Therapy":
["Medication, Administered": "Immune Checkpoint Inhibitor"] ICI
define “ICI Starts Within 8 weeks Interval”:
{
First(
"ICI Therapy" Therapy
without "ICI Therapy" PriorTherapy
such that PriorTherapy.relevantPeriod starts 57 days or more before day of start of Therapy.relevantPeriod
where Therapy.relevantPeriod starts 1 year or less before start of "Measurement Period"
sort by start of relevantPeriod
)
}
immune check inhibitor (ICI) therapy with Thyroid Stimulating Hormone (TSH) testing - Therapy.relevantPeriod : When writing an expression to capture thyroid-stimulating hormone (TSH) lab tests at the start of an 8-week course of immune checkpoint inhibitor (ICI) therapy, specifically dates that are in between measurement periods and you do not want to duplicate administration dates captured in a previous measurement period, is the statement where
Therapy.relevantPeriod starts 1 year or less before start of "Measurement Period"
in the logic expression redundant since this statement is the timing for the ICI therapy definition? (Session 53 - 4/22/21)
- The where Therapy.relevantPeriod starts 1 year or less before start of "Measurement Period" statement should remain within the logic expression since, in this case, we deleted it from the define "ICI Therapy": ["Medication, Administered": "Immune Checkpoint Inhibitor"] ICI, which then removed the limitation.
define "ICI Therapy":
["Medication, Administered": "Immune Checkpoint Inhibitor"] ICI
define “ICI Starts Within 8 weeks Interval”:
{
First(
"ICI Therapy" Therapy
without "ICI Therapy" PriorTherapy
such that PriorTherapy.relevantPeriod starts 57 days or more before day of start of Therapy.relevantPeriod
where Therapy.relevantPeriod starts 1 year or less before start of "Measurement Period"
sort by start of relevantPeriod
)
}
immune check inhibitor (ICI) therapies: How do you write an expression to return all immune check inhibitor (ICI) therapies, over a 12-month period, where the ICI administration dates are eight weeks or less between administration? (Session 52 - 3/25/21)
- The intent is that the administrations are eight weeks or less apart. There is a string of data points that are no more than eight weeks apart until the endpoint. The endpoint could be where the ICI therapy is greater than eight weeks from the previous administration, the end of the one-year treatment period from the start of ICI therapy, or the end of the measurement period.
define "ICI Starts Within 8 weeks Interval":
"ICI Therapy" Therapy
without "ICI Therapy" PriorTherapy
such that PriorTherapy !~ Therapy
and PriorTherapy.relevantPeriod starts 57 days or more before day of start of Therapy.relevantPeriod
define "Start of ICI":
Min("ICI Starts Within 8 weeks Interval" ICITherapy
return start of ICITherapy.relevantPeriod
)
define "End of ICI":
Min({
end of "Measurement Period", "Start of ICI" + 1 year, Max("ICI Starts Within 8 weeks Interval" Therapy
return
end of Therapy.relevantPeriod
)}
)
Influenza Vaccine measure (CMS 147) - negation rationale pattern for Immunization Not Done queries: In the Influenza Vaccine measure (CMS 147), when following the negation rationale pattern for Immunization Not Done queries in Clinical Quality Language (CQL), if more than one criterion is returned in the query, does the expression stop after the first criterion is met and returned? (Session 55 - 6/24/21)
- If a patient has multiple codes from the negation rationale value sets, the “Medical Patient or System Reason for Not Administering Influenza Vaccine” definition will return multiple items. Multiple items are then converted by the code into a Boolean for this measure because the Denominator Exclusions population criteria uses an exists operator.
define "Medical Patient or System Reason for Not Administering Influenza Vaccine":
[Immunization: "Influenza Vaccine"] NoFluVaccine
where NoFluVaccine.recorded during "Influenza Season Including August and September of the Prior Year"
and NoFluVaccine.status = 'not-done'
and (
NoFluVaccine.statusReason in "Medical Reason"
or NoFluVaccine.statusReason in "Patient Reason"
or NoFluVaccine.statusReason in "System Reason"
or NoFluVaccine.statusReason in "Influenza Vaccination Declined"
)
Library to illustrate patterns for accessing FHIR through references: When using a library to illustrate patterns for accessing related Fast Healthcare Interoperability Resources® (FHIR®) through references, what does the highlighted term Medication refer to in the line of code below?
1.5 Translator also supports related context retrieve usage:
define TestMedicationRequest1B:
[MedicationRequest] MR
with [MR.medication -> Medication] M
such that M.code in "Aspirin"
(Session 53 - 4/22/21)
1.5 Translator also supports related context retrieve usage:
define TestMedicationRequest1B:
[MedicationRequest] MR
with [MR.medication -> Medication] M
such that M.code in "Aspirin"
- In this line of code, Medication references that a medication request can have as its medication element a codable concept or a reference to a medication resource, depending on the server. The example defines it as a reference to a medication resource.
Multiple Source Queries with No Attributes: In multi-source queries, if an attribute is not mentioned specifically in the query, like the "method" attribute, will it still be included in the return? (Session 35 - 5/23/19)
- Yes, if it is defined as an attribute in that source. For example, “method” is one of the attributes for “Physical Exam, Performed”. So, for the default behavior (when no return is specified), each element will have the same structure as the source it came from.
Multiple Source Queries with No Return Statement: When setting up relationships between multiple sources of data at the same time, what should you expect to see as the return with multi-source queries without specifying a return statement? For example, in CMS144v7: Consecutive Heart Rates less than 50 Inpatients, what would you expect to see as the return if not using a return statement? (Session 35 - 5/23/19)
- Without a return statement, you’ll get a couple of results that have elements for each of the sources. So, you’ll get heart rate and a moderate or severe LVSDHF (left ventricular systolic dysfunction heart failure) inpatient encounter:
// Result Type:
{
{ HeartRate: { id: 'obs-1', code: ... }, ModerateOrSevereLVSDHFInpatientEncounter: { id: 'enc-1', code: ... } }
{ HeartRate: { id: 'obs-2', code: ... }, ModerateOrSevereLVSDHFInpatientEncounter: { id: 'enc-1', code: ... } }
{ HeartRate: { id: 'obs-3', code: ... }, ModerateOrSevereLVSDHFInpatientEncounter: { id: 'enc-2', code: ... } }
{ HeartRate: { id: 'obs-4', code: ... }, ModerateOrSevereLVSDHFInpatientEncounter: { id: 'enc-2', code: ... } }
...
}
If you don’t specify a return, then for each of the items in your “from,” you’ll get a result. The actual result of the query will be a list where you’ll have every combination of heart rate and moderate or severe LVSDHF inpatient encounter for this patient. A return is typically used with a multi-source query to pick out particular elements to be returned. The “where” clause eliminates combinations of those encounters so it would pull out the rows that don’t match that criteria. In the end, you only end up with rows that match the criteria, but since you didn’t specify the return, you will still get this list. Typically, if the result is used elsewhere, then a return would be included. If you’re only using it in something like an “exists”, then you don’t need to include a return.
Multiple Source Queries with Specified Attributes Returned: In multi-source queries, is it feasible to specify the type of attributes we want returned? (Session 35 - 5/23/19)
- Yes, you can use return, it’s an arbitrary expression. So whatever you want to return from the “from,” you can.
Related Person Query: Is the related person query included in the FHIR Quality Measure Implementation Guide? (Session 33 - 3/28/19)
- In the FHIR Quality Measure Implementation Guide May 2019 ballot content there is an example of this use case and we are seeking comments. Terminology is also being worked on within this example. There is nothing specific about this type of query in the base FHIR Clinical Reasoning measure specification.
Running CQL Queries: I am new to CQL, how do we run CQL queries - is it against C-CDA documents? (Session 31 - 1/31/19)
- CQL can be used with any data model. In the examples in this series we are focused on using the Quality Data Model (QDM), which has a serialization as Quality Reporting Document Architecture (QRDA). QRDA is similar to C-CDA (they are both Health Level Seven International [HL7] V3 standards), but not the same. FHIR resources may also be used.
Substance Use Disorder (SUD) Encounter During Identification with Patient Age at Start: How should we express the criteria that a Substance Use Disorder (SUD) encounter in the "identification period" (6 months before through the first 6 months of the measurement period) is considered new if there are no other SUD encounters in the 60 days prior to the encounter, and that for each new SUD encounter, there is a baseline Quality of Life (QOL) assessment in the 14 days on or before the new SUD encounter, and a corresponding follow up QOL using the same assessment tool within 3 to 6 months of the new SUD encounter, and having a SUD encounter within 60 days of the follow up QOL assessment? (Session 34 - 4/25/19)
- For each SUD encounter, there should be a baseline QOL assessment 14 days on or before the new SUD encounter and a follow up QOL assessment using the same QOL tool within 3-6 months and that had a SUD encounter within 60 days before that follow up QOL assessment, which could take place on the same day as the SUD encounter. Please see the example below of how this query should be expressed.
define "New SUD Encounter":
"SUD Encounters" S
without "SUD Encounters" S2 such that S2.relevantPeriod ends 60 days or less before start of S.relevantPeriod
where S.relevantPeriod starts during "Identification Period"
define "Follow Up QOL Assessment":
from
"SUD Encounter During Identification Period with Patient Age at Start" NewSUDEncounter,
"QOL Assessment" BaselineAssessment,
"QOL Assessment" FollowupAssessment
where (BaselineAssessment.authorDatetime 14 days or less before or on start of
NewSUDEncounter.relevantPeriod
or BaselineAssessment.authorDatetime during NewSUDEncounter.relevantPeriod)
and FollowupAssessment.authorDatetime 3 months or more after start of NewSUDEncounter.relevantPeriod
and FollowupAssessment.authorDatetime 6 months or less after start of
NewSUDEncounter.relevantPeriod
and exists ("SUD Encounter" SUDEncounter where SUDEncounter.relevantPeriod starts 60 days or less before or on
FollowupAssessment.authorDatetime)
and BaselineAssessment.code ~ FollowupAssessment.code
return FollowupAssessment
TST Testing very 8 Weeks: When working with a measure that is looking for patients for whom thyroid stimulating hormone (TSH or T4) testing is performed at least once every 8 weeks while receiving immune check inhibitor (ICI) therapy for a maximum duration of 1 year from the start of ICI therapy, how can the data be sorted into relevant bins while looking for an abnormal TSH or T4 result? (Session 52 - 3/25/21)
- For each TSH or T4 lab test performed, there should be a laboratory test result returned to the eight-week bin that the lab result is associated with. Lab results are assigned to a bin by the result date being within the bin boundaries. Bins start with the beginning of ICI therapy, indexed 1 through x, where bin 1 is from zero to eight weeks after the start of ICI therapy and x is the end of that eight-week period. The subsequent bin, e.g., bin 2, starts at the previous bin’s ending point and goes through the next eight-week period.
The bin intervals could be constructed as follows: Bin 1: 0 weeks <= x < 8 weeks Bin 2: 8 weeks <= x < 16 weeks Bin 3: 16 weeks <= x < 24 weeks Bin 4: 24 weeks <= x < 32 weeks Bin 5: 32 weeks <= x < 40 weeks Bin 6: 40 weeks <= x < 48 weeks Bin 7: 48 weeks <= x < 56 weeks
If the patient stops therapy before exactly 1 year from therapy start date, look for 1 TSH test within the bin for which the patient therapy end date falls. If the patient is still on therapy when they reach 1 year from therapy start date, look for a final TSH test within bin 7 (week 48-56). If the patient is on therapy for less than 8 weeks, look for 1 TSH test within bin 1.
define "ICI Therapy Bins":
expand Interval[1, "Required Bins"]
Then use the bin numbers to construct 8-week intervals, beginning at the start of ICI:
define "ICI Therapy Bin Periods":
"ICI Therapy Bins" Bin
return Interval["Start of ICI" + ((Bin - 1) * 8 weeks), "Start of ICI" + (Bin * 8 weeks))
Then look for bin periods that contain the expected tests:
define "ICI Therapy Bin Periods with Required Test Lab":
"ICI Therapy Bin Periods" Period
with "Test Lab" LT
such that LT.relevantDatetime during Period
Then in the numerator:
define "Required Bins":
(weeks between "Start of ICI" and "End of ICI") div 8
define "Proposed Numerator":
Count("ICI Therapy Bin Periods with Required Test Lab") = "Required Bins"
Use of the group by clause in CQL: Considering Clinical Quality Language (CQL) aggregate functions using Fast Healthcare Interoperability Resources® (FHIR®) v4.0.1 and calculating the number of each kind of observation a patient has, can the query use the GROUP BY clause?
define NumberOfObservationsPerCode:
[Observation] O
return {
code: O.code,
numberOfObservations: Count([Observation] InnerO where InnerO.code ~ O.code)
}
(Session 61 - 2/24/22)
define NumberOfObservationsPerCode:
[Observation] O
return {
code: O.code,
numberOfObservations: Count([Observation] InnerO where InnerO.code ~ O.code)
}
- No, CQL does not define a group by clause like SQL has, but grouping queries can still be expressed using the approach illustrated here. Users may submit feedback requesting the addition of a group by clause in CQL as a shorthand for this type of calculation.
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