QQL (Quevell Query Language) это язык, на котором задаются вопросы о задачах: в поиске, в сохраненных фильтрах, на досках и в условиях правил автоматизации. Везде один и тот же язык с одним и тем же разбором: запрос, работающий в поиске, дословно работает в условии правила.
Тому, кто пишет на JQL, синтаксис знаком: =, in, ~, and, order by означают то, что вы ожидаете. Чего в языке нет намеренно: предикатов по истории (was, changed). Каждый оператор QQL исполняется с предсказуемой стоимостью.
Синтаксис
Запрос это условие и, при желании, сортировка:
status = "In progress" and assignee = currentUser() order by updated desc
- Условия соединяются
andиor, группируются скобками, отрицаютсяnot. - Регистр не важен:
Status,statusиSTATUSэто одно поле,ANDиandэто один союз. - Пустота проверяется словами:
dueDate is empty,assignee is not empty. Пустота как равенство «ничему» не выражается намеренно. - Списки значений:
status in ("To do", "In progress"),assignee not in (anna@example.com, ivan@example.com). - Запрос из одной сортировки тоже запрос:
order by updated descозначает «все, что мне видно, свежее сверху».
Запрос всегда отвечает в пределах видимости спрашивающего: задачи из проектов, которые вам не видны, не существуют для вашего запроса. Это относится и к правилам автоматизации: их условия отвечают глазами аккаунта правила.
Операторы
| Оператор | Смысл |
|---|---|
= , != | Равно, не равно |
in , not in | Входит в список, не входит |
~ | Содержит текст |
is empty , is not empty | Пусто, не пусто |
> >= < <= | Сравнение чисел, дат и длительностей |
Не каждый оператор применим к каждому полю: у даты нет ~, у текста нет >. Такой запрос не выполняется «в никуда», а отклоняется при разборе с указанием места и списка операторов, которые поле принимает. Полный перечень: в таблицах ниже.
Приоритет операторов
not сильнее and, and сильнее or. Запрос a or b and c означает a or (b and c). Скобки всегда выигрывают: (a or b) and c.
Кавычки и экранирование
Значение с пробелами или служебными символами берется в кавычки, двойные или одинарные: status = "In progress", summary ~ 'новый офис'. Внутри кавычек нет экранирования: строка с двойными кавычками берется в одинарные и наоборот. Значения без пробелов пишутся как есть: OFFICE-13, -7d, 2026-08-24, anna@example.com.
Значения перечислимых полей распознаются по любому написанию: ключу, названию по умолчанию и каждому переводу. status = "В работе" и status = "In progress" это один запрос: значение становится стабильным ключом, и фильтр переживает переименование статуса.
Системные поля
Таблица генерируется из кода продукта и не может от него отстать.
| Поле | Операторы | Сортировка |
|---|---|---|
assignee | = != in not in is empty is not empty | нет |
created | > >= < <= | да |
description | = != ~ is empty is not empty | нет |
dueDate | is empty is not empty > >= < <= | да |
key | = != in not in | да |
level | = != in not in | нет |
originalEstimate | = != is empty is not empty > >= < <= | да |
parent | = != in not in is empty is not empty | нет |
priority | = != in not in is empty is not empty | да |
project | = != in not in | да |
remainingEstimate | = != is empty is not empty > >= < <= | да |
reporter | = != in not in is empty is not empty | нет |
startDate | is empty is not empty > >= < <= | да |
status | = != in not in | нет |
statusCategory | = != in not in | нет |
summary | = != ~ is empty is not empty | нет |
team | = != in not in is empty is not empty | нет |
text | ~ | нет |
timeSpent | = != > >= < <= | да |
type | = != in not in | нет |
updated | > >= < <= | да |
Замечания к отдельным полям:
keyиparentпринимают ключи задач:key in (OFFICE-1, OFFICE-2),parent = OFFICE-13. Регистр ключа не важен.textэто то же, что ищет строка поиска: название и описание вместе. Только~.teamспрашивает, отмечена ли команда на задаче:team = "Логистика". Одна задача может нести несколько команд, поэтому равенство здесь означает «содержит».statusCategoryпринимает три значения:TODO,IN_PROGRESS,DONE, а также написанияto doиin progress.priorityпринимаетhighest,high,medium,low,lowest.- Длительности (
timeSpent,originalEstimate,remainingEstimate) сравниваются в формате учета времени:timeSpent > 1d,originalEstimate <= 2w, где1w= 5 дней,1d= 8 часов. startDateиdueDateэто календарные дни: «срок на этой неделе» означает одно и то же в любом часовом поясе.createdиupdatedэто моменты времени.
Кастомные поля
Кастомное поле спрашивается по своему имени: Бюджет > 100000, "Дата запуска" < startOfMonth(). Операторы определяются типом поля:
| Тип поля | Операторы | Сортировка |
|---|---|---|
| Дата | = != is empty is not empty > >= < <= | да |
| Задача | = != in not in is empty is not empty | нет |
| Мультивыбор | in not in is empty is not empty | нет |
| Число | = != is empty is not empty > >= < <= | да |
| Абзац | ~ is empty is not empty | нет |
| Выбор | = != in not in is empty is not empty | да |
| Строка | = != ~ is empty is not empty | нет |
| Ссылка | = != ~ is empty is not empty | нет |
| Пользователь | = != in not in is empty is not empty | нет |
- У числа нет
~: подстрока числа ничего о нем не говорит. У абзаца нет=: точное равенство со страницей текста никто никогда не имел в виду. Многозначный выбор спрашивается толькоinиnot in. - Поля определяются в проектах, поэтому одно имя может означать несколько определений. Запрос по имени означает их все, пока они одного типа; имя, означающее в одном проекте дату, а в другом абзац, ведет себя как текст.
- Запрос хранит стабильные идентификаторы, а не имена: переименование поля или варианта не ломает сохраненный фильтр.
Функции
| Функция | Что означает |
|---|---|
currentUser() | Тот, кто выполняет запрос. В сохраненном фильтре: тот, кто его открыл, а не тот, кто написал. |
myReports() | Мои прямые подчиненные по организационной структуре. Без меня самого. |
myVertical() | Все, кто подо мной по структуре, на любую глубину. Без меня самого. |
myTeammates() | Все люди из всех команд, где я состою, в любой роли. Без меня самого. |
now() | Текущий момент. |
startOfDay() , startOfWeek() , startOfMonth() | Начало сегодняшнего дня, недели (с понедельника), месяца. |
myReports(), myVertical() и myTeammates() называют нескольких людей, поэтому спрашиваются через in: assignee in (myReports()). Форма assignee = myReports() отклоняется с подсказкой. «Моя команда и я» составляется так: assignee in (myReports(), currentUser()).
Функции людей и времени разрешаются при каждом выполнении, а не при сохранении: фильтр «обновлено за последнюю неделю» означает последнюю неделю читателя каждый раз, когда он его открывает.
Даты и относительное время
Поля дат и моментов сравниваются с:
- фиксированной датой:
duedate <= 2026-09-15; - относительным сдвигом:
updated > -7d(семь дней назад),duedate <= +7d(семь дней вперед); единицыd,w,m: дни, недели, месяцы; - функциями:
created >= startOfMonth(),updated > startOfWeek().
Люди
Человек называется по имени или по адресу почты: assignee = "Анна Петрова", assignee = anna@example.com. Если в компании два человека с одним именем, запрос по имени отклоняется и просит адрес: два человека с одним именем это факт о компании, и запрос должен сказать, кого имел в виду.
Сортировка
order by поле и направление: asc (по умолчанию) или desc. Сортируемость поля указана в таблицах выше; попытка сортировать несортируемое поле отклоняется при разборе. Один ключ сортировки на запрос.
project = OFFICE and status != Done order by duedate asc
Сообщения об ошибках
Ошибка разбора указывает на позицию в запросе и говорит, что именно не так. Типичные сообщения и их смысл:
| Сообщение | Что означает |
|---|---|
There is no field called "..." | Такого поля нет. Проверьте имя; кастомные поля спрашиваются по имени поля, статусы это значения поля status. |
"..." does not support ~. It accepts =, !=, ... | Оператор не применим к полю; список рядом перечисляет применимые. |
There is no status called "..." | Значение не входит в словарь поля. Если словарь короткий, он приводится тут же. |
Nobody here is called "..." | Человек с таким именем или адресом не найден. |
2 people are called "...". Use their email address instead | Имя неоднозначно; спросите по адресу. |
"..." is not a date. Use 2026-08-24, -7d, startOfWeek() or now() | Значение не читается как дата или сдвиг. |
That is not a duration. Use the 1w 2d 4h 30m form (1w = 5d, 1d = 8h) | Длительность в другом формате. |
"..." is not an issue key like PROJECT-12 | Поле ожидает ключ задачи. |
"..." cannot be ordered by | Поле не сортируется. |
This quote is never closed | Кавычка открыта и не закрыта. |
myReports() names several people. Ask with "assignee in (myReports())" | Функция называет нескольких людей и спрашивается через in. |
Примеры
assignee = currentUser() and status != Done order by duedate asc
Мои незакрытые задачи, ближайшие сроки сверху.
project in (OFFICE, WAREHOUSE) and priority in (highest, high) and status = "In progress"
Горящее в работе по двум проектам.
assignee in (myVertical()) and duedate < startOfWeek() and status != Done
Просроченное у всех, кто подо мной по структуре.
summary ~ "переезд" or description ~ "переезд"
Задачи, где переезд упомянут в названии или описании. То же самое короче: text ~ "переезд".
type = Bug and created >= -30d and assignee is empty
Дефекты за месяц, у которых нет исполнителя.
"Бюджет" > 500000 and "Дата запуска" <= startOfMonth()
Кастомные поля: число и дата.
team = "Логистика" and remainingEstimate > 1w
Задачи команды, где осталось больше недели работы.