A Workday Query Language (WQL) query names a data source in FROM, the fields you want in SELECT, and optionally filters, groups, sorts and limits the rows. It has no SELECT *, and every name in it is a WQL alias taken from Workday's data-source metadata, not the label you see on a report.

This is the quick reference. For how to approach a query and check the result, see the WQL guide; for what an error means, see WQL error messages.

WQL clause order

Write the clauses in this order. Only SELECT and FROM are required.

PARAMETERS ...
SELECT ...
FROM ...
WHERE ON ...
WHERE ...
GROUP BY ...
HAVING ...
ORDER BY ...
LIMIT ...

Two ordering rules come straight from Workday's reference: every WHERE ON comes before the main WHERE, and HAVING works only together with GROUP BY.

What goes in each clause

Clause What it does Notes
SELECT Returns fields by alias field AS name renames a column. Aggregates: AVG, COUNT(), COUNT(DISTINCT field), MAX, MIN, SUM. COUNT() takes no argument. A WQL keyword cannot be an alias.
FROM Data source, optional filter and as-of dates FROM src(dataSourceFilter=alias, prompt=value)
WHERE Row conditions joined by AND and OR Parentheses are evaluated first.
WHERE ON Conditions on fields of a related object Written without braces. One clause per related object.
GROUP BY Summary rows Cannot group by an aggregate, a currency field or a multi-instance field.
HAVING Filters the groups Can use the aggregate functions.
ORDER BY ASC or DESC Sorts alphabetically, not logically. With no ORDER BY, order follows an internal record ID.
LIMIT Maximum rows Must be above zero and below 1 million. Does not make the query faster, because Workday builds the full result first.
PARAMETERS Built-in prompt values at the top A parameter can appear once.

WHERE operators

Operator Works on
= != Boolean, date, numeric, text
> >= < <= Date, numeric
contains not contains startswith endswith Text, not case sensitive
in not in Instance, text
is empty is not empty Boolean, date, instance, numeric, text

Instance fields such as location or supervisoryOrganization are compared by Workday ID, or by reference ID with in (Location_ID = value). Workday validates the ID's format and fails the query if it is malformed.

Dates and as-of values

Dates are YYYY-MM-DD and datetimes are YYYY-MM-DD HH:MM:SS in Pacific time, or with a trailing Z for UTC. Quote them.

To read data as it stood on a date, pass effectiveAsOfDate, effectiveAsOfMoment, entryDate or entryMoment inside the FROM parentheses. Workday documents these for standard, Workday-delivered data sources only, and a data source that does not support effective or entry values returns an error when you pass them. With none given, the query runs as of now.

Curly braces select fields of a related business object: dependents{legalName_LastName, age}. Filter on them with WHERE ON, without the braces. Two documented limits matter: you cannot use these fields in a query that has GROUP BY, and a multi-instance relationship returns at most 500 values per object, after which the query errors.

WQL examples on documented data sources

The data sources and fields below were checked against Workday's data-source metadata. Fields and calculated fields differ by tenant and by security, so confirm each alias in yours with GET /dataSources before relying on it (see the last section).

1. The simplest useful query

SELECT fullName, employeeID, businessTitle
FROM allWorkers
ORDER BY fullName ASC
LIMIT 25

2. Workers who have not been terminated

SELECT worker, hireDate
FROM allWorkers
WHERE terminationDate is empty

3. Text match with two conditions

SELECT fullName, businessTitle
FROM allWorkers
WHERE businessTitle contains 'analyst' AND terminationDate is empty

4. Filter an instance field by reference ID (replace the value with a real Location reference ID from your tenant)

SELECT worker, location
FROM allWorkers
WHERE location in (Location_ID = <location reference ID>)

5. Data as of a past date

SELECT worker, businessTitle
FROM allWorkers (effectiveAsOfDate="2025-01-01")
WHERE terminationDate is empty

6. Headcount by location

SELECT location, count() AS Headcount
FROM allWorkers
WHERE terminationDate is empty
GROUP BY location

7. Only groups above a threshold

SELECT workerType, count() AS Total
FROM allWorkers
GROUP BY workerType
HAVING count() >= 10

8. Several aggregates in one pass

SELECT location, AVG(yearsOfService), MAX(age)
FROM allWorkers
GROUP BY location

9. Related object fields with a related filter

SELECT worker, dependents{legalName_FirstName, age}
FROM allWorkers
WHERE ON dependents age >= 18

10. Large supervisory organizations

SELECT name, code, employeeCount
FROM supervisoryOrganizations
WHERE employeeCount > 50
ORDER BY employeeCount DESC
LIMIT 20

11. Active locations by country

SELECT locationName, primaryAddress_CountryName
FROM locations
WHERE inactive = false
ORDER BY locationName

12. Open positions that are not frozen

SELECT positionID, positionTitle, supervisoryOrganization
FROM allPositions
WHERE positionCount_Available > 0 AND hiringFreeze = false

13. Requisitions with openings, newest first

SELECT jobPostingTitle, recruitingStartDate, numberOfOpeningsAvailable
FROM allJobRequisitions
WHERE numberOfOpeningsAvailable > 0
ORDER BY recruitingStartDate DESC
LIMIT 50

14. Recent integration runs that had errors. This data source has no effective or entry date support, so do not pass any.

SELECT integrationSystem, actualStartDateAndTime, numberOfErrors, itemsProcessed
FROM integrationEvents
WHERE numberOfErrors > 0
ORDER BY actualStartDateAndTime DESC
LIMIT 20

15. Overdue business process steps by process

SELECT businessProcess, count()
FROM allBusinessProcessTransactionsAwaitingPersons
WHERE daysPastDue > 0
GROUP BY businessProcess

Data source filters and PARAMETERS

Some data sources take built-in prompts, either directly or through a data source filter. Name the filter in FROM, or put the prompts in a PARAMETERS clause first. Prompts for a data source or its filter go in PARAMETERS or in FROM, never both. Report fields take their values in PARAMETERS only, and the filter alias itself always goes in FROM. The alias and prompt names below are placeholders; get the real ones from the data source's filter list.

PARAMETERS <prompt alias> = <Workday ID>
SELECT <field alias>
FROM <data source alias> (dataSourceFilter = <filter alias>)

Get the aliases from Workday

Do not guess aliases. Two REST calls give the right ones, using the base URL https://{hostname}/api/wql/{version}/{tenant}:

  1. GET {baseURL}/dataSources?alias=<name> finds the data source and its ID.
  2. GET {baseURL}/dataSources/{ID}/fields lists its fields, and /dataSourceFilters lists the filters and their prompts.

GET {baseURL}/data?query=... runs a query under 2,048 characters. Use POST /data with the query in the body for queries from 2,048 up to 16,000 characters.

Row limits at a glance

A query returns at most 1 million rows. Results come back at most 10,000 rows at a time, and you page with the REST limit and offset parameters, which are separate from the LIMIT clause. In Workday, the View WQL Query Result report shows only the first 500 rows. How to get past that, including windowing and paging, is in WQL and more than 500 rows.

Sources checked