Study guide

9.1 JQL Fundamentals, Clauses, Operators & History (WAS / CHANGED)

Atlassian Certified Professional - Jira Administration for Cloud ACP-120

Track your progress as you read

Finished sections get a check mark.

1 Chapter 1: Exam Overview, Blueprint & Jira Cloud Fundamentals

1.1 ACP-120 Exam Structure, Blueprint & Testing Strategy 1.2 Jira Cloud Architecture, Products & Admin Hierarchy

2 Chapter 2: Organizations, Managed Accounts & Global Access

2.1 Atlassian Organizations, Domain Verification & Managed Accounts 2.2 Atlassian Guard, SAML SSO, SCIM & Authentication Policies 2.3 Site Access, Product Access Tiers & Global Permissions 2.4 User Directory Architecture: Groups vs. Project Roles

3 Chapter 3: Project Permissions & Issue-Level Security Schemes

3.1 Permission Scheme Mechanics & Critical Project Permissions 3.2 Permission Troubleshooting, Additive Permissions & Permission Helper 3.3 Issue Security Schemes, Security Levels & Access Containment

4 Chapter 4: Project Configuration, Types, Versions & Boards

4.1 Company-Managed vs. Team-Managed Project Architecture 4.2 Project Templates, Project Keys & Project Categories 4.3 Project Components, Component Leads & Default Assignees 4.4 Versions, Fix Versions, Release Lifecycles & Project Archiving 4.5 Scrum and Kanban Board Configuration, Board Filters & Columns

5 Chapter 5: Issue Types, Custom Fields, Screens & Schemes

5.1 Standard vs. Sub-task Issue Types & Issue Type Schemes 5.2 Custom Field Types, Global vs. Project Contexts & Options 5.3 Field Configurations, Renderers, Hiding & Required Fields 5.4 Screens, Screen Schemes & Issue Type Screen Schemes

6 Chapter 6: Workflows — Company-Managed and Team-Managed

6.1 Statuses, Status Categories, Direct & All-to-One Global Transitions 6.2 Transition Rules: Conditions vs. Validators 6.3 Post Functions, Execution Order & Resolution Management 6.4 Workflow Schemes, Editing Active Workflows & Status Migration 6.5 Team-Managed Workflows, Statuses & Workflow Rules

7 Chapter 7: Jira Cloud Automation

7.1 Automation Engine, Rule Architecture & Event Triggers 7.2 Automation Conditions, Smart Values & String/Date Expressions 7.3 Branch Rules, Related Issues, Sub-tasks & Parent Epics 7.4 Rule Scopes, Automation Usage, Audit Logs & Error Handling

8 Chapter 8: Notifications, Events, Personal Settings & Mail Handlers

8.1 Jira Events, System Events & Notification Schemes 8.2 Notification Recipients, Custom User Fields & Deduplication 8.3 Team-Managed Notifications, Personal Settings & Troubleshooting Missing Email 8.4 Mail Handlers: Creating Issues and Comments from Email

9 Chapter 9: JQL, Filters, Dashboards & Bulk Operations

9.1 JQL Fundamentals, Clauses, Operators & History (WAS / CHANGED) 9.2 Advanced JQL Functions & Dynamic Date Searches 9.3 Filter Permissions, Shared Filters & Filter Subscriptions 9.4 Dashboard Layouts, the Default Dashboard, Sharing & Essential Gadgets 9.5 Bulk Operations: Edit, Move, Transition, Delete & Watch

10 Chapter 10: System Administration

10.1 Global UI Features: User Defaults, Look and Feel, Announcement Banner & Default Dashboard 10.2 Statuses, Resolutions, Priorities & Sub-tasks: Global Configuration 10.3 Global Settings: Time Tracking, Issue Linking, Attachments & Application Links 10.4 System Backup, Restore & Data Import

9.1 JQL Fundamentals, Clauses, Operators & History (WAS / CHANGED)

Key Takeaways Explain This Topic AI

JQL clauses combine fields, operators, values, and keywords (AND, OR, NOT, EMPTY, NULL, ORDER BY), and AND binds tighter than OR, so use parentheses.

Negative operators such as != and NOT IN don't return issues where the field is empty; add OR field IS EMPTY when you need them.

