Clinical Query Language (CQL) Reference

You can use Clinical Query Language (CQL) to access, retrieve, and interact with clinical data in Veeva Clinical DataBase (CDB). This guide provides details on how to best utilize CQL, and outlines its syntax, structure, clauses, and operators. Although CQL queries share many syntax elements with Structured Query Language (SQL), CQL statements allow you to perform queries specifically for EDC data using a streamlined, clinical-focused syntax.

Availability: Clinical DataBase (CDB) is only available to CDB license holders. Contact your Veeva Services representative for details.

When you query data in CDB Workbench, it passes a CQL statement that specifies the objects to query in the FROM clause, the fields to retrieve in the SELECT clause, and any optional filters to apply (in the WHERE clause).

The following example query returns all data items from the Demographics and Inclusion Criteria forms in the Cholecap 2019 Phase 1 study.

SELECT *
FROM F.Demographics, F.Inclusion_Criteria

CQL’s Clinical Context

CQL is aware of common clinical data patterns and relationships. This “context” provides a language syntax that is simpler than general purpose query languages like SQL. CQL is aware of the following predefined objects and relationships:

Context Element Description Examples
Study

All clinical data is collected within the context of a Study, which has a predefined structure of time-points and data, as well as predefined workflows for collecting, reviewing, cleaning, and locking that data.

IMG-0314-A, TEL2019-1
Site

A Site where clinical data is collected.

101
Country

The country (represented by the Study Country object in Vault EDC) where a Site is located.

USA, UK
Subject

All clinical data within a clinical trial is collected about a Subject enrolled in that Study.

1001, 1002
Event

All data is collected within the context of a specific collection point. This collection point is an “Event”. This often corresponds with a “visit”.

Enrollment Visit, Visit 1, Visit 2
Header

All of the Forms collected for a given Subject at a given collection point (Event) share the same context. You can query for this context using the header. The header is a quick way to return all context objects that exist above the form in the Workbench’s object hierarchy.

@HDR
Form

The collection of data items collected on a Form.

Vital Signs, Medical History
Data Item

Specific data elements (Items) collected about a Subject at a specific collection point in the Study.

Date of Birth, Systolic Blood Pressure, Eye Color
Properties

All of the context elements listed above have additional properties describing various aspects of the element. These properties can represent the state of the object or basic information, such as the item’s name or the date it was last modified. Most properties of an element are returned by function(), however, some basic properties such as Name, ID, etc. can be returned using dot notation.

Locked(Event 1), Item1.ID

Queryable Data

To create queries in CQL, it’s important to understand what data is queryable and the structure of that data. You can use the DESCRIBE and SHOW keywords to return lists of queryable data with CQL.

Describe

You can create a query with the DESCRIBE keyword to return details about the schema.

CQL supports DESCRIBE for the following data elements:

  • HEADER
  • FORM
  • ITEMGROUP
  • ITEM
  • REFERENCE_OBJECT

When you call DESCRIBE, CQL returns every field within that table or object.

DESCRIBE Form

Calling DESCRIBE for a form returns a list of all items (with the Name and DataType) included on the form.

DESCRIBE Form VITALS

This query returns a list of all of the items on the Vitals form for the Cholecap 2019 - Phase 1 study.

  Name Data Type
Form Form.Name Text(100)
Form.SeqNbr Int
Item Group ItemGroup.Name Text(100)
ItemGroup.SeqNbr Int
Item Pulse Int
Item Systolic_Blood_Pressure Text(255)
Item Diastolic_Blood_Pressure Text(255)
Item Temperature Int

Show

You can also create a query with the SHOW keyword to return a list of possible values. You can apply SHOW to event groups, events, forms, and codelist items. You can also use SHOW to return a list of Studies within the current vault.

SHOW Studies

You can use SHOW to return a list of Studies within the current vault:

SHOW STUDIES

SHOW EVENTGROUPS

You can use SHOW to return a list of Event Groups within the current Study:

SHOW EVENTGROUPS

SHOW EVENTS

You can use SHOW to return a list of Events within the current Study:

SHOW EVENTS

SHOW FORMS

You can use SHOW to return a list of Forms within the current Study:

SHOW FORMS

SHOW CODELIST ITEMS

You can use SHOW to return a list of Codelist Items within a given Codelist. Note that you must provide the name of a codelist-type data item.

SHOW CODELIST <DATAITEM>

SHOW VIEWS

You can use SHOW to return a list of Views within your Study.

SHOW Views

SHOW Reference

You can use SHOW to return a list of Reference Objects within your Study.

SHOW Reference

System Listings

You can access System Listings via CQL using CALL. System Listings are listings generated for raw-type exports that contain contextual information about the study and collected data.

  • Sys_Sites: CALL Sys_Sites
  • Sys_Subjects: CALL Sys_Subjects
  • Sys_Events: CALL Sys_Events
  • Sys_Forms: CALL Sys_Forms
  • Sys_ILB: CALL Sys_ILB
  • Sys_Links: CALL Sys_Links

Views

You can access Views via CQL using SHOW VIEWS. This returns a list of all existing Views for the current Study. Views are specialized listings. You can also reference Views in the selection when writing CQL for use with another View. To do so, use the Name (Title) of the View as the source.

CQL Limitations when Defining Views

The following CQL functionality isn’t supported when defining a View:

  • select *
  • UnPivot()
  • Duplicate column aliases
  • @Form attributes other than @Form.SeqNbr in the projection
  • @ItemGroup attributes other than @ItemGroup.SeqNbr in the projection

CQL Limitations when Referencing Views

The following are limitations when referencing a View in a custom listing:

  • Referencing a View inside another View isn’t supported.
  • Inclusion of a view’s @Form and @ItemGroup attributes in the projection or filter (WHERE clause) isn’t supported.
  • If using On Subject ALIGN, the View must not use UNALIGN.
  • When joining a View with another Form or View using On Subject, the View must use On Subject.

On Subject Joins in Views

Views support On Subject ALIGN and On Subject UNALIGN when a joining a View with another Form or View.

To perform an on subject join between a View and a Form, the view’s View Definition must contain On Subject. If not, CQL returns the following error:

“View can only be joined in the same way as its definition. Please ensure On Subject alignment is the same between View definition and View Reference.”

View Definition Using On Subject ALIGN

The View Definition below retrieves the medications that subjects are taking for an Adverse Event. This View is called “View_AE_CM\OnSubjectALIGN”:

select @HDR.Site.Name, @HDR.Subject.Name,
  @Form.SeqNbr, @ItemGroup.SeqNbr,
  ae.AETERM, ae.AESTDAT, ae.AEONGO, ae.AEENDAT, ae.AESEV,
  cm.CMTRT, cm.CMSTDAT, cm.CMONGO, cm.CMENDDAT
from AdverseEvent as ae, ConcomitantMedication as cm On Subject ALIGN
where (@Form.Status = 'submitted__v' or @HDR.Event.Status IN ('did_not_occur__v'))
and AETERM is not null 
order by @HDR.Subject.Name, @Form.SeqNbr

Now, this View can be joined with another Form, VitalSigns, to get vitals such as Height, Weight, or BMI for these subjects. This join can be done using both On Subject ALIGN and On Subject UNALIGN.

select @HDR.Site.Name, @HDR.Subject.Name,
  @Form.SeqNbr, @ItemGroup.SeqNbr,
  algn.AETERM, algn.AESTDAT, algn.AEONGO, algn.AEENDAT, algn.AESEV,
  algn.CMTRT, algn.CMSTDAT, algn.CMONGO, algn.CMENDDAT,
  vtls.HEIGHT, vtls.WEIGHT, vtls.BMI, vtls.SYSBP
from View_AE_CM_OnSubjectALIGN as algn, VitalSigns as vtls On Subject ALIGN
where (@Form.Status = 'submitted__v' or @HDR.Event.Status IN ('did_not_occur__v'))
select @HDR.Site.Name, @HDR.Subject.Name,
  @Form.SeqNbr, @ItemGroup.SeqNbr,
  algn.AETERM, algn.AESTDAT, algn.AEONGO, algn.AEENDAT, algn.AESEV,
  algn.CMTRT, algn.CMSTDAT, algn.CMONGO, algn.CMENDDAT,
  vtls.HEIGHT, vtls.WEIGHT, vtls.BMI, vtls.SYSBP
from View_AE_CM_OnSubjectALIGN as algn, VitalSigns as vtls On Subject UNALIGN
where (@Form.Status = 'submitted__v' or @HDR.Event.Status IN ('did_not_occur__v'))
View Definition Using On Subject UNALIGN

The View Definition below retrieves the medications that subjects are taking for an Adverse Event. This View is called “View_AE_CM\OnSubjectUNALIGN”:

select @HDR.Site.Name, @HDR.Subject.Name,
  @Form.SeqNbr, @ItemGroup.SeqNbr,
  ae.AETERM, ae.AESTDAT, ae.AEONGO, ae.AEENDAT, ae.AESEV,
  cm.CMTRT, cm.CMSTDAT, cm.CMONGO, cm.CMENDDAT
from AdverseEvent as ae, ConcomitantMedication as cm On Subject UNALIGN
where (@Form.Status = 'submitted__v' or @HDR.Event.Status IN ('did_not_occur__v'))
and AETERM is not null 
order by @HDR.Subject.Name, @Form.SeqNbr

Views that contain On Subject UNALIGN in their definition can only be joined to another Form using On Subject UNALIGN, as shown below:

select @HDR.Site.Name, @HDR.Subject.Name,
  @Form.SeqNbr, @ItemGroup.SeqNbr,
  unalgn.AETERM, unalgn.AESTDAT, unalgn.AEONGO, unalgn.AEENDAT, unalgn.AESEV,
  unalgn.CMTRT, unalgn.CMSTDAT, unalgn.CMONGO, unalgn.CMENDDAT,
  vtls.HEIGHT, vtls.WEIGHT, vtls.BMI, vtls.SYSBP
from View_AE_CM_OnSubjectALIGN as unalgn, VitalSigns as vtls On Subject UNALIGN
where (@Form.Status = 'submitted__v' or @HDR.Event.Status IN ('did_not_occur__v'))

Reference Objects

To retrieve a list of all reference objects for your Study, use the SHOW keyword:

SHOW Reference

Then, you can use the DESCRIBE keyword to retrieve a list of Items on a given reference object:

DESCRIBE Reference <Reference_Object_Name>

Use the ReferenceRelations keyword to retrieve a table of key value pairs for the following properties: reference_object_name,related_form, related_item, and related_key.

ReferenceRelations <Reference_Object_Name>

For text-type reference object Items, CQL supports the following functions:

  • CONCAT
  • LENGTH
  • TRIM
  • LTRIM
  • RTRIM
  • UPPER
  • LOWER
  • LEFT
  • RIGHT

