Skip to content
Bryn Rhodes edited this page May 25, 2017 · 2 revisions

Unions in CQL

The union operator in CQL combines two lists, resulting in a single set that contains elements from both lists. The union in CQL is a set operation, meaning that if an element appears in both lists, it will only appear once in the output. (NOTE: The union in CQL 1.1 does not eliminate duplicates, but the behavior was changed in CQL 1.2 to make the operator more intuitive. This discussion is based on the 1.2 version of CQL.)

To illustrate the basic operation, consider the following diagram:

list-union

The first list of integers is combined with the second list to produce a single list containing the elements that appear in either list.

Strict Unions

Simple lists in CQL can only contain elements of the same type. When evaluating a strict union, this means that the following CQL is invalid:

define "Intervention Comfort Measures":
  ["Intervention, Order": "Comfort Measures"]
    union ["Intervention, Performed": "Comfort Measures"]

This is because the structures of "Intervention, Order" and "Intervention, Performed" are different; they have different attributes. In particular, "Intervention, Order" has the following attributes:

id
code
patientId
reporter
recorder
authorDatetime
reason
negationRationale

While "Intervention, Performed" has the following attributes:

id
code
patientId
reporter
recorder
authorDatetime
relevantPeriod
reason
result
status
negationRationale

Note that the first five attributes, id, code, patientId, reporter, and recorder, are common to all QDM data types. The id attribute is the instance identifier for the data element (e.g. Encounter #11335). The code attribute represents the coded type of the element (e.g. SNOMED-CT:305338009 (Admission to GP Hospital)). The patientId attribute represents a unique identifier for the patient (e.g. Patient #1234), and the reporter and recorder attributes represent provenance information for the data element.

Because of this difference in structures, a strict union requires that the data elements be "converted" into the same format so they can appear in the same list. In CQL, this is done with a return clause for one or the other of the inputs to the union:

define "Intervention Comfort Measures":
  ["Intervention, Order": "Comfort Measures"]
    union (
      ["Intervention, Performed": "Comfort Measures"] P
        return "Intervention, Order" { 
          id: P.id,
          code: P.code,
          patientId: P.patientId,
          reporter: P.reporter,
          recorder: P.recorder,
          authorDatetime: Coalesce(start of P.relevantPeriod, P.authorDatetime)
        }
    )

The return clause in this case is "converting" the "Intervention, Performed" events into "Intervention, Order" events by providing the values for the corresponding attributes, and calculating a value for the authorDatetime attribute based on the relevantPeriod of the "Intervention Performed", if it is available.

The result of this union will now be a list of "Intervention, Order" structures. Note that this may not be the best way to do this, given that the result now looks like a list of "Intervention, Order", but some of them are actually "Intervention, Performed".

Using this approach it would not be possible to tell after the elements had been combined which ones were orders and which were actually performed interventions.

Choice Unions

An alternative approach is to use the more flexible choice union, but it will result in a list with different elements:

define "Intervention Comfort Measures":
  ["Intervention, Order": "Comfort Measures"]
    union ["Intervention, Performed": "Comfort Measures"]

This result will include both orders and performed interventions. It is possible to tell which elements are which using the is operator:

"Intervention Comfort Measures" I
  where I is "Intervention, Order"

However, because the structures are different, accessing attributes of the elements will return null if the attribute does not exist for the instance:

"Intervention Comfort Measures" I
  where I.relevantPeriod starts during "Measurement Period"

For the elements of the list that are "Intervention, Performed", the criteria is correct. But for elements of the list that are "Intervention, Order", they have no relevantPeriod attribute, so the expression will result in null.

It is important to note at this point that QDM allowed unions of different types, and that this ambiguity about the date/time attribute being accessed was covered up by the fact that temporal relationships in QDM were always based on an implied primary temporal attribute for the event. With the added precision of CQL, we need to be able to say exactly what we mean when we apply a criteria like this against a list that contains elements of different types.

One way to do this is to use the Coalesce operator to provide a "default" for the case where a given attribute is not present:

"Intervention Comfort Measures" I
  where Coalesce(start of I.relevantPeriod, I.authorDatetime) during "Measurement Period"

This condition accesses the start of the relevantPeriod attribute if it is present, otherwise it will access the authorDatetime attribute.

Wiki Index

Home

Authoring Patterns - QICore v4.1.1

Authoring Patterns - QICore v5.0.0

Authoring Patterns - QICore v6.0.0

Authoring Measures in CQL

Composite Measure Development

Cooking with CQL Examples

Cooking with CQL Q&A All Categories
Additional Q&A Examples

CQL 1.3 Impact Guidance

CQL Error Messages

Developers Introduction to CQL

Discussion Items

Example Measures

Formatting and Usage Topics

Formatting Conventions

Library Versioning

Negation in QDM

QDM Known Issues

Specific Occurrences

Specifying Population Criteria

Supplemental Data Elements

Terminology in CQL

Translator Options For Measure Development

Unions in CQL

Clone this wiki locally