WAS, WAS IN, WAS NOT, WAS NOT IN, and CHANGED work only on Assignee, Fix Version, Priority, Reporter, Resolution, and Status.

CHANGED supports seven predicates (FROM, TO, BY, BEFORE, AFTER, ON, DURING); WAS tests a past state, and CHANGED tests a change event.

Basic search can't do OR across different fields, parentheses, history operators, or most functions, so complex needs require JQL.

Last updated: September 2026

9.1 JQL Fundamentals, Clauses, Operators & History ( WAS / CHANGED )

Quick Summary: Jira Query Language (JQL) is the core search engine powering issue discovery, agile boards, dashboard gadgets, automation triggers, and SLA tracking across Jira Cloud. A JQL query consists of fields , operators , values , and connecting keywords . Beyond querying the current state of an issue, JQL provides powerful historical auditing capabilities through the WAS and CHANGED operators. Understanding how historical searching interfaces with Jira's changelog, which fields support historical analysis, and how to chain historical predicates ( FROM , TO , BY , DURING , BEFORE , AFTER , ON ) is essential for both daily administration and passing the ACP-120 exam.

Anatomy of a JQL Query

JQL is a structured, SQL-like query language designed specifically for searching issues within Jira. When navigating to Filters > Advanced issue search (or selecting Switch to JQL from the basic search bar), administrators write queries composed of one or more clauses : +--------------------------------------------------------------------------+

  • | ANATOMY OF A JQL CLAUSE |
  • +--------------------------------------------------------------------------+
  • | [ FIELD ] [ OPERATOR ] [ VALUE ] [ KEYWORD ] |
  • | project = "ALPHA" AND |
  • | status IN ("In Dev", "Testing") AND |
  • | assignee = currentUser() ORDER BY |
  • | created DESC |
  • +--------------------------------------------------------------------------+
  • 1. Fields

A field represents a specific issue attribute in Jira. Fields fall into two primary categories:

System Fields: Native attributes built into Jira Cloud, such as project , issuetype , status , resolution , priority , assignee , reporter , created , updated , and duedate .

Custom Fields: Custom attributes created by Jira Administrators. In JQL, custom fields can be referenced by their human-readable name (e.g., "Account ID" = "ACC-9921" ). If multiple custom fields share identical names, or if a custom field name contains reserved words or special characters, administrators must reference the field by its immutable custom field ID using the format cf[XXXXX] (e.g., cf[10042] = "ACC-9921" ).

2. Operators

An operator defines the logical relationship between the field and the value. JQL operators include:

  • Comparison Operators: = , != , > , >= , < , <=
  • Set Operators: IN , NOT IN
  • Null Validation Operators: IS EMPTY , IS NOT EMPTY , IS NULL , IS NOT NULL
  • Text Matching Operators: ~ (CONTAINS), !~ (DOES NOT CONTAIN)
  • Historical Operators: WAS , WAS IN , WAS NOT IN , CHANGED
  • 3. Values and Functions

A value represents the actual data evaluated against the field. Values can be string literals enclosed in double quotes ( "High" ), numbers ( 42 ), ISO-formatted dates ( "2026-06-15" ), or dynamic function calls that resolve at query runtime (such as currentUser() or startOfWeek() ).

4. Keywords and Logical Precedence

Keywords join multiple clauses or control the final result presentation:

  • Boolean Connectors: AND , OR , NOT
  • Sorting: ORDER BY <field> [ASC | DESC]

Parentheses () for Grouping: JQL evaluates AND operators before OR operators by default. To prevent logical ambiguity, administrators must use parentheses to explicitly group logical conditions.

Consider the following query: project = PROJ AND status = Open OR assignee = currentUser()

Because AND binds more tightly than OR , Jira interprets this query as: (Issues in project PROJ that are Open) OR (Issues assigned to the current user in ANY project across the entire instance) .

To correctly restrict both conditions to project PROJ, parentheses are mandatory: project = PROJ AND (status = Open OR assignee = currentUser())

Comparison, Set, and Text Search Operators

Understanding the precise mechanics and limitations of standard JQL operators prevents common data reporting errors.