For date-type reference object Items, CQL supports the following functions:

  • ADDDATE
  • SUBDATE
  • DATEDIFF
  • DATE_FORMAT
  • SITENORMALIZEDDATE
  • RAWDATE
  • SDTMDATEFORMAT
  • STR_TO_DATE
  • CURDATE
  • NOW
  • YEAR
  • MONTH
  • WEEK
  • DAY
  • HOUR
  • MINUTE
  • SECOND
  • LAST_DAY

CQL Limitations for Reference Objects

CQL limitations apply when working with reference objects.

The following functions are not available for use with reference data:

  • FROZEN
  • ILB
  • LABEL
  • LASTCODED
  • LASTMODIFIEDDATE
  • LOCKED
  • SIGNED
  • STATUS

Query Syntax & Structure

CQL queries return a tuple: a table of data with a defined order of columns. In order to return a tuple, your CQL query must specify:

  • PROJECTION: The specific data elements that you want to retrieve.
  • SELECTION: The specific data tables in which the data elements in the projection exist.
  • FILTER (Optional): The matching criteria for the Data Elements to be returned (these don’t have to be included in the tuple and can be referenced through the implicit relationships in the study).
  • ORDER (Optional): The order in which the rows are returned in the tuple.

Projection

The PROJECTION of your CQL query specifies which data elements you’re retrieving and the order of those elements in the result set. You can specify the list of fields explicitly using the DATAITEM names, or you can use wildcard shortcuts.

Use a SELECT statement to describe the projection.

Wildcards

You can use a wildcard asterisk on your SELECT statement to return all columns, in layout order, for the associated DATAITEMS within the FORM context specified in the FROM clause.

SELECT *
FROM Demographics

Context-Qualified Asterisk

Instead of a wildcard asterisk, you can use a context-qualified asterisk to return all DATAITEMS within the context of the qualifier.

In the current release, only the FORM and ITEMGROUP qualifiers are supported.

SELECT <Qualifier>.*
FROM <Form_Name>

SELECT Creation_Criteria.*
FROM Demographics

This example query would return all DATAITEMS in the Creation Criteria item group on the Demographics form in the Cholecap 2019 Phase 1 study.

Data Items

Alternatively, you can specify specific DATAITEMS to retrieve. Any DATAITEM that exists on the specified FORM can be selected in the projection. If you only specify one FORM, then you can reference those columns directly. If you specified multiple FORMs, then you must qualify each DATAITEM with the FORM name or alias.

SELECT <Qualifier>.<DataItem>
FROM <Form_Name>

SELECT Demographics.Subject_Date_of_Birth, Enrollment.Randomization_Number
FROM Demographics, Enrollment

This example query would return all values for the Date of Birth item on the Demographics form and the Randomization Number item on the Enrollment form.

Data Functions

You can also specify functions which can be returned as specific columns of the result set. Functions can take DATAITEMS as arguments, as well as many of the contexts listed above.

You can access all the properties of a DATAITEM with a function, except for Name and ID.

You can’t use Item Groups in functions.

For a complete list of functions, accepted arguments, and definitions, see below.

SELECT STATUS(Demographics.Subject_Date_of_Birth)
FROM Demographics

This example query would return the Status of the Date of Birth item on the Demographics form in the Cholecap 2019 Phase 1 study.

Distinct

You can use DISTINCT to return only unique instances of the values in a given column or across a set of columns.

SELECT DISTINCT <Qualifier>.<DataItem>
FROM <Form_Name>

SELECT DISTINCT Dosing.Dosage_Amount
FROM Dosing

This query would return all unique values for the Dosage Amount item on the Dosing form in the Cholecap 2019 Phase 1 study.

In the current release, CDB won’t display cell highlighting for listings where the CQL statement uses DISTINCT.

Aliases (AS)

You can use AS to define aliases for forms and data items in your query. Aliases can be useful when a form or data item has a longer name, and you want to reference it multiple times.

You can provide aliases for specific columns in your projection. If you provide an alias for a data item, Workbench renames the item’s column with the alias in the Listing. Aliases for data items are especially useful when a data item has a longer name, like the example below. Using shorter aliases for data items can help limit the need for horizontal scrolling while viewing your results in their Core Listing.

You can also provide aliases for forms. This is useful you want to reference your form multiple times in a single query. After you set the alias, you need only use the alias, and not the form name, to reference the form.

SELECT <Qualifier>.<DataItem> AS <Item_Alias>
FROM <Form_Name> as <Form_Alias>

SELECT Demographics.Subject_Date_of_Birth as DOB, Enrollment.Randomization_Number_from_IRT as ID
FROM Demographics, Enrollment

This example query would return all values for the Date of Birth item on the Demographics form and the Randomization Number item on the Enrollment form.

Operational Projection Elements

In addition to DATAITEMS, you can query for operational data that may be useful alongside your query results. The most powerful of these operational elements it the Header. The Header is a summary of the most important study metadata that relates to the forms and data items you’re requesting. You can also request information about the Study, Site, Subject, Event Group, and Event.

You can return Header information in any projection using the @HDR variable notation. You can query for @HDR information with a wildcard to retrieve all queryable metadata, or query for specific header information related to a Form.

SELECT @HDR, <Qualifier>.<DataItem>
FROM <Form_Name>

SELECT @HDR.SITE, *
FROM Dosing

The query above would return summary information for the Site.

Header Summaries

You can create specific summaries within a given context, using a predefined set of elements and column order. The following header contexts are available:

  • @HDR.Study
  • @HDR.Site
  • @HDR.Subject
  • @HDR.Event

In the current release, @HDR.EventGroup does not include a summary. You must specify a property to use the Event Group context.

If you use the @HDR variable and the context alone, such as @HDR.Study, CQL returns only a limited set of the available properties.

Header Context Returned Properties
@HDR.Study Study.Name
@HDR.Site Site.Name, Site.PI
@HDR.Subject Subject.Name, Subject.Status
@HDR.Event Event.Name, Event.Date, Event.Status
Header Detail Properties

You can also target specific elements of the header to return in the selection or to use in a filter clause. Append the property name to the @HDR context using dot notation to retrieve that property. For example, use @HDR.Study.Phase to return the Phase for the Study, or use @HDR.Event.Date to return the Event Date for an Event.

The following properties are available for each @HDR context element, using dot notation.

Header Context Available Properties
@HDR.Study
  • ID
  • Name
  • Phase
  • LastModifiedDate
  • Status
  • Locked
  • OID
  • ExternalID
@HDR.Site
  • ID
  • Name
  • Number
  • LastModifiedDate
  • PI
  • Country (returns country abbreviation)
  • CountryName
  • Timezone
  • Status
  • OID
  • ExternalID
@HDR.Subject
  • ID
  • Name
  • LastModifiedDate
  • WithdrawnDate
  • Key
  • Status
  • ExternalID
  • Arm
  • Cohort
  • Substudy
  • EndOfStudyDate
  • EndOfTreatmentDate
  • EnrolledDate
  • InitialConsentDate
  • LostToFollowUpDate
  • RandomizedDate
  • ScreenedDate
  • ScreenFailedDate
  • StartedFollowUpDate
  • StartedTreatmentDate
  • WithdrawnDate
@HDR.EventGroup
  • ID
  • Name
  • Label
  • SeqNbr
  • Type
@HDR.Event
  • ID
  • Name
  • Label
  • LastModifiedDate
  • Date
  • Status
  • Frozen
  • Locked
  • Signed
  • SDV
  • DMR
  • OID
  • Dynamic
  • EventType
  • ChangeReason
  • PlannedDate
  • ExternalID
  • OpenQuery
  • AnsweredQuery
  • ClosedQuery
  • Version
  • VisitMethod

Form & Item Group Properties

You can target properties of the Form and Item Group in the selection or in a filter clause. Append the property name to the @Form or @ItemGroup using dot notation to retrieve that property. For example, use @Form.CreatedDate to return the Created Date for a Form.

Context Available Properties
@Form
  • Name
  • Label
  • DataSource
  • SeqNbr
  • Status
  • ILB
  • ILBReason
  • SDV
  • DMR
  • Frozen
  • Locked
  • Signed
  • SDVDate
  • DMRDate
  • FrozenDate
  • LockedDate
  • LinkCreatedDate
  • LinkId
  • Signed
  • SignatureDate
  • CreatedDate
  • SubmissionDate
  • SubmissionCount
  • LastModifiedDate
  • Version
  • ID
  • ExternalID
@ItemGroup
  • Name
  • SeqNbr

You can target Items used in Item to Form linking using the @FormLink notation. The Form that contains the FormLink item is the Linking Form. The FormLink item is linked to Linked Form. In order to use the @FormLink notation, you must provide the name of the FormLink item on the Linking Form and the Item you want to target on the Linked Form.

@FormLink.<FormLink-Name>.<Item-Name>

If the Item in the Linked Form is used across more than one Item Group, then you must also provide the Name of the Item Group.

@FormLink.<FormLink-Name>.<ItemGroup-Name>.<Item-Name>

If the Linking Form uses the same FormLink Item across multiple Item Groups, then you must specify the Name of the Item Group FormLink.

@FormLink.<ItemGroup-Name-FormLink>.<FormLink-Name>.<ItemGroup-Name>.<Item-Name>

The following example assumes that there are 2 FormLinks on the AE form: ae_to_cm and ae_to_mh. You can access Items in the Linked Form using the following CQL:

select  @HDR.Subject.Name, AETERM, AESTDAT, AEONGO,@FormLink.ae_to_cm.CMTRT, @FormLink.ae_to_cm.CMSTDAT, @FormLink.ae_to_cm.CMONGO, @FormLink.ae_to_cm.CMENDAT,@FormLink.ae_to_mh.MHTERM, @FormLink.ae_to_mh.MHSTDAT, @FormLink.ae_to_mh.MHONGO, @FormLink.ae_to_mh.MHENDAT
from `EDC`.`AE`
where @For.Status = 'submitted__v' or @HDR.Event.Status IN ('did_not_occur__v') 

The FormLink ae_to_cm is between the ae_to_cm item and the CM form. You can access the CMONGO item in the Linked Form CM by using @FormLink.ae_to_cm.CMONGO.

The FormLink ae_to_mh is between the ae_to_mh item and the MH form. You can access the MHSTDAT item in the Linked Form MH by using @FormLink.ae_to_mh.MHSTDAT.

You can use Items denoted by the @FormLink notation in the WHERE clause, Order By clause and Group By clause.

The following CQL features are supported with FormLink Items:

  • UNION and UNION ALL
  • On Subject ALIGN and UNALIGN
  • Subqueries
  • UNPIVOT

Query Properties

You can target properties of Queries in the selection or in a filter clause. Append the property name to @QRY or @QRYMSG using dot notation to retrieve that property. For example, use @QRY.ID to retrieve the ID of the Query.

