Clinical Query Language (CQL)

Constants can be integers, decimal numbers or strings (quoted with single or double quotes):

1

1.1

'string'

"string"

Maths operators follow normal precedence rules:

1 + 2 * 3  equates to 7

Strings can be concatenated:

'a' & 'b' equates to 'ab'

Dates, times and datetime values are quoted and indicated thus:

d'13 MAR 1967'
t'10:12:13'
dt'13 MAR 1967 10:12:13'

All valid Rave date and time formats are supported, including unknown values for partial dates:

d'UN UNK 1967'
t'09:12 PM'

Parenthesis can be used to control order of evaluation

(6-2)/((1+1)*2) equates to 1

Values can be compared:

1 < 2
1 <= 2
1 == 1
1 != 1
2 > 1
2 >= 1

Logical operators follow normal precedence rules (AND, OR, NOT)

1 < 2 OR 2 < 3
NOT 1 > 2

Data references are composed of the Folder, Form and Field OIDs, separated by the '.' character:

FOLDER_OID.FORM_OID.FIELD_OID == 1

Folder OID is optional and can be wildcarded, but Form and Fields OIDs are mandatory:

*.FORM_OID.FIELD_OID == 1

Record Positions and Folder/Form repeat numbers can be specified:

FOLDER_OID[1].FORM_OID[1].FIELD_OID[1] == 1

and can be wild-carded using '*':

FOLDER_OID[*].FORM_OID[*].FIELD_OID[*] == 1

Variable only data references are prefixed with the ':' character:

:VARIABLE == 1
:VARIABLE[1] == 1

If not specified the reference will default to 'StandardValue'. This can be changed by appending the data value type:

*.FORM.FIELD.CodedValue
*:VARIABLE.UserValue

Logical Record Position (LRP) functions must specify the scope (Form, Folder or Subject):

min(FOLDER_OID.FORM_OID.FIELD_OID in Folder)
max(FOLDER_OID.FORM_OID.FIELD_OID in Subject)

and order (RecordDate or CRFLocation):

first(FOLDER_OID.FORM_OID.FIELD_OID in Form order by RecordDate)
last(FOLDER_OID.FORM_OID.FIELD_OID in Folder order by CRFLocation)
next(FOLDER_OID.FORM_OID.FIELD_OID in Form order by RecordDate)
previous(FOLDER_OID.FORM_OID.FIELD_OID in Subject order by CRFLocation)

Data objects have methods:

FOLDER_OID.FORM_OID.FIELD_OID.IsEmpty
FOLDER_OID.FORM_OID.FIELD_OID.IsNotEmpty
FOLDER_OID.FORM_OID.FIELD_OID.InLocalLabRange
FOLDER_OID.FORM_OID.FIELD_OID.IsPresent
FOLDER_OID.FORM_OID.FIELD_OID.IsActive
FOLDER_OID.FORM_OID.FIELD_OID.IsNonConformant

The same operation can be applied to multiple data values at the same time using the 'ANY' and 'ALL' functions.

any(*.FORM.FIELD1, *.FORM.FIELD2, *.FORM.FIELD3) == 1
all(*.FORM.FIELD1, *.FORM.FIELD2, *.FORM.FIELD3).IsPresent

are equivalent to:

*.FORM.FIELD1 == 1 or *.FORM.FIELD2 == 1 or *.FORM.FIELD3 == 1
*.FORM.FIELD1.IsPresent and *.FORM.FIELD2.IsPresent and *.FORM.FIELD3.IsPresent

There are string and date functions:

FOLDER_OID.FORM_OID.FIELD_OID Contains 'abc'
FOLDER_OID.FORM_OID.FIELD_OID StartsWith 'abc'
FOLDER_OID.FORM_OID.FIELD_OID AddSec 20
FOLDER_OID.FORM_OID.FIELD_OID AddMin 10
FOLDER_OID.FORM_OID.FIELD_OID AddHour 2
FOLDER_OID.FORM_OID.FIELD_OID AddDay 1
FOLDER_OID.FORM_OID.FIELD_OID AddMonth 12
FOLDER_OID.FORM_OID.FIELD_OID AddYear 1
FOLDER_OID.FORM_OID.FIELD_OID Contains 'abc'
FOLDER_OID.FORM_OID.FIELD_OID Contains FOLDER2.FORM2.FIELD2
FOLDER_OID.FORM_OID.FIELD_OID Contains ('a' &amp; FOLDER2.FORM2.FIELD2)
FOLDER_OID.FORM_OID.FIELD_OID AddSec 20 * 60
FOLDER_OID.FORM_OID.FIELD_OID AddMin FOLDER.FORM.FIELD

And functions to calculate the differences between date/times:

age(*.FORM.DOB, *.FORM.VSDT)
dayspan(*.FORM.VSDT1, *.FORM.VSDT2)
timespan(*.FORM.DOB, *.FORM.VSDT)

String length comparisons use a 'Length' function. The following is equivalent to the 'LengthIsGreaterThanOrEqual' Rave check function:

length( FOLDER_OID.FORM_OID.FIELD_OID ) <= 10

Everything is case-insensitive. The following are equivalent:

FOLDER_OID.FORM_OID.FIELD_OID.IsEmpty
Folder_OID.Form_OID.field_oid.isempty
FOLDER_OID.FORM_OID.FIELD_OID.ISEMPTY

Whitespace is generally ignored, except that '(' must follow immediately after function names. This is valid:

age(*.FORM.DOB, *.FORM.VSDT)

This is not valid because of the space between 'age' and '(':

age (*.FORM.DOB, *.FORM.VSDT)

Custom functions can be called using the 'customfunction' function, or 'cf' for short:

customfunction('cf_name')
cf('cf_name')

and can reference the previous step:

FOLDER_OID.FORM_OID.FIELD_OID.customfunction('cf_name')