Operator Supported Field Types Description & Operational Behavior Example JQL Clause

= Fields with defined values (priority, status, users, versions, select lists) Exact match on the value. Free-text fields such as Summary and Description use ~ instead. priority = Critical

!= All single-value fields Inequality matching. Note: != excludes issues where the field is empty! status != Closed

> , >= , < , <= Date, numeric, duration fields Quantitative comparison against dates, numbers, and time estimates. created >= "2026-01-01"

IN Fields supporting multiple options Evaluates whether the field matches any value in a comma-separated list (logical OR). issuetype IN (Bug, Incident)

NOT IN Fields supporting multiple options Evaluates whether the field does not match any value in the list. Excludes empty fields unless combined with OR is EMPTY . priority NOT IN (Low, Lowest)

IS EMPTY / IS NULL Nullable fields Matches issues where the field contains no value. Equivalent to IS NULL . resolution IS EMPTY

IS NOT EMPTY Nullable fields Matches issues where the field has been populated with any value. duedate IS NOT EMPTY

~ (CONTAINS) Free-text fields (Summary, Description, Environment, Comments) Performs a full-text search with stemming and wildcard support. summary ~ "database connection"

!~ (DOES NOT CONTAIN) Free-text fields Matches issues where the free-text field does not contain the specified search term. description !~ "reproduced"

Important

A critical ACP-120 exam trap involves the behavior of negative operators ( != and NOT IN ) on empty fields. If an administrator queries priority != High , Jira returns all issues where priority is explicitly set to Medium, Low, or Lowest. However, if priority were nullable and empty on an issue, that issue would not be returned. To include unassigned or empty values in negative queries, use: (priority != High OR priority IS EMPTY) .

Historical Searching: The WAS Operator

Standard JQL clauses evaluate only the current state of an issue. However, compliance audits, SLA reporting, and team velocity metrics frequently require knowing whether an issue previously held a specific value, regardless of its current state.

Jira provides the WAS operator to search the historical audit changelog of an issue. +--------------------------------------------------------------------------+

  • | THE WAS OPERATOR MECHANICS |
  • +--------------------------------------------------------------------------+
  • | [FIELD] [WAS OPERATOR] [VALUE] [PREDICATE] |
  • | status WAS "Resolved" BY currentUser() |
  • | assignee WAS IN ("alex", "sam") DURING ("2026-01-01", |
  • | "2026-03-31") |
  • +--------------------------------------------------------------------------+
  • Supported Fields for WAS

Atlassian documents that WAS , WAS IN , WAS NOT , WAS NOT IN , and CHANGED work with six fields only :

  • assignee
  • fixVersion
  • priority
  • reporter
  • resolution
  • status

WAS matches the value name as it was configured when the change happened, and also matches the value's ID. If an issue has more than 10,000 changes, history operators search only the most recent ones.

Warning

Custom fields do not support the WAS operator in native Jira Cloud. Attempting to execute cf[10050] WAS "Approved" will throw a JQL syntax validation error. Administrators must rely on Jira Automation audit trails, external audit apps, or changelog REST APIs for historical tracking of custom fields.

Historical Predicates for WAS

The WAS operator can be qualified using temporal and actor predicates to isolate exactly when or by whom a historical value was set:

BEFORE "date" : Matches issues where the field held the specified value before a certain date. status WAS "In Progress" BEFORE "2026-01-01"

AFTER "date" : Matches issues where the field held the specified value after a certain date. priority WAS High AFTER "2026-06-01"

ON "date" : Matches issues where the field held the value on a specific calendar date. assignee WAS "jsmith" ON "2026-05-15"

DURING ("date1", "date2") : Matches issues where the field held the value during an inclusive date range. status WAS "Blocked" DURING ("2026-03-01", "2026-03-15")

BY user : Matches issues where the value was set by a specific user (account ID), a list of users, or a function such as currentUser() . status WAS "Under Review" BY currentUser()

WAS vs. WAS IN vs. WAS NOT IN

status WAS "Done" : Returns issues that occupied the "Done" status at any point in their lifecycle, even if they were subsequently reopened to "In Progress".

status WAS IN ("In Review", "QA Testing") : Returns issues that occupied either "In Review" or "QA Testing" at some historical point.