@QRY

The following properties are querable for the Query object using @QRY:

Property Description
ID

The id autogenerated for the query.

Name

The Name of the query as defined in EDC (VV#####). Note that for third party data, this number is still a unique identifier.

Status

The current Status of the query (Open, Answered, or Closed)

Category

The origin of the query (Manual or System-generated)

FirstMessage

The first Query Message created in the query (comment entered when opening the query). This is not a list of all query messages (comments) for a query.

LatestMessage

The latest (most recent) Query Message created in the query (comment entered when responding to the query). This is not a list of all query messages (comments) for a query.

CreatedDate

The date and time the query was created (opened).

CreatedBy

The username of the user who created (opened) the query.

LastModifiedDate

The date and time when the query was last modified.

LastModifiedBy

The username of the user who last modified the query.

ItemName

The Name of the Item that the query was opened on. If the query is on the Event Date, this returns null.

EventName

The Name of the Event associated with the query.

EventDate

The Event Date of the Event associated with the query.

SubjectName

The Name of the Subject associated with the query.

SubjectStatus

The Subject Status of the Subject associated with the query.

Site

The Site assigned to the Subject associated with the query.

SiteCountry

The Study Country of the Site assigned to the Subject associated with the query.

Form

The Name of the Form associated with the query. If the query is on the Event Date, this returns null.

FormSeqNbr

The Sequence Number of the Form associated with the query. If the query is on the Event Date, this returns null.

FormSource

The Source that the query’s data point originated from, for example, “Lab”, “EDC”, or “eCOA”.

ItemGroupSeqNbr

The Sequence Number of the Item Group associated wtih the query. If the query is on the Event Date, this returns null.

OriginSystem

The Name of the Source System where the query originated (EDC, CDB, etc.). In the current release, CQL only returns the value “CDB” for this property for queries opened via Checks in CDB.

OriginName

The Name of the Listing where the query was opened. If the query wasn’t opened in CDB, this returns null.

OriginID

The ID of the Listing where the query was opened. If the query wasn’t opened in CDB, this returns null or can be optionally set using the CDB Open Query API.

OpenToReply

The date difference between the query’s Created Date and the query’s First Response Date.

RuleID

The ID of the Rule that generated the query (for system-generated queries).

TriggerID

The ID of the custom Trigger that generated the query.

CausedDataChange

Whether the data changed after query creation.

RowExternalID

The Row External ID assigned to the row during data import.

@QRYMSG

The following properties are queryable for the Query Message object using @QRYMSG:

Property Description
Status

The Status of the Query Message (Open, Answered, Closed).

Text

The text of the message.

CreatedDate

The date and time that the query message was created.

CreatedBy

The username of the user who created the query message.

Selection

Selection (FROM) is the mechanism by which you specify the Names of the Forms on which the projection operates. In the wildcard asterisk, the selection also specifies the order of the projection’s Forms.

In CQL, FROM always refers to the Form context that the data is selected from. You can’t use any other context in the FROM clause.

Because the Header is accessible from the @HDR variable, you can also select any elements of the Header by themselves if you don’t need the FORM and DATAITEMS. You can use these types of selections to create results listing only operational data by subject. You can filter this selection without providing a FROM when the projection contains only @HDR. However, to use aliasing and subqueries, you must include a FROM clause.

Join on Subject

By default, CQL joins on both Subject and Event. Because of this, if you select from two Forms that are in different Events, CQL will return a row for each Form, instead of a single row per subject.In this case, you can return a single row for each Subject, containing the data from both Forms, by joining on subject only.

To join on subject, append on subject to the list of form identifiers in the selection. There is no limit to the number of identifiers that you can use, but on subject applies to all forms specified.

CQL returns null for any @HDR.EventGroup or @HDR.Event properties when used with on subject because on subject can return data from multiple Event Groups or Events. If you need to retrieve these properties, you can do so by selecting it with the form alias for each Form.

Known Issue: In the current release, CQL doesn’t support the use of COMPACT when joining on subject.

The example query below would return a single row for each Subject with the @HDR.Subject properties, the Subject Initials, Subject DOB, Height, Weight, Pulse, Systolic Blood Pressure, Diastolic Blood Pressure, and Temperature. If the example query didn’t use join by subject, CQL would return a row for the items on the Demographics form and a second row for the items on the Vitals form.

SELECT @HDR.Subject, creation_criteria.subject_initials, creation_criteria.subject_dob, vitals.height, vitals.weight, vitals.pulse__bpm_, vitals.systolic_bp__hhMg, vitals.diastolic_bp__hhMg, vitals.temperature 
FROM demographics, vitals ON subject
Align & Unalign Modifiers

When using on subject with a Form or Item Group that is repeating, you can choose to return data for joined sequences (aligned) or return data even when the sequences don’t align (unaligned). For example, when showing information from a Demographics form and a repeating Adverse Event form, CQL returns the data from the Demographics form in the rows returned for all Adverse Event form instances for the Subject. This behavior is “unaligned” because it is returning the data even when the sequences aren’t aligned. UNALIGN is the default behavior, so explicitly including this modifier in the CQL statement is optional. In this example, “aligned” behavior would return the data from the Demographics form only for the first row returned for all Adverse Event form instances for the Subject. To use the aligned behavior, include the ALIGN modifier.

Advanced Joins

CQL also supports advanced (directional) joins. With advanced joins, you can join forms without first joining to the @HDR.

LEFT JOIN: All records from the first (left) table and any matching data from the second (right) RIGHT JOIN: All records from the second (right) table and any matching data from the first (left) INNER JOIN: Only records from both tables where a match is found

In the current release, CQL doesn’t support outer joins.

You can’t join reference data to other data using advanced joins.

Example: Left Join between Forms

In the CQL statement below, there is a LEFT JOIN between the AE and CM forms, based on the form definition attribute @Form.Subject. Note that Subject.Name is part of the Form Definition and doesn’t come from the @HDR.

select @Form.Subject.Name, @Form.Event.Name,
       AETERM, AESTDAT, CMTRT, CMSTDAT
from AE as ae LEFT JOIN CM as cm
     ON ae.@Form.Subject.Name = cm.@Form.Subject.Name
where @Form.Status = 'submitted__v'

This works without joining to the @HDR because the join condition is based on a @Form attribute (@Form.Subject.Name) and the projection doesn’t contain any @HDR attributes.

Example: Left Join between Forms & @HDR

The CQL query below requires a join with the @HDR since the projection has @HDR attributes. The query below is a LEFT JOIN between @HDR and AE based on Event.ID - the output of this LEFT JOIN is then LEFT JOINed again with CM based on Event.ID and Subject.ID.

In the CQL statement below, the projection contains @HDR attributes, so a join with the @HDR is required. This is a LEFT JOIN between the @HDR and the AE form based on @Form.Event.ID. The output of that join is then joined again with a LEFT JOIN with the CM form based on @Form.Event.ID and @Form.Subject.ID.

select @HDR.Subject.Name, @HDR.Site.Name,
       AETERM, AESTDAT, CMTRT, CMTERM
from @HDR LEFT JOIN AE as ae ON @HDR.Event.ID = ae.@Form.Event.ID
          LEFT JOIN CM as cm ON @HDR.Event.ID = cm.@Form.Event.ID and ae.@Form.Subject.ID = cm.@Form.Subject.ID

Subqueries

CQL supports subqueries.

Subqueries with IN

You can define a subquery that returns a list of values that you can reference within the IN operator of a filter.

SELECT * FROM Randomization
WHERE @HDR.Subject.ID IN (
    SELECT @HDR.Subject.ID FROM Demographics 
    WHERE Creation_Criteria.Sex = 'Female'
)

This query returns all DATAITEMS from the Randomization form for all female subjects.

Subquery Joins

You can also define two SELECT statements and join them together using a subquery, instead of typical JOIN syntax. Use a comma (,) to represent the join, with the second subquery being left-outer-joined to the first. Sub-selects can be aliased, but it’s not required. These joins implicitly include EventId and SubjectId. You can accomplish additional filtering with a filter (WHERE) clause after your subqueries.

SELECT * FROM
    (
        SELECT @HDR.Subject, Creation_Criteria.Subject_Initials, Creation_Criteria.Age_at_Screening as Screening_Age
        FROM Demographics
        WHERE Creation_Criteria.Sex = 'Female'
    ) AS Female_Subjects,
    (
        SELECT @HDR.Subject, Creation_Criteria.Subject_Initials, Creation_Criteria.Age_at_Screening as Screening_Age
        FROM Demographics
        WHERE Creation_Crtieria.Sex = 'Male'
    ) AS Male_Subjects
WHERE Female_Subjects.Screening_Age = Male_Subjects.Screening_Age
Subqueries in Functions

You can use subqueries, including @HDR, @Form header, and DATAITEMS, within functions.

SELECT @HDR.Subject, Body_Temperature,
IF (IFNULL(Body_Temperatore,0) < (SELECT AVG(Body_Temperature) FROM Vitals), 'Below Avg', 'Acceptable') AS CompTemp
FROM Vitals
Correlated Subqueries

CQL allows correlated subqueries for filtering results.

SELECT * FROM Demographics
WHERE Age_at_Screening > (
    SELECT AVG(Age_at_Screening) FROM Demographics
)

Filter

You can use filters to reduce the values of the initial CQL result provided by your Projection and Selection. This is optional. The primary filtering mechanism in CQL is a WHERE clause.

WHERE Status(Form) = 'Complete' AND GENDER = 'Male'

Tip: Core listings return all Forms in the Submitted status. You can edit the WHERE clause to return forms in both the Submitted and In Progress Post Submit statuses. Use the following CQL: WHERE @Form.Status in ('submitted__v', 'in_progress_post_submit__v').

Comparison Functions & Operators

The following functions and operators are usable in a WHERE clause:

Operator Definition
AND Logical AND
OR Logical OR
= Equals
!= Does not equal
> Greater than
< Less than
>= Greater than or equal to
<= Less than or equal to
IS Tests a value against a boolean condition
IS NOT Tests a value against a boolean condition
IS NULL Tests a value against a NULL
IS NOT NULL Tests a value against a NULL
IN() Check whether a value is within a defined set of values
BETWEEN...AND... Check whether a value is within a range of values
CONTAINS Check whether a value is contained within the value
DOES NOT CONTAIN Checks whether a value is not contained within the value

Order

You can use an ORDER BY clause to customize the order of your results.

For example:

SELECT @HDR * 
ORDER BY @HDR.Subject.Name ASC, ETHNICITY

Known Issue: In the current release, Workbench doesn’t support the use of ORDER BY for any data items within a repeating item group.

Comments

If needed, you can also include comments in your CQL statement. To include a comment, enter two dashes and a space (-- ), followed by your comment.

SELECT @HDR, * from EDC.adverse_events
WHERE @Form.Status = 'submitted__v' or @HDR.Event.Status IN ('did_not_occur__v')

-- comment text

Data Aggregation

CQL can perform basic data aggregation on query results. You can reference any element of the header or any DATAITEM in an aggregate function. Aggregate functions accept wildcards, @ variables, and specific DATAITEMS as arguments.

Aggregate Functions

Operator Definition
AVG() Return the average value of the argument
COUNT() Return a count of the number of rows returned
MAX() Returns the maximum (highest) value
MIN() Returns the minimum (lowest) value
SUM() Returns the sum
STDDEV_POP() Population standard deviation
STDDEV_SAMP() Sample standard deviation
VAR_POP() Returns the population standard variance
VAR_SAMP() Returns the sample variance

If you don’t specify an attribute to be counted, CQL treats the request as a count on all columns within that object. This is the equivalent of COUNT(*) on that specific table.

Because WHERE isn’t supported for use with aggregate functions, you can use the HAVING keyword instead. To use HAVING, your CQL projection must have at least one aggregate function.

SELECT COUNT(@HDR.Subject.Name), @HDR.Site.Number
FROM EDC.demographics
GROUP BY @HDR.Site.Number
HAVING COUNT(@HDR.Subject.Name) > 100

Grouping Results

CQL supports GROUP BY syntax as long as there is at least one aggregate function included in your projection.

SELECT COUNT(@HDR.Event), @HDR.Subject
GROUP BY @HDR.Subject

SELECT @HDR, AVG(SYSTOLIC)
FROM Vitals
GROUP BY @HDR.Subject

Result Structure

CQL results are returned in a specific sequence based on the elements you provide in the Projection. CQL includes three methods for quickly identifying what should be included in the projection: the header, the wildcard, and qualified wildcards. You can specify additional columns that should be returned in the results within you query.

Depending on which DATAITEMS you include in your Projection, there is also a specific order in which execution data is sorted.

Form & Data Item Results

As with SELECT @HDR notation, the remaining FORM and DATAITEMS can be returned using SELECT * or SELECT ItemGroup.*. When using these notations, the result set has a default column order, and rows from this section are returned in a specific sort order after following the sort order applied to the Header (if included in the projection).

If you don’t use wildcard notation in your query, you must specify the columns of data you want returned within your projection. The order of the results then matches the hierarchy for the sort options listed below, based on which elements you included in your projection.

Note that any of the objects included in the sort hierarchy are present, even if that specific column isn’t present, the sort hierarchy rules are still applied.

SELECT * Default Column Order

Columns are laid out starting with the FORM attributes listed below and then following the form’s layout order.

  • Form Name
  • Form SeqNum (only if the Form is repeating)
  • Item Group
  • SeqNbr (only if the Item Group is repeating)
  • Item1
  • Item2
  • ItemN

SELECT ItemGroup.* Default Column Order

Columns are laid out starting with the FORM and Item Group attributes listed below, and then following the item group’s layout order.

  • Form Name
  • Form SeqNum (only if the Form is repeating)
  • Item Group
  • SeqNbr (only if the Item Group is repeating)
  • Item1
  • Item2
  • ItemN

Column Titles

CQL titles each column using a specific pattern:

  • @HDR Columns: Object.Property, e.g. “Site.Name” for @HDR.Site.Name
  • Data Items: Name of the Item Definition
  • Alias: For any aliased data, CQL uses the alias as the column title.

Because Forms and Item Groups can repeat, they follow the same Object.Property notation as Header results: Form.Name, ItemGroup.SeqNbr, etc.

Wide & Compact Results

CQL always returns data items with their @Form and @ItemGroup information prepended to the result set. This is the form header. This information is useful for understanding which Forms and Item Group a given data item was collected in. Beyond the form header, you can arrange data items in a wide or compact format. By default, CQL returns results using wide format.

Wide format means that every data item is returned in its own column for every form or item group it was collected in (in the context of the query).

Compact format means that a data item’s results are presented in a single column, regardless of which form or item group it was collected in. This can be useful for comparing item values.

To return results in compact format, specify COMPACT in your SELECT statement:

SELECT COMPACT @HDR, Creation_Criteria.*
FROM Demographics

This query returns the @HDR summary and DATAITEMS in the Demographics form’s Creation Criteria item group in compact format.

Example: Multiple Forms Reusing an Item

In this example, a Study has two forms, Demographics and Informed Consent, that both use the Date of Birth item.

WIDE
Form.Name Form.SeqNbr ItemGroup.Name ItemGroup.SeqNbr Initials Age_at_Screening DOB DOB
Demographics 1 Creation_Criteria 1 CMA 27 02-22-1992 --
Informed_Consent 1 Informed_Consent 1 -- -- -- 02-22-1992
COMPACT
Form.Name Form.SeqNbr ItemGroup.Name ItemGroup.SeqNbr Initials Age_at_Screening DOB
Demographics 1 Creation_Criteria 1 CMA 27 02-22-1992
Informed_Consent 1 Informed_Consent 1 -- -- 02-22-1992

Example: Repeating Form

In this example, a study has a repeating Adverse Event form.

WIDE
Form.Name Form.SeqNbr ItemGroup.Name ItemGroup.SeqNbr Start_Date End_Date Start_Date End_Date
Adverse_Event 1 AE_Duration 1 05-18-2019 05-23-2019 -- --
Adverse_Event 2 AE_Duration 1 -- -- 11-27-2019 11-29-2019
COMPACT
Form.Name Form.SeqNbr ItemGroup.Name ItemGroup.SeqNbr Start_Date End_Date
Adverse_Event 1 AE_Duration 1 05-18-2019 05-23-2019
Adverse_Event 2 AE_Duration 1 11-27-2019 11-29-2019

Example: Repeating Item Group

In this example, a study has a Physical Exam form with a repeating Item Group for Exam by Body Area.

WIDE
Form.Name Form.SeqNbr ItemGroup.Name ItemGroup.SeqNbr body_area date_of_exam body_area date_of_exam
physical_exam 1 exam_by_body_area 1 Head 12-11-2019 --- ---
physical_exam 1 exam_by_body_area 2 --- --- Chest 12-11-2019
COMPACT
Form.Name Form.SeqNbr ItemGroup.Name ItemGroup.SeqNbr body_area date_of_exam
physical_exam 1 exam_by_body_area 1 Head 12-11-2019
physical_exam 1 exam_by_body_area 2 Chest 12-11-2019

Log Form Events

Some Events within EDC don’t have an Event Date associated with them. These events are “log” events, and the FORMS within these events are “Log Forms”. Common examples of a log form include Adverse Event and Concomitant Medication forms. Information within these log forms is collected independent of scheduled events.

When a log form is included in the projection, CQL groups these forms under a Log Event. The Log Event is always listed after all other event groups in the result set.

Functions

CQL supports various functions to provide additional information around a given DATAITEM or FORM. You can include any of these functions in the CQL Projection, Filter, and in the Order By clause. CQL also includes a set of functions that are specific to querying clinical data.

Clinical

The following clinical functions are available:

DESCRIPTION

Returns the description provided for the specified data item’s Item Definition.

Syntax
DESCRIPTION(DATAITEM)
Example
SELECT DESCRIPTION(Randomization.Randomization_Number)
FROM Enrollment

This query returns the Description value for the Randomization Number item on the Enrollment form.

DMR

Returns true if the DATAITEM has been data management reviewed (DMR), otherwise, it returns false.

Syntax
DMR(DATAITEM) 
Example
SELECT @HDR.Subject.Name, @HDR.Site.Name, @HDR.Event.Name, @HDR.Event.Date,
       AESTDAT, DMR(AESTDAT) as  `Is AE Start Date DMR`
FROM AE where @Form.Status = 'submitted__v' or @HDR.Event.Status IN ('did_not_occur__v')

FROZEN

Returns true or false based on whether or not the given data item is currently frozen. If this value is NULL, it is inherited from its parents (Item Group and Form).

Syntax
FROZEN(DATAITEM)
Example
SELECT FROZEN(Creation_Criteria.Initials)
FROM Demographics

This query returns true if the Initials item on the Demographics form is frozen. If the Initials item is unlocked, this query returns false.

HELPTEXT

Returns the help text provided for the specified data item’s Item Definition.

Syntax
HELPTEXT(DATAITEM)
Example
SELECT HELPTEXT(Randomization.Randomization_Number)
FROM Enrollment

This query returns the Help Text (the Help Content property for items created in Vault EDC) value for the Randomization Number item on the Enrollment form.

HINTLABEL

Returns the Hint Label provided for the specified data item’s Item Definition.

Syntax
SELECT HINTLABEL(Randomization.Randomization_Number)
FROM Enrollment

This query returns the Hint Label (the Hint Label property for items created in Vault EDC) value for the Randomization Number item on the Enrollment form.

ILB

Returns true or false based on whether or not the given DATAITEM is marked as Intentionally Left Blank. If this value is NULL, it is inherited from its parent form.

Syntax
ILB(DATAITEM)
Example
SELECT @HDR, *
FROM Dosing
WHERE ILB(Dosage_Amount) = FALSE 

This query returns the header summary (@HDR) and all data items (*) from the Dosing form for any subjects where the Dosage Amount item is not marked as Intentionally Left Blank.

ILBREASON

Returns the Change Reason associated with a DATAITEM or FORM that was marked as Intentionally Left Blank.

Syntax
ILBREASON(DATAITEM)
Example
SELECT ILBREASON(Dosage_Amount)
FROM Dosing
WHERE ILB(Dosage_Amount) = TRUE

This query returns the Change Reason for Dosage Amount items on the Dosing form that were marked as intentionally left blank. This query filters the results so that CQL doesn’t return rows for Dosage Amount items that weren’t marked as intentionally left blank.

LABEL

Returns the label provided for the specified DATAITEM’s Item Definition. You can choose to specify an alternate locale to return a localized label. By default, LABEL() returns the label in the current user’s locale. See a list of Vault CMDS locale values here.

Syntax
LABEL(DATAITEM,['locale'])
Example
SELECT LABEL(Randomization.Randomization_Number, 'es_PR')
FROM Enrollment

This query returns localized (for es_PR, or Puerto Rico) item label for the Randomization Number item on the Enrollment form.

CODELABEL

Returns the Label for the Codelist Item selected for the codelist-type data item.

Syntax
CODELABEL(DATAITEM)
Example
SELECT CODELABEL(adverse_event.AEACTN)
FROM Adverse_Event

This query returns the Label of the Codelist Item selected for the AEACTN (Action Taken with Study Drug) codelist item.

LASTMODIFIEDDATE

Returns the date on which the DATAITEM was last modified (for data in Vault EDC, this is based on the Last Modified Date field on the Item object).

Syntax
LASTMODIFIEDDATE(DATAITEM)
Example
SELECT LASTMODIFIEDDATE(Randomization.Randomization_Number)
FROM Enrollment

Returns the date that the Randomization Number item on the Enrollment form was last modified.

LOCKED

Returns true or false based on whether or not the given DATAITEM is currently locked. If this value is NULL, it is inherited from its parents (Item Group and Form).

Syntax
LOCKED(DATAITEM)
Example
SELECT LOCKED(Creation_Criteria.Initials)
FROM Demographics

This query returns true if the Initials item on the Demographics form is locked. If the Initials item is unlocked, this query returns false.

SDV

Returns true if the DATAITEM has been source data verified (SDV), otherwise, it returns false.

Syntax
SDV(DATAITEM) 
Example
SELECT @HDR.Subject.Name, @HDR.Site.Name, @HDR.Event.Name, @HDR.Event.Date,
       AETERM, SDV(AETERM) as  `Is AE Term SDV`
FROM AE where @Form.Status = 'submitted__v' or @HDR.Event.Status IN ('did_not_occur__v')

SIGNED

Returns true or false based on whether or not the given DATAITEM has been signed. If this value is NULL, it is inherited from its parents (Item Group and Form).

Syntax
SIGNED(DATAITEM)
Example
SELECT SIGNED(Creation_Criteria.Initials)
FROM Demographics

This query returns true if the Initials item on the Demographics form has been signed. If the Initials item has not been signed, this query returns false.

STATUS

Returns the status of a DATAITEM. You can also use this function to return the status of a form by using dot notation and the @Form variable, instead of STATUS(). See the second example.

Syntax
STATUS(DATAITEM)
Examples
SELECT STATUS(Randomization.Randomization_Number)
FROM Enrollment

This query returns the Status of the Randomization Number item on the Enrollment form.

SELECT @Form.Status
FROM Enrollment

This query returns the Status of the Enrollment form.

UOM

Returns the Unit of Measure (UOM) for the DATAITEM

Syntax
UOM(DATAITEM)
Example
SELECT UOM(Vitals.Weight)
FROM Vitals

This query returns the UOM for the Weight item on the Vitals form.

UOMTRANSLATED

Returns the Unit of Measure (UOM) of the default unit, instead of the user-entered unit (e.g. Fahrenheit instead of Celsius)

Syntax
UOMTRANSLATED(Vitals.Temperature)
Example
SELECT TRANSLATED(Vitals.Temperature)
FROM Vitals

This query returns “Fahrenheit”, the default unit for the Temperature item.

TRANSLATED

Returns the value in the default unit, translated (converted) into the default unit from the user-entered unit

Syntax
TRANSLATED(DATAITEM)
Example
SELECT TRANSLATED(Vitals.Temperature)
FROM Vitals

This query returns the value in fahrenheit (default unit) from the Temperature item on the Vitals form, even if the site user entered the temperature in Celsius.

FILL

Returns a specified fill value from an Item in a non-repeating Item Group for cells that return CQL NULL. This function is only available for use in the projection.

Syntax
FILL(DATAITEM)
Example
select @HDR.Subject.Name, @HDR.Site.Name,
       @Form.SeqNbr, @ItemGroup.SeqNbr,
       CMTRT, fill(CMTRT) as fill_CMTRT, CMSTDAT, CMONGO
from CM
where (@Form.Status = 'submitted__v' or @HDR.Event.Status IN ('did_not_occur__v'))

In this example, the CM form contains a repeating Item Group and a non-repeating Item Group. The CMTRT item is in the non-repeating group, and so it returns -- (for NULL) in the rows for the repeating Item Group instances. This example returns the value for the CMTRT item for the null cells for that column in the fill_CMTRT column.

FormName, FormSeqNbr, ItemGroupName, ItemGroupSeqNbr

Returns the Name and Sequence Number of the Form and Item Group of the data item.

Syntax
FormName(Item), FormSeqNbr(Item), ItemGroupName(Item), ItemGroupSeqNbr(Item)
Example
SELECT FormName(ae_term), FormSeqNbr(ae_term), ItemGroupName(ae_term), ItemGroupSeqNbr(ae_term)
FROM adverse_event

Labs

The following functions are available for use with data from EDC’s Labs module.

SPECIMENTYPE

Returns the Specimen Type of the Analyte specified in the LBTEST column. Use the LBTEST item with this function.

Syntax
SpecimenType(LBTEST)
Example
SELECT LBTEST, SpecimenType(LBTEST) FROM edc.baseline_labs

The example above returns the LBTEST item and the Specimen Type for the test.

TESTINGMETHOD

Returns the Testing Method of the Analyte specified in the LBTEST column. Use the LBTEST item with this function.

Syntax
TestingMethod(LBTEST)
Example
SELECT LBTEST, TestingMethod(LBTEST) FROM edc.baseline_labs

The example above returns the LBTEST item and the Testing Method for the test.

LOINCCODE

Returns the LOINC Code of the Analyte specified in the LBTEST column. Use the LBTEST item with this function.

Syntax
LOINCCode(LBTEST)
Example
SELECT LBTEST, LOINCCode(LBTEST) FROM edc.baseline_labs

The example above returns the LBTEST item and the LOINC Code for the test.

ANALYTECODE

Returns the Analyte Code of the Analyte specified in the LBTEST column. Use the LBTEST item with this function.

Syntax
AnalyteCode(LBTEST)
Example
SELECT LBTEST, AnalyteCode(LBTEST) FROM edc.baseline_labs

The example above returns the LBTEST item and the Analyte Code for the test.

LABLOCTITLE

Returns the Lab Title for the Lab Location. LBLOC returns only the Lab ID. Use the LBLOC item with this function.

Syntax
LabLocTitle(LBLOC)
Example
SELECT LBLOC, LabLocTitle(LBLOC) FROM edc.baseline_labs

The example above returns the Lab ID (LBLOC) and the Lab Location Title for the Lab Location chosen on the Baseline Labs form.

OVERRIDEREASON

Returns the Override Reason that the site user provided when entering a Normal Override. Use the LBOVRDNRLO and LBOVRDNRHI items with this function.

Syntax
OverrideReason(LBOVRDNRLO), OverrideReason(LBOVRDNHRI)
Example
SELECT OverrideReason (LBOVRDNRLO), OverrideReason(LBOVRDNRHI) FROM edc.baseline_labs

Coding

The following functions allow you to retrieve information about the assigned coded terms and status of coding forms. Vault Coder supports coding with the MedDRA and WHODrug (B3 and C3) dictionaries.

If you use these functions on a Form that isn’t configured to use Vault Coder, CQL will return an error.

CODEDTERM

If a coded term exists (the form’s Code Request is in the Coded or Autocoded status), returns the Coded Term for a data item. By default, CQL returns the Preferred Term for the MedDRA dictionary and the Preferred Name for the WHODrug dictionary. You can specify a term level to return another level, such as HLT or LLT.

Syntax
CODEDTERM(Item, 'TermLevel')
Example
SELECT CODEDTERM(ae_term.ae, 'Primary Path') as `Primary Path`,
       CODEDTERM(ae_term.ae, 'LLT') as LLT,
       CODEDTERM(ae_term.ae, 'PT') as PT,
       CODEDTERM(ae_term.ae, 'HLT') as HLT,
       CODEDTERM(ae_term.ae, 'HLGT') as HLGT,
       CODEDTERM(ae_term.ae, 'SOC') as SOC
FROM adverse_event
Term Levels
MedDRA WHODrug
Primary Path Drug Name
LLT Preferred Name
PT ATC4
HLT ATC3
HLGT ATC2
SOC ATC1

CODEDCODE

If a coded code exists (the form’s Code Request is in the Coded or Autocoded status), returns the Coded Code for a data item. By default, CQL returns the Preferred Term Code for the MedDRA dictionary and the Preferred Code for the WHODrug dictionary. You can specify a code level to return another level.

Syntax
CODEDCODE(Item, 'CodeLevel')
Example
SELECT CODEDCODE(medication_therapy.conmed, 'DrugCD'),
       CODEDCODE(medication_therapy.conmed, 'PreferredCD'),
       CODEDCODE(medication_therapy.conmed, 'LLTCD'),
       CODEDCODE(medication_therapy.conmed, 'PTCD'),
       CODEDCODE(medication_therapy.conmed, 'HLTCD'),
       CODEDCODE(medication_therapy.conmed, 'HLGTCD'),
       CODEDCODE(medication_therapy.conmed, 'SOCCD')
FROM concomitant_medication
Code Levels
MedDRA WHODrug
DrugCD
LLTCD PreferredCD
PTCD ATC4CD
HLTCD ATC3CD
HLGTCD ATC2CD
SOCCD ATC1CD

CODEDDICTREL

Returns the coded dictionary release version assigned to the Form.

Syntax
CODEDDICTREL(Item)
Example
SELECT CODEDDICTREL(ae_term.ae)
FROM adverse_event
SELECT CODEDDICTREL(medication_therapy.conmed)
FROM concomitant_medication

CODEDSTATUS

Returns the Coding Status of the Item (Code Request).

Syntax
CODEDSTATUS(item)
Example
SELECT CODEDSTATUS(ae_term.ae)
FROM adverse_event

CODEDBY

Returns the Coded By (user ID of the user who coded the Code Request) for the Item.

Syntax
CODEDBY(item)
Example
SELECT CODEDBY(ae_term.ae)
FROM adverse_event

LASTCODED

Returns the Last Coded Date (date of the last time the Code Request moved into the Coded or Autocoded status) for the Item.

Syntax
LASTCODED(item)
Example
SELECT LASTCODED(ae_term.ae)
FROM adverse_event

Reference Objects

The following reference object functions are available:

KEYMATCH

Returns true if there is a match between the related_item and the related_key.

KEYMATCH leverages the related_item and related_key from the manifest file for the Items to match. If the related_item from the Form matches related_key from the reference data, then the value for the keymatch column is true. Otherwise, the value is false.

When you specify the Source for the Form in the first argument of your KEYMATCH function (SourceName.FormName), that SourceName.FormName specified in the first argument must exactly match the SourceName.FormName in the FROM clause.

Syntax
KEYMATCH(form_name, reference_object_name)

Flow Control

The following flow control functions are available:

IF

Evaluates a logical expression and returns a value if true or false. This function is useful when you’re comparing two values.

Syntax
IF(<Expression>, <Return_Value_True>,<Return_Value_False>)
Example
SELECT IF(Item1=Item2,1,0) as comp
FROM Form1

This query returns “1” if Item 1 is equal to Item 2. If Item 1 is not equal to Item 2, this query returns “0”.

CASE

Evaluates a logical expression and returns a value if true or false. This function is useful when you’re comparing multiple values.

Syntax
CASE WHEN(<Expression>) THEN '<Return_Value>' ELSE '<Return_Value>' END
Example
SELECT CASE WHEN(Item1=Item2) THEN 'a' WHEN Item1 > Item2 THEN 'b' ELSE 'c' END
FROM Form1

This query returns ‘a’ when Item 1 is equal to Item 2, ‘b’ when Item 1 is greater than Item 2, or ‘c’ if neither of those conditions are true.

IFNULL

Evaluates a DATAITEM and returns a value if the DATAITEM is NULL.

Syntax
IFNULL(DATAITEM,<Return_Value>)`
Example
SELECT IF(IFNULL(Item1,0)=Item2,1,0) as comp
FROM Form1

This query returns “1” if Item1 and Item2 are equal or if Item1 is NULL and Item2 is equal to 0. Otherwise, this query returns “0”.

String

The following string functions are available:

CONCAT

Returns the resulting string after concatenating the arguments.

Syntax
CONCAT(DATAITEM, 'string')
Example
SELECT CONCAT(@HDR.Subject.ID,'_',Creation_Criteria.Initials)
FROM Demographics

This query returns a concatenated string of the Subject ID, an underscore, and the Initials item value, for example, 101-1001_CRJ.

CONCAT_WS

Returns arguments together with a separator

Syntax
CONCAT_WS ( separator, DATAITEM1, DATAITEM2)
Example
select @HDR.Subject.Name, @HDR.Event.Name, AETERM, concat_ws ( ' ', 'AE ID ', @Form.SeqNbr, ' . ', @ItemGroup.SeqNbr )
from AE

GROUP_CONCAT

Return a concatenated string of non-NULL values from a group.

Syntax
GROUP_CONCAT ( DATAITEM)
Example
select @HDR.Subject.Name, @HDR.Event.Name, @Form.SeqNbr, group_concat(@ItemGroup.SeqNbr) 
from `EDC`.`AE`
where @Form.Status = 'submitted__v' or @HDR.Event.Status IN ('did_not_occur__v')
group by @HDR.Subject.Name, @Form.SeqNbr

COALESCE

Return the first non-NULL argument

Syntax
COALESCE (DATAITEM1, DATAITEM2, ...)
Example
select @HDR.Subject.Name, MHTERM, MHSTDAT, MHONGO, coalesce(MHTRT_1, MHTRT_2) 
from MHTERM

LENGTH

Returns the length of the value or DATAITEM passed in the argument.

Syntax
LENGTH(DATAITEM)
Example
SELECT LENGTH(Item1)
FROM Form1

This query returns the length of the Item 1 value from Form 1.

TRIM

Removes the leading and trailing spaces from a DATAITEM.

Syntax
TRIM(DATAITEM)
Example
SELECT TRIM(Baseline_X-ray.Interpretation)
FROM Baseline_Exam

This query returns the Interpretation item’s value from the Baseline Exam form with any leading or trailing spaces removed.

LTRIM

Removes leading spaces from a DATAITEM.

Syntax
LTRIM(DATAITEM)
Example
SELECT LTRIM(Baseline_X-ray.Interpretation)
FROM Baseline_Exam

This query returns the Interpretation item’s value from the Baseline Exam form with any leading spaces removed.

RTRIM

Removes trailing spaces from a DATAITEM.

Syntax
RTRIM(DATAITEM)
Example
SELECT RTRIM(Baseline_X-ray.Interpretation)
FROM Baseline_Exam

This query returns the Interpretation item’s value from the Baseline Exam form with any trailing spaces removed.

UPPER

Converts a DATAITEM to upper case.

Syntax
UPPER(DATAITEM)
Example
SELECT UPPER(Item1)
FROM Form1

This query returns the value of the Initials item as uppercase, e.g. from “cfa” to “CFA”.

LOWER

Converts a DATAITEM to lower case.

Syntax
LOWER(DATAITEM)
Example
SELECT LOWER(Item1)
FROM Form1

This query returns the value of Item 1 as lower case.

LEFT

Returns the leftmost len (number of) characters.

Syntax
LEFT(DATAITEM,len)
Example
SELECT LEFT(Creation_Criteria.Initials,1)
FROM Demographics

This query returns the rightmost character from the Initials item (the subject’s last initial).

Returns the rightmost len (number of) characters.

Syntax
RIGHT(DATAITEM,len)
Example
SELECT RIGHT(@HDR.Subject.ID,4)
FROM Demographics

This query returns the 4 rightmost characters from a Subject ID. In the Cholecap2019_Phase1 study, this is the four digit identifier for a subject, e.g. 1001, that is appended to the site number to make up the subject’s ID (e.g. 104-1001).

MID

Return a substring starting from the specified position

Syntax
MID ( DATAITEM, start index, length )
Example
select @HDR.Subject.Name, AETOXGR, MID(AETOXGR, 7, 1) as `Grade Number` 
from `EDC`.`AE`

REGEXP

Whether string matches regular expression

Syntax
REGEXP 'regular expression pattern'
Example
select @HDR.Subject.Name, SAE_TERM
from `EDC`.`AE`
where SAE_TERM regexp  ',|\\[|\\]|{|}|\\(|\\)'

REPLACE

Replace occurrences of a specified string

Syntax
REPLACE ( DATAITEM , 'substring' , 'new_string')
Example
select @HDR.Subject.Name, AETOXGR, replace(AETOXGR, 'GRADE', 'G')
from `EDC`.`AE`

SUBSTR

Return the substring as specified

Syntax
SUBSTR (DATAITEM, start index, length)
Example
select @HDR.Subject.Name, AETOXGR, SUBSTR(AETOXGR, 7, 1) as `Grade Number` 
from `EDC`.`AE`

Date & Time

CDB supports three different ways of looking at dates and datetimes captured through EDC: imputed, raw, and site normalized. Imputed dates are dates where logic is applied to impute any missing parts (unknowns) in a date or datetime. In EDC, studies can allow the collection of unknown day, month, or hour parts of dates and datetimes. In CDB, when a date contains an unknown, CDB applies first logic to those unknown parts. If the month is unknown, CDB imputes the first month of the year. If the day is unknown, CDB inputs the first hour of the day. By default, all dates and datetimes are returned as whole date and datetimes where the unknown parts are imputed. This is done to make date and datetime comparisons easy for review and cleaning.

CDB can also return the exact representation of the date and datetime as entered with the RawDate() function. This function always returns the value exactly as entered as a string, and it doesn’t substitute any of the unknown parts. Additionally, CDB can also return dates or datetimes as a site normalized value using the SiteNormalizedDate() function. This function returns dates and datetimes adjusted to match the timezone of the site for which they were captured.

The following functions are available for dates and times:

ADDDATE

Adds a date/time interval (resulting in a later date) from a given date or Date-type DATAITEM and returns the date/time

You can provide either a number of days or a number value and a unit with INTERVAL.

Syntax
ADDDATE ('date', days)

or

ADDDATE('date', INTERVAL value unit)

CQL supports the following interval units:

  • MICROSECOND
  • SECOND
  • MINUTE
  • HOUR
  • DAY
  • WEEK
  • MONTH
  • QUARTER
  • YEAR
  • SECOND_MICROSECOND
  • MINUTE_MICROSECOND
  • MINUTE_SECOND
  • HOUR_MICROSECOND
  • HOUR_SECOND
  • HOUR_MINUTE
  • DAY_MICROSECOND
  • DAY_SECOND
  • DAY_MINUTE
  • DAY_HOUR
  • YEAR_MONTH
Example
SELECT ADDDATE(Randomization.Date_of_Randomization, INTERVAL 5 DAY)
FROM Enrollment

This query returns the date 5 days after the Date of Randomization date value.

SUBDATE

Subtracts a date/time interval (resulting in an earlier date) from a given date or Date-type DATAITEM and returns the date/time.

You can provide either a number of days or a number value and a unit with INTERVAL.

Syntax
SUBDATE ('date', days)

or

SUBDATE('date', INTERVAL value unit)

CQL supports the following interval units:

  • MICROSECOND
  • SECOND
  • MINUTE
  • HOUR
  • DAY
  • WEEK
  • MONTH
  • QUARTER
  • YEAR
  • SECOND_MICROSECOND
  • MINUTE_MICROSECOND
  • MINUTE_SECOND
  • HOUR_MICROSECOND
  • HOUR_SECOND
  • HOUR_MINUTE
  • DAY_MICROSECOND
  • DAY_SECOND
  • DAY_MINUTE
  • DAY_HOUR
  • YEAR_MONTH
Example
SELECT SUBDATE(Randomization.Date_of_Randomization, INTERVAL 5 DAY)
FROM Enrollment

This query returns the date 5 days before the Date of Randomization date value.

TIMESTAMPDIFF

Subtract an interval from a datetime expression

Syntax

TIMESTAMPDIFF(month, date, date) 

Example

select @HDR.Subject.Name, AESTDT, AEENDDT, timestampdiff(day, AESTDT, AEENDDT)
from `EDC`.`AE`

DATEDIFF

Returns the difference between two dates in days.

Syntax
DATEDIFF('date', 'date')
Example
SELECT DATEDIFF(Randomization.Date_of_Randomization, '2019-12-31')
FROM Enrollment

This query returns the difference (in days) between the Date of Randomization item’s date value and 12-12-2019.

DATE_FORMAT

Returns a given date in the specified format. See a list of date specifiers below.

Syntax
DATE_FORMAT(<date>,'<format>')
Example
SELECT DATE_FORMAT(@HDR.Event.Date, '%Y-%m-%d')

This query returns the Event Date in the %Y-%m-%d format (e.g. 2019-12)

SITENORMALIZEDDATE

By default, CDB returns datetime value as entered in EDC. SiteNormalizedDate function returns the datetime normalized to UTC time.

Syntax
SiteNormalizedDate(date)
Example
select @HDR.Site.Name, @HDR.Site.Number, @HDR.Site.Timezone, @HDR.Site.Country, @HDR.Site.CountryName, @HDR.Subject.Name, AESTDT, SiteNormalizedDate(AESTDT) as 'Site Normalized Start Date' 
from `EDC`.`AE`
where @Form.Status = 'submitted__v'or @HDR.Event.Status in ('did_not_occur__v')

In this example, a subject has the same AE Start Date across 3 timezones. AESTDAT will return a datetime value as entered in EDC while the SiteNormalizedDate function will return a date time value normalized to UTC time.

RAWDATE

Returns a given date or datetime in the raw format. In raw format, partial dates and times display without any modifications.

If a Date is entered in Site’s local timezone then RawDate will return the Site’s local timezone.

See a list of raw-formatted partial dates below.

Syntax
RawDate(<date>)
Example
select @HDR.Site.Name, @HDR.Site.Number, @HDR.Site.Timezone, @HDR.Site.Country, @HDR.Site.CountryName, @HDR.Subject.Name, AESTDT, SiteNormalizedDate(AESTDT) as 'Site Normalized Start Date', RawDate(AESTDT) as 'Raw Start Date'
from `EDC`.`AE`
where @Form.Status = 'submitted__v'or @HDR.Event.Status in ('did_not_occur__v')

In this example, CQL returns AESTDT as ‘Raw Start Date’ in raw format.

This query returns the date value from the Subject DOB item in raw format.

SDTMDATEFORMAT

Returns a given date or datetime in the SDTM (ISO 8061) format, automatically handling unknown parts of the date if they exist. The value is returned as a string. See a list of SDTM-formatted partial dates below.

Syntax
SDTMDateFormat(<date>)
Example
SELECT SDTMDateFormat(mh.condition_start_date) from EDC.medical_history

This query returns the date value from the Condition Start Date item in SDTM format, handling any unknowns.

STR_TO_DATE

Given a string and the string’s date format, returns a date. See a list of date specifiers below.

Syntax
SELECT STR_TO_DATE('<string>', '<format>')
Example
SELECT STR_TO_DATE('January 01, 2021', '%M %d, %Y')

This query returns Jan 1, 2021 as a date.

CURDATE

Returns the current date as YYYY-MM-DD.

Example
SELECT CURDATE()
FROM Demographics

This query returns the current date.

NOW

Returns the current date and time as a value in ‘YYYY-MM-DD hh:mm:ss’.

Example
SELECT NOW()
FROM Demographics

This query returns the current date and time.

YEAR

Returns the year from a given date.

Syntax
YEAR('date')
Example
SELECT YEAR('2019-12-12')
FROM Demographics

This function returns “2019”, the year from 2019-12-12.

MONTH

Returns the month from a given date.

Syntax
MONTH('date')
Example
SELECT MONTH('2019-12-12')
FROM Demographics

This function returns “12”, the month from 2019-12-12.

WEEK

Returns week of the year from a given date.

Syntax
WEEK('date')
Example
SELECT WEEK('2019-12-12')
FROM Demographics

This function returns “50”, the week of the year for 2019-12-12.

DAY

Returns the day from a given date.

Syntax
DAY('date')
Example
SELECT DAY('2019-12-12')
FROM Demographics

This function returns “12”, the day from 2019-12-12.

HOUR

Returns the hour, given a time.

Syntax
HOUR('time')
Example
SELECT HOUR('10:05:03')
FROM Demographics

This function returns “10”, the hour from 10:05:03.

MINUTE

Returns the minute, given a time.

Syntax
MINUTE('time')
Example
SELECT MINUTE('10:05:03')
FROM Demographics

This function returns “05”, the minute from 10:05:03.

SECOND

Returns the second, given a time.

Syntax
SECOND('time')
Example
SELECT SECOND('10:05:03')
FROM Demographics

This function returns “03”, the second from 10:05:03.

LAST_DAY

Returns the last day of the month, given a date.

Syntax
LAST_DAY('date'), LAST_DAY(DATAITEM)
Example
SELECT LAST_DAY(@HDR.Event.Date)

This query returns the last day of the month from the Event Date’s month. For example, if the Event Date was 2019-11-15, this query would return “30”, or the last day of November.

Unknown Dates

Workbench supports referencing unknown dates and datetimes, either from Vault EDC or 3rd party data, in CQL queries. Workbench allows the following unknown date and time options:

  • Month, Day, and Time
  • Day and Time
  • Time

By default, Workbench converts the unknown date part to the first day of the month or the first month of the year and the unknown time to 00:00:00. This allows you to treat dates universally without concern over unknown dates and times.

Unknown

Returns the parts of the date that are unknown if the date contains unknown parts (M, D, and T), otherwise returns the string COMPLETE.

Syntax
Unknown(Date)
Example
Unknown(edc.mh_condition_start_date)

In this example, the Condition Start Date item on the Medical History form allows for unknown month, day, and time. If an EDC user entered “07-17-2021 5:15”, the function would return COMPLETE, as the entered date contains no unknowns. If an EDC user entered “06-?-2005 ?”, the function would return D,T because the date has an unknown day and time.

UnknownImpute

This function allows a user to specify how they want to represent unknown parts. The function, given an Item, determines if a date contains unknown parts using the raw date value, and then it applies the provided logic for how to handle the unknown parts. The result is a value with the date data type. If the value doesn’t contain any unknown parts, the function returns the default date.

Syntax
UnknownImpute(Item, 'day impute type', 'month impute type', 'time impute type')
Impute Types:

You must enter each impute type, even if a date or datetime doesn’t allow for those unknowns. Note that the input type must be surrounded with single quotes (‘).

  • Day:
    • FIRST DAY: First day of the month.
    • LAST DAY: Last day of the month.
    • MID DAY: 15th of the month.
  • Month:
    • FIRST MONTH: January (1)
    • LAST MONTH: December (12)
      • MID MONTH: June (6)
  • Time:
    • FIRST HOUR: 00:00 24hr
    • LAST HOUR: 23:59 24hr
    • MID HOUR: 12:00 24hr
Example
UnknownImpute(edc.ae_start_datetime, 'FIRST DAY', 'FIRST MONTH', 'FIRST HOUR')

In this example, the AE Start DateTime item allows unknowns for time. This query returns the AE Start DateTime with the unknown time set to 12:00 AM. For example, if the entered datetime in EDC was “Jul 22, 2021 ?”, CQL would return “Jul 22, 2021 12:00 AM”.

Date & Time Specifiers

The following date and time specifiers are available in CQL:

Specifier Definition
%r Time, 12-hour clock (hh:mm:ss, followed by AM or PM)
%T Time, 24-hour clock (hh:mm:ss)
%I Hour, 12-hour clock, with leading zeroes (01..12)
%l Hour, 12-hour clock, without leading zeroes (1..12)
%k Hour, 24-hour clock, with leading zeroes (01..24)
%i Minutes, numeric (00..59)
%S Seconds (00..59)
%s Seconds (00..59), same as %S
%f Microseconds (000000..999999)
%p AM or PM
%d Day of the month, numeric (00..31)
%e Day of the month, numeric, without leading zeroes (0..31)
%D Day of the month with English suffix (0th, 1st, 2nd, 3rd...)
%j Day of the year (001..366)
%w Day of the week (0 is Sunday..6 is Saturday)
%W Weekday name (Sunday..Saturday)
%a Weekday name, abbreviated (Sun..Sat)
%M Month name (January..December)
%b Month name, abbreviated (Jan..Dec)
%m Month, numeric (00..12)
%Y Year, numeric, 4 digits
%y Year, numeric, 2 digits
%U Week (00..53), where Sunday is the first day of the week, WEEK() mode 0
%u Week (00..53), where Monday is the first day of the week, WEEK() mode 1
%V Week (00..53), where Sunday is the first day of the week, WEEK() mode 2; used with %X
%v Week (01..53), where Monday is the first day of the week, WEEK() mode 3; used with %x
%X Year for the week, numeric, where Sunday is the first day of the week; used with %V
%x Year for the week, numeric, where Monday is the first day of the week; used with %v
%% A literal % character
% x x, for any "x" not listed above

Raw Format Dates

Date or DateTime as Recorded Raw Format
1 27-Oct-2020 27-Oct-2020
2 ?-Oct-2020 UN-Oct-2020
3 ?-?-2020 UN-UNK-2020
4 27-Oct-2020 10:40 27-Oct-2020 10:40
5 27-Oct-2020 ? 27-Oct-2020 UN:UN
6 ?-Oct-2020 ? UN-Oct-2020 UN:UN
7 ?-?-2020 ? UN-UNK-2020 UN:UN

SDTM Format Dates

Date or DateTime as Recorded Interval of Uncertainty Nominal Date/Time (--DTC)
1 March 15, 2020 13:14:17 Complete date 2020-03-14T13:14:17
2 March 15, 2020 13:14 Unknown seconds 2020-03-15T13:14
3 March 15, 2020 13 Unknown minutes 2020-03-15T13
4 March 15, 2020 Unknown time 2020-03-15
5 March, 2020 Unknown day 2020-03
6 2020 Unknown month 2020

Other

The following functions are also available for use in CQL queries:

CAST

Cast takes a data item or expression argument and returns the result in the specified data type.

Syntax
CAST(item AS data_type) 
CAST (expression AS data_type

The following data types are available for use within CAST functions:

  • Binary
  • CHAR
  • DATE
  • DATETIME
  • TIME
  • DECIMAL
  • SIGNED
  • UNSIGNED
Example
SELECT CAST(Exclusion_Criteria.Hypersensitivity_Constituents as CHAR)
FROM Demographics

This query returns the codelist item value (Y or N) from the Hypersensitivity Constituents codelist-type Item as text (char).

FIELD

Returns the index, or position, of an item value within a list of strings. This is useful for customizing the order of a list of possible values within a result set.

Syntax
FIELD(DATAITEM, '<string1>', '<string2>','<stringN>')
Example
SELECT @HDR.Subject, Route, Dosage_Amount
FROM Dosing
ORDER BY FIELD(Route, 'Oral', 'Nasal', 'Topical')

This query returns the subject-level header information and the Route and Dosage Amount item values, ordered by the Route from Oral to Nasal to Topical.

UNION

Union combines the results of multiple SELECT statements into a single set of results. CQL uses the column names listed in the first SELECT statement as the column names. For a column in the first SELECT statement, the corresponding column in the subsequent SELECT statements must be of the same data type. For example, if the second column of the first statement is an integer, the second column of the second SELECT statement must also be an integer.

UNION returns all possible result rows from queries in the union, as does UNION ALL. You can use UNION DISTINCT to retrieve only unique result rows from queries in the union. UNION DISTINCT only removes duplicate rows where the duplication is a 100% match.

Union Limit: CQL limits UNION operations to 4000.

Syntax
SELECT ItemGroup.Item, ItemGroup.Item FROM Form1
UNION
SELECT ItemGroup.Item, ItemGroup.Item FROM Form2
Example
SELECT test.date_collected, test.rbc, test.wbc FROM LocalLabs.Hematology
UNION
SELECT chem.date_collected, chem.total_protein, chem.urea_nitrogen FROM CentralLabs.Chemistry

UNPIVOT

UnPivot is a relational operator that you can use to convert a table’s columns into column values. You can’t include any @HDR values in an UnPivot or reference any unpivoted Items in a WHERE, GROUP BY, or ORDER BY clause.

In the current release, CDB won’t display cell highlighting for listings where the CQL statement uses UnPivot.

Syntax
SELECT up.@HDR.Subject.Name, up_items
FROM (
    SELECT @HDR.Subject.Name, itemA, itemB, itemC, itemD) up
UNPIVOT (
    up_items
    FOR items in (itemA, itemB, itemC, itemD)
) as unpivot_table
Example: Unpivot
SELECT up.@HDR.Subject.Name up_items
FROM (
	SELECT @HDR.Subject.Name, body_temperature, height, weight, systolic_blood_pressure__mmhg_, diastolic_blood_pressure__mmhg_, pulse__bpm_ FROM Vitals) up
UNPIVOT (
up_items 
FOR items in (body_temperature, height, weight, systolic_blood_pressure__mmhg_, diastolic_blood_pressure__mmhg_, pulse__bpm_)
) as unpivot_table
Example: Multiple Unpivot Sections
SELECT @HDR.Subject.Name, @HDR.Event, Body_Temperature, vsResult, vsTest, VSSTAT, HIDe 
FROM ( SELECT @HDR.Subject.Name, Body_Temperature, Height, Weight, ILB(Body_Temperature), ILB(Height), ILB(Weight) From EDC.Vitals) main
UNPIVOT (vsResult FOR vsTest in (Body_Temperature, Height, Weight)) as result
UNPIVOT (VSSTAT FOR HIDe in (ILB(Body_Temperature), ILB(Height), ILB(Weight))) as ilb

Example: UnPivot on Multiple Forms:
SELECT @HDR.Subject.Name, d.MHTERM, b.Please_specify_abnormality AS term, up_item.vs_result, up_item.vs_test
FROM (SELECT body_temperature, height, weight, systolic_blood_pressure__mmHg_, diastolic_blood_pressure__mmHg_, pulse__bpm_ FROM vitals) AS main
UNPIVOT (vs_result FOR vs_test IN (body_temperature, systolic_blood_pressure__mmHg_, diastolic_blood_pressure__mmHg_, pulse__bpm_)) AS up_item,
baseline_chest_x-ray_evaluation b, demographics d
WHERE main.@HDR.Subject.ID = b.@HDR.Subject.ID 
AND main.@HDR.Subject.ID = d.@HDR.Subject.ID
Unsupported Use Cases:

The following use cases are not supported in the current release:

  • UnPivot within a subquery
  • UnPivot within Union
  • Referencing @Form or @ItemGroup properties within UnPivot
UnPivot within a Subquery:
SELECT @HDR.Subject.Name, creation_criteria.subject_initials, creation_criteria.subject_dob, up.*
FROM demographics.creation_criteria
(SELECT @HDR.Subject.Name, up_item.vs_test, up_item.vs_result
FROM (SELECT body_temperature, height, weight, systolic_blood_pressure__mmhg_, diastolic_blood_pressure__mmhg_, pulse__bpm_ FROM Vitals) as main
UNPIVOT (vs_result FOR vs_test IN (body_temperature, height, weight, systolic_blood_pressure__mmhg_, diastolic_blood_pressure__mmhg_, pulse__bpm_)) AS up_item) AS up
WHERE d.@HDR.Subject.Name = up.@HDR.Subject.Name
UnPivot within Union:
SELECT @HDR.Subject.Name, @HDR.Event.Name, up_item.*
FROM (SELECT body_temperature, height, weight, systolic_blood_pressure__mmHg_, diastolic_blood_pressure__mmHg_, pulse__bpm_ FROM vitals) AS main
UNPIVOT (vs_result FOR vs_test IN (vody_temperature, systolic_blood_pressure__mmHg_, diastolic_blood_pressure__mmHg_, pulse__bpm_)) AS up_item
UNION ALL
SELECT @HDR.Subject.Name, @HDR.Event.Name, up_item.*
FROM (SELECT WBC, RBC, HEMOGLOBIN, HEMATOCRIT, PLATELET, NEUTROPHILS FROM hematology) AS main
UNPIVOT (vs_result FOR vs_test IN (WBC, RBC, HEMOGLOBIN, HEMATOCRIT, PLATELET, NEUTROPHILS)) AS up_item;

Other Available Functions

The following SQL functions are also available for use within CQL:

Function Description
ABS() Return the absolute value
ACOS() Return the arc cosine
ADDTIME() Add time
ASCII() Return numeric value of left-most character
ASIN() Return the arc sine
ATAN() Return the arc tangent
ATAN2(), ATAN() Return the arc tangent of the two arguments
BIN() Return a string containing binary representation of a number
BINARY Cast a string to a binary string
BIT_AND() Return bitwise AND
BIT_COUNT() Return the number of bits that are set
BIT_LENGTH() Return length of argument in bits
BIT_OR() Return bitwise OR
BIT_XOR() Return bitwise XOR
CEIL() Return the smallest integer value not less than the argument
CEILING() Return the smallest integer value not less than the argument
CHAR() Return the character for each integer passed
CHAR_LENGTH() Return number of characters in argument
CHARACTER_LENGTH() Synonym for CHAR_LENGTH()
CHARSET() Return the character set of the argument
COERCIBILITY() Return the collation coercibility value of the string argument
COLLATION() Return the collation of the string argument
CONV() Convert numbers between different number bases
CONVERT_TZ() Convert from one time zone to another
COS() Return the cosine
COT() Return the cotangent
COUNT(DISTINCT) Return the count of a number of different values
CURRENT_DATE(), CURRENT_DATE Synonyms for CURDATE()
CURRENT_TIME(), CURRENT_TIME Synonyms for CURTIME()
CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP Synonyms for NOW()
CURTIME() Return the current time
DATE_ADD() Add a value (interval) to a date
DATE_FORMAT() Format date as specified
DATE_SUB() Subtract a value (interval) from a date
DAY() Synonym for DAYOFMONTH()
DAYNAME() Return the name of the weekday
DAYOFMONTH() Return the day of the month (0-31)
DAYOFWEEK() Return the weekday index of the argument
DAYOFYEAR() Return the day of the year (1-366)
DEGREES() Convert radians to degrees
ELT() Return string at index number
EXP() Raise to the power of
EXPORT_SET() Return a string such that for every bit set in the value bits, you get an on string and for every unset bit, you get an off string
EXTRACT() Extract part of a date
FIND_IN_SET() Index (position) of first argument within second argument
FLOOR() Return the largest integer value not greater than the argument
FORMAT() Return a number formatted to specified number of decimal places
FOUND_ROWS() For a SELECT with a LIMIT clause, the number of rows that would be returned were there no LIMIT clause
FROM_BASE64() Decode base64 encoded string and return result
FROM_DAYS() Convert a day number to a date
FROM_UNIXTIME() Format Unix timestamp as a date
GET_FORMAT() Return a date format string
GREATEST() Return the largest argument
HEX() Hexadecimal representation of decimal or string value
INSERT() Insert substring at specified position up to specified number of characters
INSTR() Return the index of the first occurrence of substring
INTERVAL() Return the index of the argument that is less than the first argument
ISNULL() Test whether the argument is NULL
LCASE() Synonym for LOWER()
LEAST() Return the smallest argument
LN() Return the natural logarithm of the argument
LOCALTIME(), LOCALTIME Synonym for NOW()
LOCALTIMESTAMP, LOCALTIMESTAMP() Synonym for NOW()
LOCATE() Return the position of the first occurrence of substring
LOG() Return the natural logarithm of the first argument
LOG10() Return the base-10 logarithm of the argument
LOG2() Return the base-2 logarithm of the argument
LPAD() Return the string argument, left-padded with the specified string
MAKE_SET() Return a set of comma-separated strings that have the corresponding bit in bits set
MAKEDATE() Create a date from the year and day of year
MAKETIME() Create time from hour, minute, second
MICROSECOND() Return the microseconds from argument
MOD() Return the remainder
MONTHNAME() Return the name of the month
NAME_CONST() Cause the column to have the given name
NULLIF() Return NULL if expr1 = expr2
OCT() Return a string containing octal representation of a number
OCTET_LENGTH() Synonym for LENGTH()
ORD() Return character code for leftmost character of the argument
PERIOD_ADD() Add a period to a year-month
PERIOD_DIFF() Return the number of months between periods
PI() Return the value of pi
POSITION() Synonym for LOCATE()
POW() Return the argument raised to the specified power
POWER() Return the argument raised to the specified power
QUARTER() Return the quarter from a date argument
QUOTE() Escape the argument for use in an SQL statement
RADIANS() Return argument converted to radians
RAND() Return a random floating-point value
RANDOM_BYTES() Return a random byte vector
REPEAT() Repeat a string the specified number of times
REVERSE() Reverse the characters in a string
ROUND() Round the argument
ROW_COUNT() The number of rows updated
RPAD() Append string the specified number of times
SEC_TO_TIME() Converts seconds to 'hh:mm:ss' format
SIGN() Return the sign of the argument
SIN() Return the sine of the argument
SPACE() Return a string of the specified number of spaces
SQRT() Return the square root of the argument
STD() Return the population standard deviation
STDDEV() Return the population standard deviation
STDDEV_POP() Return the population standard deviation
STDDEV_SAMP() Return the sample standard deviation
STRCMP() Compare two strings
SUBSTRING() Return the substring as specified
SUBSTRING_INDEX() Return a substring from a string before the specified number of occurrences of the delimiter
SUBTIME() Subtract times
SYSDATE() Return the time at which the function executes
TAN() Return the tangent of the argument
TIME() Extract the time portion of the expression passed
TIME_FORMAT() Format as time
TIME_TO_SEC() Return the argument converted to seconds
TIMEDIFF() Subtract time
TIMESTAMP() With a single argument, this function returns the date or datetime expression; with two arguments, the sum of the arguments
TIMESTAMPADD() Add an interval to a datetime expression
TO_BASE64() Return the argument converted to a base-64 string
TO_DAYS() Return the date argument converted to days
TO_SECONDS() Return the date or datetime argument converted to seconds since Year 0
TRUNCATE() Truncate to specified number of decimal places
UCASE() Synonym for UPPER()
UNHEX() Return a string containing hex representation of a number
UNIX_TIMESTAMP() Return a Unix timestamp
UTC_DATE() Return the current UTC date
UTC_TIME() Return the current UTC time
UTC_TIMESTAMP() Return the current UTC date and time
UUID() Return a Universal Unique Identifier (UUID)
UUID_SHORT() Return an integer-valued universal identifier
VALUES() Define the values to be used during an INSERT
VAR_POP() Return the population standard variance
VAR_SAMP() Return the sample variance
VARIANCE() Return the population standard variance
WEEK() Return the week number
WEEKDAY() Return the weekday index
WEEKOFYEAR() Return the calendar week of the date (1-53)
WEIGHT_STRING() Return the weight string for a string
YEARWEEK() Return the year and week

CQL Errors

In the unlikely event you receive generic CQL run-time errors (error codes 0001 through 0010), contact Veeva Support.