SELECT
Содержание
1. Обзор
Оператор SELECT используется для выполнения запросов к базе данных. Результатом выполнения SELECT является ноль или более строк данных, каждая из которых содержит фиксированное число столбцов. Оператор SELECT не вносит изменений в базу данных.
Приведённая выше синтаксическая диаграмма «select-stmt» пытается показать как можно больше синтаксиса оператора SELECT на одной диаграмме, поскольку некоторым читателям это помогает. Следующая диаграмма синтаксиса «factored-select-stmt» — это альтернативная диаграмма, которая описывает тот же синтаксис, но пытается разбить его на более мелкие части.
Обратите внимание, что на диаграммах синтаксиса есть пути, которые на практике недопустимы. Например:
- Предложение VALUES может быть первым элементом в составном SELECT, в котором используется предложение WITH, однако перед простым SELECT, состоящим только из предложения VALUES, нельзя помещать предложение WITH.
- Предложение WITH должно находиться в первом SELECT составного SELECT. Оно не может следовать за оператором составного запроса.
Эти и другие подобные ограничения синтаксиса описаны в тексте.
Оператор SELECT — самая сложная команда языка SQL. Чтобы описание было легче понять, в некоторых фрагментах ниже рассматривается, как определяется набор данных, возвращаемый оператором SELECT, в виде последовательности шагов. Важно помнить, что это лишь иллюстрация: на практике ни SQLite, ни какой-либо другой механизм SQL не обязан следовать этому или любому другому определённому процессу.
2. Обработка простого SELECT
Основой оператора SELECT является «простой SELECT», представленный на приведённых ниже синтаксических диаграммах select-core и simple-select-stmt. На практике большинство операторов SELECT являются простыми операторами SELECT.
В описании ниже генерация результатов простого оператора SELECT представлена как процесс из четырёх шагов:
-
Обработка предложения FROM: определяется входной набор данных для простого оператора SELECT. Входные данные — это либо неявно одна строка с 0 столбцами (если предложение FROM отсутствует), либо данные, определяемые предложением FROM.
-
Обработка предложения WHERE: входные данные фильтруются с помощью выражения предложения WHERE.
-
Обработка GROUP BY, HAVING и выражений столбцов результата: набор результирующих строк вычисляется путем агрегирования данных согласно предложению GROUP BY (если оно есть) и вычисления выражений результирующего набора для строк отфильтрованного входного набора данных.
-
Обработка ключевого слова DISTINCT/ALL: если запрос является запросом "SELECT DISTINCT", из набора результирующих строк удаляются дубликаты.
Существует два типа простых операторов SELECT — агрегатные и неагрегатные запросы. Простой оператор SELECT является агрегатным запросом, если он содержит предложение GROUP BY или одну либо несколько агрегатных функций в результирующем наборе. В противном случае, если простой запрос SELECT не содержит агрегатных функций и предложения GROUP BY, он является неагрегатным запросом.
2.1. Определение входных данных (обработка предложения FROM)
Входные данные, используемые простым запросом SELECT, представляют собой набор из N строк, каждая из которых содержит M столбцов.
Если в простом операторе SELECT предложение FROM опущено, входные данные неявно представляют собой одну строку с нулем столбцов (то есть N=1 и M=0).
Если указано предложение FROM, данные, с которыми работает простой запрос SELECT, берутся из одной или нескольких таблиц либо подзапросов (операторов SELECT в скобках), указанных после ключевого слова FROM. Подзапрос, указанный в table-or-subquery после предложения FROM в простом операторе SELECT, обрабатывается так, как если бы он был таблицей, содержащей данные, возвращаемые при выполнении оператора подзапроса. Каждый столбец подзапроса имеет последовательность сортировки и типовую принадлежность, соответствующие выражению подзапроса.
Если в предложении FROM указана только одна таблица или один подзапрос, входными данными оператора SELECT является содержимое указанной таблицы. Если в предложении FROM указано более одной таблицы или подзапроса, содержимое всех таблиц и/или подзапросов объединяется в один набор данных, с которым работает простой оператор SELECT. То, как именно объединяются данные, зависит от конкретных оператора соединения и ограничения соединения, использованных для связи таблиц или подзапросов.
Все соединения в SQLite основаны на декартовом произведении левого и правого наборов данных. Столбцы набора данных декартова произведения идут в следующем порядке: сначала все столбцы левого набора данных, затем все столбцы правого. Для каждой уникальной комбинации строки из левого набора данных и строки из правого набора данных в наборе данных декартова произведения формируется строка. Другими словами, если левый набор данных состоит из Nleft строк по Mleft столбцов, а правый — из Nright строк по Mright столбцов, то декартово произведение представляет собой набор данных из Nleft×Nright строк, каждая из которых содержит Mleft+Mright столбцов.
Если оператор соединения — это "CROSS JOIN", "INNER JOIN", "JOIN" или запятая (",") и при этом отсутствует предложение ON или USING, результатом соединения является просто декартово произведение левого и правого наборов данных. Если оператор соединения содержит предложения ON или USING, они обрабатываются согласно следующим пунктам:
-
Если есть предложение ON, выражение ON вычисляется для каждой строки декартова произведения как логическое выражение. В набор включаются только строки, для которых выражение принимает значение true.
-
Если есть предложение USING, каждое из указанных в нем имен столбцов должно существовать в наборах данных как слева, так и справа от оператора соединения. Для каждой пары столбцов с одинаковыми именами выражение "lhs.X = rhs.X" вычисляется для каждой строки декартова произведения как логическое выражение. В результирующий набор включаются только строки, для которых все такие выражения принимают значение true. При сравнении значений в результате применения предложения USING действуют обычные правила обработки типовой принадлежности, последовательностей сортировки и значений NULL. Для определения приоритета последовательности сортировки и типовой принадлежности столбец из набора данных слева от оператора соединения считается находящимся слева от оператора сравнения (=).
Для каждой пары столбцов, определенной предложением USING, столбец из правого набора данных исключается из объединенного набора. Это единственное отличие предложения USING от эквивалентного ограничения ON.
-
Если в операторе соединения указано ключевое слово NATURAL, к ограничениям соединения добавляется неявное предложение USING. Это неявное предложение USING содержит имена всех столбцов, присутствующих в обоих входных наборах данных — левом и правом. Если у левого и правого входных наборов данных нет общих имен столбцов, ключевое слово NATURAL не влияет на результаты соединения. К соединению с ключевым словом NATURAL нельзя добавить предложение USING или ON.
-
Если оператор соединения — "LEFT JOIN" или "LEFT OUTER JOIN", то после применения фильтрующих предложений ON или USING в результат добавляется дополнительная строка для каждой строки исходного левого входного набора данных, которой не соответствует ни одна строка правого набора данных. В добавленных строках столбцы, в которых обычно содержались бы значения из правого входного набора данных, содержат значения NULL.
-
Если оператор соединения — "RIGHT JOIN" или "RIGHT OUTER JOIN", то после применения фильтрующих предложений ON или USING в результат добавляется дополнительная строка для каждой строки исходного правого входного набора данных, которой не соответствует ни одна строка левого набора данных. В добавленных строках столбцы, в которых обычно содержались бы значения из левого входного набора данных, содержат значения NULL.
-
"FULL JOIN" или "FULL OUTER JOIN" — это сочетание "LEFT JOIN" и "RIGHT JOIN". В результат добавляются дополнительные строки для каждой строки левого набора данных, которой не соответствует ни одна строка правого набора, и для каждой строки правого набора данных, которой не соответствует ни одна строка левого набора. Несовпавшие столбцы заполняются значениями NULL.
Если в рамках предложения FROM соединяются более двух таблиц, операции соединения выполняются слева направо. Другими словами, предложение FROM (A join-op-1 B join-op-2 C) вычисляется как ((A join-op-1 B) join-op-2 C).
2.2. Особая обработка CROSS JOIN.
Между операторами соединения "INNER JOIN", "JOIN" и "," нет различий. В SQLite они полностью взаимозаменяемы. Оператор соединения "CROSS JOIN" дает тот же результат, что и операторы "INNER JOIN", "JOIN" и ",", но обрабатывается оптимизатором запросов иначе: он не позволяет оптимизатору запросов менять порядок таблиц в соединении. Программист может использовать оператор CROSS JOIN, чтобы напрямую влиять на алгоритм, выбранный для реализации оператора SELECT. Не используйте CROSS JOIN, кроме особых случаев, когда требуется вручную управлять оптимизатором запросов. Не используйте CROSS JOIN на ранних этапах разработки приложения, поскольку это преждевременная оптимизация. Особая обработка CROSS JOIN — это специфическая возможность SQLite, не входящая в стандарт SQL.
2.3. Фильтрация с помощью предложения WHERE.
Если указано предложение WHERE, выражение WHERE вычисляется для каждой строки входных данных как логическое выражение. При дальнейшей обработке набора данных учитываются только строки, для которых выражение предложения WHERE принимает значение true. Строки исключаются из результата, если выражение WHERE принимает значение false или NULL.
Для JOIN, INNER JOIN или CROSS JOIN между ограничивающим выражением в предложении WHERE и таким же выражением в предложении ON нет различий. Однако для LEFT, RIGHT или FULL OUTER JOIN это различие очень важно. При внешнем соединении дополнительные строки NULL для несовпавших строк другого операнда добавляются после обработки предложения ON, но до обработки предложения WHERE. Поэтому ограничение вида "left.x=right.y" в предложении ON пропустит добавленные строки, состоящие только из NULL. Но если то же ограничение указано в предложении WHERE, значение NULL в одном из столбцов "right.y" или "left.x" не позволит выражению "left.x=right.y" принять значение true, и эта строка будет исключена из результата.
2.4. Формирование набора результирующих строк
После того как входные данные из предложения FROM (если оно есть) отфильтрованы выражением предложения WHERE, вычисляется набор результирующих строк простого оператора SELECT. То, как именно это делается, зависит от того, является ли простой оператор SELECT агрегатным или неагрегатным запросом, а также от наличия предложения GROUP BY.
Список выражений между ключевыми словами SELECT и FROM называется списком выражений результата. Если выражение результата — специальное выражение "*", оно заменяется всеми столбцами входных данных. Если выражение — это псевдоним таблицы или подзапроса в предложении FROM, за которым следует ".*", оно заменяется всеми столбцами указанной таблицы или подзапроса. Использование выражения "*" или "alias.*" в любом контексте, кроме списка выражений результата, является ошибкой. Также ошибкой является использование выражения "*" или "alias.*" в простом запросе SELECT без предложения FROM.
Число столбцов в строках, возвращаемых простым оператором SELECT, равно числу выражений в списке выражений результата после замены выражений * и alias.*. Каждая результирующая строка вычисляется путем вычисления выражений в списке выражений результата относительно одной строки входных данных или, для агрегатных запросов, относительно группы строк.
Если оператор SELECT является неагрегатным запросом, каждое выражение в списке выражений результата вычисляется для каждой строки набора данных, отфильтрованного предложением WHERE.
-
Если оператор SELECT является агрегатным запросом без предложения GROUP BY, каждое агрегатное выражение в результирующем наборе вычисляется один раз для всего набора данных. Каждое неагрегатное выражение в результирующем наборе вычисляется один раз для произвольно выбранной строки набора данных. Для всех неагрегатных выражений используется одна и та же произвольно выбранная строка. Если набор данных не содержит строк, каждое неагрегатное выражение вычисляется относительно строки, состоящей только из значений NULL.
Одна строка результирующих данных, созданная путем вычисления агрегатных и неагрегатных выражений в результирующем наборе, образует результат агрегатного запроса без предложения GROUP BY. Агрегатный запрос без предложения GROUP BY всегда возвращает ровно одну строку данных, даже если входные данные не содержат строк.
-
Если оператор SELECT является агрегатным запросом с предложением GROUP BY, каждое выражение, указанное в предложении GROUP BY, вычисляется для каждой строки набора данных согласно приведенным ниже правилам обработки выражений ORDER BY. Затем каждая строка помещается в группу в зависимости от результатов: строки, для которых вычисление выражений GROUP BY дает одинаковые результаты, относятся к одной группе. При группировке строк значения NULL считаются равными. При вычислении выражений в предложении GROUP BY применяются обычные правила выбора последовательности сортировки для сравнения текстовых значений. Выражения в предложении GROUP BY не обязаны присутствовать в результирующем наборе. Выражения в предложении GROUP BY не могут быть агрегатными выражениями.
Если указано предложение HAVING, оно вычисляется один раз для каждой группы строк как логическое выражение. Если результат вычисления предложения HAVING — false, группа отбрасывается. Если предложение HAVING содержит агрегатное выражение, оно вычисляется для всех строк группы. Если предложение HAVING содержит неагрегатное выражение, оно вычисляется относительно произвольно выбранной строки из группы. Выражение HAVING может ссылаться на значения, в том числе на агрегатные функции, отсутствующие в результирующем наборе.
Затем каждое выражение в результирующем наборе вычисляется один раз для каждой группы строк. Если выражение является агрегатным, оно вычисляется для всех строк группы. В противном случае оно вычисляется относительно одной произвольно выбранной строки из группы. Если в результирующем наборе больше одного неагрегатного выражения, все такие выражения вычисляются для одной и той же строки.
Каждая группа строк входного набора данных вносит одну строку в набор результирующих строк. С учетом фильтрации, связанной с ключевым словом DISTINCT, число строк, возвращаемых агрегатным запросом с предложением GROUP BY, совпадает с числом групп строк, полученных при применении предложений GROUP BY и HAVING к отфильтрованному входному набору данных.
2.5. Неагрегированные столбцы в агрегатном запросе
Обычно все имена столбцов в агрегатном запросе являются аргументами агрегатных функций или присутствуют в предложении GROUP BY. Столбец результата, содержащий имя столбца, которое не входит в агрегатную функцию и не присутствует в предложении GROUP BY (если оно есть), называется «неагрегированным» столбцом. Пример:
SELECT a, b, sum(c) FROM tab1 GROUP BY a;
В приведенном выше запросе столбец "a" входит в предложение GROUP BY, поэтому каждая строка результата содержит одно из различных значений "a". Столбец "c" входит в агрегатную функцию sum(), поэтому этот столбец результата содержит сумму всех значений "c" в строках с одинаковым значением "a". Но каково значение неагрегированного столбца "b"? Столбец "b" в результате будет содержать значение "b" из одной из входных строк, составляющих агрегат.¹ Проблема в том, что обычно неизвестно, какая именно входная строка используется для вычисления "b", поэтому во многих случаях значение "b" не определено.
Особая обработка применяется, если агрегатная функция — это min() или max(). Пример:
SELECT a, b, max(c) FROM tab1 GROUP BY a;
Если в запросе ровно одна агрегатная функция min() или max(), все неагрегированные столбцы в результирующем наборе принимают значения из входной строки, которая также содержит минимум или максимум. Поэтому в приведенном выше запросе столбец "b" в результате будет содержать значение столбца "b" из входной строки с наибольшим значением "c". Для этого особого поведения min() и max() существуют ограничения:
-
Если минимальное или максимальное значение встречается в двух или более строках, неагрегированные значения могут быть выбраны из любой из этих строк. Выбор произволен. Невозможно предсказать, из какой строки будут взяты неагрегированные значения. Для разных неагрегированных столбцов в одном запросе могут быть выбраны разные строки.
-
Если в запросе две или более агрегатных функции min() или max(), значения неагрегированных столбцов будут взяты из одной из строк, в которых одна из агрегатных функций достигает своего минимума или максимума. Выбор того, какая агрегатная функция min() или max() определяет выбор значений неагрегированных столбцов, произволен. Для разных неагрегированных столбцов в одном запросе могут быть выбраны разные строки.
-
Эта особая обработка агрегатных функций min() или max() работает только для их встроенных реализаций. Если приложение заменяет встроенные агрегатные функции min() или max() альтернативными функциями, определенными приложением, значения неагрегированных столбцов будут взяты из произвольной строки.
Большинство других систем управления базами данных SQL запрещают неагрегированные столбцы. Если включить неагрегированный столбец в запрос, другие системы обычно выдадут ошибку. Возможность включать неагрегированные столбцы в запрос — расширение, специфичное для SQLite. Это считается особенностью, а не ошибкой. Дополнительную информацию см. в обсуждении 7481d2a6df8980ff на форуме SQLite.
2.5.1. Примечания
- Если агрегат состоит из одной или нескольких входных строк, неагрегированный столбец принимает значение из произвольной строки входных данных агрегата. Выбранная строка может меняться от одного вызова к другому. Если агрегат пуст (то есть у него нет входных строк, как бывает, когда ни одна строка не соответствует предложению WHERE), неагрегированный столбец может принимать любое произвольное значение, в том числе значения, отсутствующие во всех таблицах предложения FROM.
2.6. Удаление дублирующихся строк (обработка DISTINCT)
В простом операторе SELECT после ключевого слова SELECT может указываться одно из ключевых слов ALL или DISTINCT. Если простой оператор SELECT — это SELECT ALL, оператор возвращает весь набор результирующих строк. Если не указано ни ALL, ни DISTINCT, поведение соответствует указанию ALL. Если простой оператор SELECT — это SELECT DISTINCT, дублирующиеся строки удаляются из набора результирующих строк перед его возвратом. Для выявления дублирующихся строк значения сравниваются с помощью оператора IS DISTINCT FROM. Поэтому два значения NULL считаются равными. Целое число равно числу с плавающей точкой, если они представляют одну и ту же величину. Текстовые значения сравниваются с использованием соответствующей последовательности сортировки. Для выбора последовательности сортировки при сравнении текстовых значений применяются обычные правила. Для сравнений DISTINCT используется типовая принадлежность BLOB, поэтому преобразование типов не выполняется.
3. Составные операторы SELECT
Два или более простых оператора SELECT можно объединить в составной оператор SELECT с помощью операторов UNION, UNION ALL, INTERSECT или EXCEPT, как показано на следующей диаграмме:
В составном SELECT все составляющие его операторы SELECT должны возвращать одинаковое количество столбцов результата. Поскольку компоненты составного SELECT должны быть простыми операторами SELECT, они не могут содержать предложения ORDER BY или LIMIT. Предложения ORDER BY и LIMIT могут встречаться только в конце всего составного SELECT и только если последний элемент составного запроса не является предложением VALUES.
Составной SELECT, созданный с помощью оператора UNION ALL, возвращает все строки из оператора SELECT слева от оператора UNION ALL и все строки из оператора SELECT справа от него. Оператор UNION работает так же, как UNION ALL, за исключением того, что повторяющиеся строки удаляются из итогового набора результатов. Оператор INTERSECT возвращает пересечение результатов левого и правого операторов SELECT. Оператор EXCEPT возвращает подмножество строк, возвращённых левым оператором SELECT, которые не возвращаются правым оператором SELECT. Повторяющиеся строки удаляются из результатов операторов INTERSECT и EXCEPT до возврата набора результатов.
При определении повторяющихся строк в результатах операторов составного SELECT значения NULL считаются равными другим значениям NULL и отличными от всех значений, не равных NULL. Последовательность сортировки, используемая для сравнения двух текстовых значений, определяется так, как если бы столбцы операторов SELECT слева и справа были левым и правым операндами оператора равенства (=), за исключением того, что последовательности сортировки, указанной с помощью постфиксного оператора COLLATE, не назначается более высокий приоритет. При сравнении строк в составе составного SELECT никакие преобразования по правилам аффинности типов не применяются.
Если три или более простых оператора SELECT объединены в составной SELECT, группировка выполняется слева направо. Иными словами, если "A", "B" и "C" — простые операторы SELECT, то (A op B op C) обрабатывается как ((A op B) op C).
4. Предложение ORDER BY
Если оператор SELECT, возвращающий более одной строки, не содержит предложения ORDER BY, порядок возврата строк не определён. Если же оператор SELECT содержит предложение ORDER BY, список выражений, указанных в ORDER BY, определяет порядок возврата строк пользователю.
В операторе составного SELECT предложение ORDER BY может присутствовать только в последнем, то есть самом правом, простом операторе SELECT. Это предложение ORDER BY применяется ко всем элементам составного запроса. Если самый правый элемент составного SELECT — это предложение VALUES, то в этом операторе предложение ORDER BY не допускается.
Сначала строки сортируются по результатам вычисления самого левого выражения в списке ORDER BY, затем равные значения упорядочиваются по результатам вычисления следующего выражения слева и так далее. Порядок возврата двух строк, для которых все выражения ORDER BY вычисляются в одинаковые значения, не определён. После каждого выражения ORDER BY можно указать одно из ключевых слов ASC (сначала возвращаются меньшие значения) или DESC (сначала возвращаются большие значения). Если не указано ни ASC, ни DESC, по умолчанию строки сортируются по возрастанию (сначала меньшие значения).
Для целей сортировки SQLite считает значения NULL меньшими любых других значений. Поэтому значения NULL естественным образом оказываются в начале сортировки по возрастанию и в конце сортировки по убыванию. Это можно изменить с помощью синтаксиса "ASC NULLS LAST" или "DESC NULLS FIRST".
Каждое выражение ORDER BY обрабатывается следующим образом:
Если выражение ORDER BY — это постоянное целое число K, оно считается псевдонимом K-го столбца набора результатов (столбцы нумеруются слева направо, начиная с 1).
Если выражение ORDER BY — это идентификатор, соответствующий псевдониму одного из выходных столбцов, оно считается псевдонимом этого столбца.
В противном случае, если выражение ORDER BY — любое другое выражение, оно вычисляется, а возвращённое значение используется для упорядочивания выходных строк. Если оператор SELECT является простым SELECT, ORDER BY может содержать любые произвольные выражения. Однако если SELECT является составным SELECT, выражения ORDER BY, не являющиеся псевдонимами выходных столбцов, должны в точности совпадать с выражением, используемым в качестве выходного столбца.
При сортировке строк значения сравниваются так же, как в выражениях сравнения. Последовательность сортировки, используемая для сравнения двух текстовых значений, определяется следующим образом:
Если выражению ORDER BY назначена последовательность сортировки с помощью постфиксного оператора COLLATE, используется указанная последовательность сортировки.
В противном случае, если выражение ORDER BY является псевдонимом выражения, которому назначена последовательность сортировки с помощью постфиксного оператора COLLATE, используется последовательность сортировки, назначенная выражению, для которого задан псевдоним.
В противном случае, если выражение ORDER BY — это столбец или псевдоним выражения, являющегося столбцом, используется последовательность сортировки по умолчанию для этого столбца.
В противном случае используется последовательность сортировки BINARY.
В операторе составного SELECT все выражения ORDER BY обрабатываются как псевдонимы одного из столбцов результата составного запроса. Если выражение ORDER BY не является целочисленным псевдонимом, SQLite ищет в самом левом операторе SELECT составного запроса столбец результата, соответствующий второму или третьему правилу выше. Если совпадение найдено, поиск прекращается, а выражение обрабатывается как псевдоним найденного столбца результата. В противном случае проверяется следующий оператор SELECT справа и так далее. Если в столбцах результата ни одного из составляющих операторов SELECT не найдено соответствующего выражения, возникает ошибка. Каждый элемент предложения ORDER BY обрабатывается отдельно и может сопоставляться со столбцами результата из разных операторов SELECT составного запроса.
5. Предложение LIMIT
Предложение LIMIT используется для ограничения сверху количества строк, возвращаемых всем оператором SELECT.
В составном SELECT предложение LIMIT может содержаться только в последнем, то есть самом правом, простом операторе SELECT. В составном SELECT предложение LIMIT применяется ко всему составному запросу, а не только к последнему SELECT. Если самый правый простой оператор SELECT — это предложение VALUES, то предложение LIMIT не допускается.
В предложении LIMIT можно использовать любое скалярное выражение, если оно вычисляется в целое число или значение, которое можно без потерь преобразовать в целое число. Если выражение вычисляется в значение NULL или любое другое значение, которое нельзя без потерь преобразовать в целое число, возвращается ошибка. Если выражение LIMIT вычисляется в отрицательное значение, верхнее ограничение на количество возвращаемых строк отсутствует. В противном случае SELECT возвращает только первые N строк набора результатов, где N — значение, в которое вычисляется выражение LIMIT. Если без предложения LIMIT оператор SELECT вернул бы меньше N строк, возвращается весь набор результатов.
Выражение, указанное в необязательном предложении OFFSET, которое может следовать за предложением LIMIT, также должно вычисляться в целое число или значение, которое можно без потерь преобразовать в целое число. Если в выражении есть предложение OFFSET, первые M строк исключаются из набора результатов, возвращаемого оператором SELECT, а следующие N строк возвращаются, где M и N — значения, в которые вычисляются предложения OFFSET и LIMIT соответственно. Если без предложения LIMIT оператор SELECT вернул бы меньше M+N строк, первые M строк пропускаются, а оставшиеся строки (если они есть) возвращаются. Если предложение OFFSET вычисляется в отрицательное значение, результат будет таким же, как если бы оно вычислилось в ноль.
Вместо отдельного предложения OFFSET в предложении LIMIT можно указать два скалярных выражения, разделённых запятой. В этом случае первое выражение используется как выражение OFFSET, а второе — как выражение LIMIT. Это может показаться нелогичным, поскольку при использовании предложения OFFSET второе из двух выражений задаёт OFFSET, а первое — LIMIT. Такой порядок OFFSET и LIMIT выбран намеренно — он обеспечивает максимальную совместимость с другими системами баз данных SQL. Однако во избежание путаницы программистам настоятельно рекомендуется использовать форму предложения LIMIT с ключевым словом "OFFSET" и не использовать предложение LIMIT со смещением, заданным через запятую.
6. Предложение VALUES
Выражение "VALUES(expr-list)" означает то же, что и "SELECT expr-list". Выражение "VALUES(expr-list-1),...,(expr-list-N)" означает то же, что и "SELECT expr-list-1 UNION ALL ... UNION ALL SELECT expr-list-N". Эти формы эквивалентны, за исключением того, что количество операторов SELECT в составном запросе ограничено значением SQLITE_LIMIT_COMPOUND_SELECT, тогда как количество строк в предложении VALUES не имеет произвольного ограничения.
Для использования предложения VALUES существуют ограничения, не показанные на синтаксических диаграммах:
После предложения VALUES не может следовать ORDER BY.
После предложения VALUES не может следовать LIMIT.
7. Предложение WITH
Перед операторами SELECT может находиться одно необязательное предложение WITH, определяющее одно или несколько общих табличных выражений для использования в операторе SELECT.
8. Табличные функции в предложении FROM
Виртуальную таблицу, содержащую скрытые столбцы, можно использовать в предложении FROM как табличную функцию. Аргументы табличной функции становятся ограничениями для скрытых столбцов виртуальной таблицы. Дополнительную информацию можно найти в документации по виртуальным таблицам.
9. Отличия от стандартного SQL
Синтаксис SELECT в SQLite немного отличается от стандартного SQL. Эти отличия обусловлены несколькими причинами:
В середине 2000-х годов большое внимание уделялось тому, чтобы библиотека занимала как можно меньше места и не расходовала слишком много памяти телефонов-раскладушек и других устройств с ограниченной памятью.
В первые годы существования SQLite ведущий разработчик стремился следовать закону Постела и проявлять снисходительность и гибкость к принимаемым входным данным.
В ранних парсерах SQLite были ошибки, из-за которых принимались некоторые необычные входные данные.
Знания ведущего разработчика о SQL были несовершенны.
Каково бы ни было происхождение особенностей обработки входных данных, мы обычно не пытаемся их «исправлять», поскольку любые новые ограничения синтаксиса ввода, вероятно, нарушили бы работу хотя бы некоторых из миллионов приложений, использующих SQLite. Мы этого не хотим. Цель команды разработчиков SQLite — по возможности максимально сохранить обратную совместимость. Поэтому безвредные особенности синтаксиса мы оставляем без изменений и описываем здесь, а не пытаемся исправить.
9.1. Необычные имена JOIN
SQLite принимает все обычные варианты синтаксиса для операторов JOIN:
Но на этом дело не заканчивается. SQLite отличается большой гибкостью в способах указания оператора соединения. Общий синтаксис таков:
blah blah blah JOIN
Здесь от 1 до 3 вхождений "blah", каждое из которых может быть одним из следующих слов: "CROSS", "FULL", "INNER", "LEFT", "NATURAL", "OUTER" или "RIGHT". Парсер SQLite рассматривает каждое из этих ключевых слов как атрибут соединения, который можно комбинировать с другими атрибутами в любом порядке. Благодаря этому возможны многие новые и оригинальные типы соединений, не предусмотренные синтаксической диаграммой. Некоторые из этих нестандартных типов соединений явно запрещены. Например, нельзя написать "INNER OUTER JOIN", поскольку это противоречие. Но можно написать, например, "OUTER LEFT NATURAL JOIN", что означает то же, что и "NATURAL LEFT OUTER JOIN". Или можно написать "LEFT RIGHT JOIN", что означает то же, что и "FULL JOIN".
Помните: можно использовать эти нестандартные типы соединений, но не следует этого делать. Для переносимости между разными SQL-системами используйте стандартный синтаксис JOIN.
9.2. Гибкий синтаксис соединений
Стандарт SQL устанавливает более строгие ограничения на синтаксис соединений, чем SQLite. В стандартном SQL для всех соединений, кроме соединений через запятую, CROSS JOIN и NATURAL JOIN, требуется предложение ON или USING; для соединений через запятую, CROSS JOIN и NATURAL JOIN, напротив, запрещено использовать предложения ON и USING. SQLite не так строг в отношении синтаксиса соединений. SQLite принимает и обрабатывает предложение ON или USING при соединении через запятую или CROSS JOIN, а также позволяет опустить предложение ON или USING в любом соединении. В SQLite существуют только следующие ограничения:
В соединении NATURAL нельзя использовать предложение ON или USING.
В одном соединении нельзя одновременно использовать предложения ON и USING.
SQLite позволяет даже опустить предложение ON или USING во внешнем соединении, хотя в этом случае внешнее соединение не имеет ограничений (как если бы предложение ON было "ON true"), и ведёт себя как внутреннее соединение.
9.3. Приоритет соединений через запятую и CROSS JOIN
В стандартном SQL соединения с ключевым словом JOIN имеют более высокий приоритет, чем соединения через запятую. Иными словами, операторы JOIN выполняются раньше операторов-запятых. В SQLite это не так: все соединения имеют одинаковый приоритет.
Рассмотрим следующий пример:
... FROM t1, t2 NATURAL FULL JOIN t3 ...
В стандартном SQL сначала выполнялось бы FULL JOIN таблиц t2 и t3, а затем результат левого соединения объединялся бы перекрёстным соединением с t1. Однако SQLite всегда обрабатывает все соединения слева направо. Поэтому SQLite сначала выполнит перекрёстное соединение t1 и t2, а затем передаст его результат в FULL JOIN с t3. Внутренние соединения по своей природе ассоциативны, поэтому различие проявляется только в том случае, если предложение FROM содержит одно или несколько внешних соединений.
Этого можно избежать и сделать SQL-операторы переносимыми между всеми системами, соблюдая следующие стилистические правила:
Не смешивайте соединения через запятую с ключевым словом JOIN. Использовать соединения через запятую можно, но в таком случае используйте их во всём предложении FROM.
Отдавайте предпочтение LEFT JOIN перед другими операторами внешнего соединения.
Если сомневаетесь, используйте скобки, чтобы точно указать предполагаемый порядок соединений.
Любого из этих советов достаточно, чтобы избежать проблем. Большинство программистов интуитивно следуют всем этим советам, даже если им об этом не говорят, поэтому отсутствие разницы в приоритете между соединениями через запятую и ключевым словом JOIN в SQLite редко становится проблемой на практике. Тем не менее следует помнить об этой особенности на случай, если она всё же проявится.
Последнее обновление этой страницы: 2026-01-26 15:45:07Z
SQLite is in the Public Domain.
https://sqlite.org/lang_select.html