status WAS NOT IN ("Done", "Cancelled") : Returns issues that have never been in Done or Cancelled. It's equivalent to status WAS NOT "Done" AND status WAS NOT "Cancelled" .

Historical Event Searching: The CHANGED Operator

While the WAS operator queries historical states (i.e., whether an issue resided in a state), the CHANGED operator queries historical events (i.e., whether a field underwent a change or transition). +--------------------------------------------------------------------------+

  • | THE CHANGED OPERATOR & PREDICATES |
  • +--------------------------------------------------------------------------+
  • | [FIELD] [CHANGED] [FROM value] [TO value] [TEMPORAL/ACTOR] |
  • | status CHANGED FROM "In Progress" TO "Done" BY currentUser() |
  • | DURING ( |
  • | startOfWeek(), |
  • | now() |
  • | ) |
  • +--------------------------------------------------------------------------+
  • Supported Fields for CHANGED

CHANGED works on the same six fields as WAS : assignee, fixVersion, priority, reporter, resolution, and status.

The Seven Predicates for CHANGED

The CHANGED operator supports seven optional predicates that can be chained together in a single clause:

  • Predicate Purpose & Syntax Practical Use Case
  • FROM "value" Specifies the previous value before the change event. status CHANGED FROM "In Review"
  • TO "value" Specifies the new value after the change event. status CHANGED TO "Done"
  • BY user Identifies the user who executed the modification. assignee CHANGED BY currentUser()

BEFORE "date" Restricts the change event to have occurred prior to a timestamp. resolution CHANGED TO Done BEFORE "2026-01-01"

AFTER "date" Restricts the change event to have occurred following a timestamp. priority CHANGED TO Critical AFTER startOfWeek()

ON "date" Restricts the change event to a specific calendar date. status CHANGED TO Shipped ON "2026-04-10"

DURING ("date1", "date2") Restricts the change event to a specific window of time. status CHANGED TO Resolved DURING (startOfWeek(), now())

Chaining Predicates Together

Administrators can combine transition predicates to construct highly specific audit queries. For example, to find all issues transitioned from "In Progress" directly to "Done" by the current user during the active working week: status CHANGED FROM "In Progress" TO "Done" BY currentUser() DURING (startOfWeek(), now())

Crucial Distinction: WAS vs. CHANGED

Consider an issue that was transitioned to "Resolved" on March 1st and remained in "Resolved" until March 10th.

status CHANGED TO "Resolved" ON "2026-03-05" : Returns FALSE . The transition event occurred on March 1st, not on March 5th.

status WAS "Resolved" ON "2026-03-05" : Returns TRUE . On March 5th, the issue resided in the "Resolved" status.

This conceptual difference between an event ( CHANGED ) and a state ( WAS ) is a frequent focal point of ACP-120 exam scenarios.

Basic Search vs. JQL: Know the Limits

Blueprint 6.1 lists the limitations of basic search . Basic search builds a query from dropdowns (project, type, status, assignee, and "more" fields) plus a text box. It's quick, but it can't express everything JQL can:

Need Basic Search JQL (Advanced)

OR between different fields (status = Blocked OR priority = Highest) Not possible; criteria are always combined with AND Yes

  • Parentheses to control precedence No Yes
  • History operators ( WAS , CHANGED ) No Yes

Functions such as membersOf() , startOfWeek("-1") , spacesWhereUserHasRole() Only a few built-in choices (for example, current user) Full function library

Custom sorting with ORDER BY on any field Limited to column sorting in results Yes

If a JQL query is too complex to show as basic criteria, Jira won't let you switch it back to basic mode. That's a common sign in exam scenarios that the query uses OR, parentheses, or functions.

Performance Tips for Historical Queries

History operators search each issue's change history, which is far more work than checking current values. Keep these queries fast and readable:

Scope first: add project , issuetype , or date limits before the history clause: project = PROJ AND status CHANGED TO Resolved .

Bound the time: use DURING , AFTER , or BEFORE rather than searching an issue's entire history.

Combine current and past state: status != Done AND status WAS "QA Rejected" finds open issues that were rejected at some point.

Loading diagram... Current-State Search vs. History Search in JQL