4.1. Лексическая структура
SQL-программа состоит из последовательности команд. Команда, в свою очередь, представляет собой последовательность компонентов, оканчивающуюся точкой с запятой («;»). Конец входного потока также считается концом команды. Какие именно компоненты допустимы для конкретной команды, зависит от её синтаксиса.
Компонентом команды может быть ключевое слово, идентификатор, идентификатор в кавычках, строка (или константа) или специальный символ. Компоненты обычно разделяются пробельными символами (пробел, табуляция, перевод строки), но это не требуется, если нет неоднозначности (например, когда спецсимвол оказывается рядом с компонентом другого типа).
Например, следующий текст является правильной (синтаксически) SQL-программой:
SELECT * FROM MY_TABLE; UPDATE MY_TABLE SET A = 5; INSERT INTO MY_TABLE VALUES (3, 'hi there');
Это последовательность трёх команд, по одной в строке (хотя их можно было разместить и в одну строку или наоборот, разделить команды на несколько строк).
Кроме этого, SQL-программы могут содержать комментарии. Они не являются компонентами команд, а по сути равносильны пробельным символам.
Синтаксис SQL не очень строго определяет, какие компоненты идентифицируют команды, а какие — их операнды или параметры. Первые несколько компонентов обычно содержат имя команды, так что в данном примере мы можем говорить о командах «SELECT», «UPDATE» и «INSERT». Но например, команда UPDATE
требует, чтобы также в определённом положении всегда стоял компонент SET
, а INSERT
в приведённом виде требует наличия компонента VALUES
. Точные синтаксические правила для каждой команды описаны в Части VI.
4.1.1. Идентификаторы и ключевые слова
Показанные выше команды содержали компоненты SELECT
, UPDATE
и VALUES
, которые являются примерами ключевых слов, то есть слов, имеющих фиксированное значение в языке SQL. Компоненты MY_TABLE
и A
являются примерами идентификаторов. Они идентифицируют имена таблиц, столбцов или других объектов баз данных, в зависимости от того, где они используются. Поэтому иногда их называют просто «именами». Ключевые слова и идентификаторы имеют одинаковую лексическую структуру, то есть, не зная языка, нельзя определить, является ли некоторый компонент ключевым словом или идентификатором. Полный список ключевых слов приведён в Приложении C.
Идентификаторы и ключевые слова SQL должны начинаться с буквы (a
-z
, хотя допускаются также не латинские буквы и буквы с диакритическими знаками) или подчёркивания (_
). Последующими символами в идентификаторе или ключевом слове могут быть буквы, цифры (0
-9
), знаки доллара ($
) или подчёркивания. Заметьте, что строго следуя букве стандарта SQL, знаки доллара нельзя использовать в идентификаторах, так что их использование вредит переносимости приложений. В стандарте SQL гарантированно не будет ключевых слов с цифрами и начинающихся или заканчивающихся подчёркиванием, так что идентификаторы такого вида защищены от возможных конфликтов с будущими расширениями стандарта.
Система выделяет для идентификатора не более NAMEDATALEN-1 байт, а более длинные имена усекаются. По умолчанию NAMEDATALEN
равно 64, так что максимальная длина идентификатора равна 63 байтам.
Ключевые слова и идентификаторы без кавычек воспринимаются системой без учёта регистра. Таким образом:
UPDATE MY_TABLE SET A = 5;
равносильно записи:
uPDaTE my_TabLE SeT a = 5;
Часто используется неформальное соглашение записывать ключевые слова заглавными буквами, а имена строчными, например:
UPDATE my_table SET a = 5;
Есть и другой тип идентификаторов: отделённые идентификаторы или идентификаторы в кавычках. Они образуются при заключении обычного набора символов в двойные кавычки ("
). Такие идентификаторы всегда будут считаться идентификаторами, но не ключевыми словами. Так "select"
можно использовать для обозначения столбца или таблицы «select», тогда как select
без кавычек будет воспринят как ключевое слово и приведёт к ошибке разбора команды в месте, где ожидается имя таблицы или столбца. Тот же пример можно переписать с идентификаторами в кавычках следующим образом:
UPDATE "my_table" SET "a" = 5;
Идентификаторы в кавычках могут содержать любые символы, за исключением символа с кодом 0. (Чтобы включить в такой идентификатор кавычки, продублируйте их.) Это позволяет создавать таблицы и столбцы с именами, которые иначе были бы невозможны, например, с пробелами или амперсандами. Ограничение длины при этом сохраняется.
Идентификатор, заключённый в кавычки, становится зависимым от регистра, тогда как идентификаторы без кавычек всегда переводятся в нижний регистр. Например, идентификаторы FOO
, foo
и "foo"
считаются одинаковыми в Postgres Pro, но "Foo"
и "FOO"
отличны друг от друга и от предыдущих трёх. (Приведение имён без кавычек к нижнему регистру, как это делает Postgres Pro, несовместимо со стандартом SQL, который говорит о том, что имена должны приводиться к верхнему регистру. То есть, согласно стандарту foo
должно быть эквивалентно "FOO"
, а не "foo"
. Поэтому при создании переносимых приложений рекомендуется либо всегда заключать определённое имя в кавычки, либо не заключать никогда.)
Ещё один вариант идентификаторов в кавычках позволяет использовать символы Unicode по их кодам. Такой идентификатор начинается с U&
(строчная или заглавная U и амперсанд), а затем сразу без пробелов идёт двойная кавычка, например U&"foo"
. (Заметьте, что при этом возникает неоднозначность с оператором &
. Чтобы её избежать, окружайте этот оператор пробелами.) Затем в кавычках можно записывать символы Unicode двумя способами: обратная косая черта, а за ней код символа из четырёх шестнадцатеричных цифр, либо обратная косая черта, знак плюс, а затем код из шести шестнадцатеричных цифр. Например, идентификатор "data"
можно записать так:
U&"d\0061t\+000061"
В следующем менее тривиальном примере закодировано русское слово «слон», записанное кириллицей:
U&"\0441\043B\043E\043D"
Если вы хотите использовать не обратную косую черту, а другой спецсимвол, его можно указать, добавив UESCAPE
после строки, например:
U&"d!0061t!+000061" UESCAPE '!'
В качестве спецсимвола можно выбрать любой символ, кроме шестнадцатеричной цифры, знака плюс, апострофа, кавычки или пробельного символа. Заметьте, что спецсимвол заключается не в двойные кавычки, а в апострофы, после UESCAPE
.
Чтобы сделать спецсимволом знак апострофа, напишите его дважды.
Записывать суррогатные пары UTF-16 и таким образом составлять символы с кодами больше чем U+FFFF можно либо в четырёх-, либо в шестизначной форме, хотя наличие шестизначной формы технически делает это ненужным. (Суррогатные пары не сохраняются непосредственно, а объединяются в один символ, который затем кодируется в UTF-8.)
Когда кодировка сервера — не UTF-8, символ с кодом, указанным этой спецпоследовательностью, преобразуется в фактическую кодировку сервера; если такое преобразование невозможно, выдаётся ошибка.
4.1.2. Константы
В Postgres Pro есть три типа констант подразумеваемых типов: строки, битовые строки и числа. Константы можно также записывать, указывая типы явно, что позволяет представить их более точно и обработать более эффективно. Эти варианты рассматриваются в следующих подразделах.
4.1.2.1. Строковые константы
Строковая константа в SQL — это обычная последовательность символов, заключённая в апострофы ('
), например: 'Это строка'
. Чтобы включить апостроф в строку, напишите в ней два апострофа рядом, например: 'Жанна д''Арк'
. Заметьте, это не то же самое, что двойная кавычка ("
).
Две строковые константы, разделённые пробельными символами и минимум одним переводом строки, объединяются в одну и обрабатываются, как если бы строка была записана в одной константе. Например:
SELECT 'foo' 'bar';
эквивалентно:
SELECT 'foobar';
но эта запись:
SELECT 'foo' 'bar';
считается синтаксической ошибкой. (Это несколько странное поведение определено в стандарте SQL, Postgres Pro просто следует ему.)
4.1.2.2. Строковые константы со спецпоследовательностями в стиле C
Postgres Pro также принимает «спецпоследовательности», что является расширением стандарта SQL. Строка со спецпоследовательностями начинается с буквы E
(заглавной или строчной), стоящей непосредственно перед апострофом, например: E'foo'
. (Когда константа со спецпоследовательностью разбивается на несколько строк, букву E
нужно поставить только перед первым открывающим апострофом.) Внутри таких строк символ обратной косой черты (\
) начинает C-подобные спецпоследовательности, в которых сочетание обратной косой черты со следующим символом(ами) даёт определённое байтовое значение, как показано в Таблице 4.1.
Таблица 4.1. Спецпоследовательности
Спецпоследовательность | Интерпретация |
---|---|
\b | символ «забой» |
\f | подача формы |
\n | новая строка |
\r | возврат каретки |
\t | табуляция |
\ , \ , \ (o = 0–7) | восьмеричное значение байта |
\x , \x (h = 0–9, A–F) | шестнадцатеричное значение байта |
\u , \U (x = 0–9, A–F) | 16- или 32-битный шестнадцатеричный код символа Unicode |
Любой другой символ, идущий после обратной косой черты, воспринимается буквально. Таким образом, чтобы включить в строку обратную косую черту, нужно написать две косых черты (\\
). Так же можно включить в строку апостроф, написав \'
, в дополнение к обычному способу ''
.
Вы должны позаботиться, чтобы байтовые последовательности, которые вы создаёте таким образом, особенно в восьмеричной и шестнадцатеричной записи, образовывали допустимые символы в серверной кодировке. Также может быть полезно использовать спецпоследовательности Unicode или альтернативную запись, описанную в Подразделе 4.1.2.3; в этом случае сервер будет проверять, возможно ли преобразовать указанный символ.
Внимание
Если параметр конфигурации standard_conforming_strings имеет значение off
, Postgres Pro распознаёт обратную косую черту как спецсимвол и в обычных строках, и в строках со спецпоследовательностями. Однако в версии PostgreSQL 9.1 по умолчанию принято значение on
, и в этом случае обратная косая черта распознаётся только в спецстроках. Это поведение больше соответствует стандарту, хотя может нарушить работу приложений, рассчитанных на предыдущий режим, когда обратная косая черта распознавалась везде. В качестве временного решения вы можете изменить этот параметр на off
, но лучше уйти от такой практики. Если вам нужно, чтобы обратная косая черта представляла специальный символ, задайте строковую константу с E
.
В дополнение к standard_conforming_strings
поведением обратной косой черты в строковых константах управляют параметры escape_string_warning и backslash_quote.
Строковая константа не может включать символ с кодом 0.
4.1.2.3. Строковые константы со спецпоследовательностями Unicode
Postgres Pro также поддерживает ещё один вариант спецпоследовательностей, позволяющий включать в строки символы Unicode по их кодам. Строковая константа со спецпоследовательностями Unicode начинается с U&
(строчная или заглавная U и амперсанд), а затем сразу без пробелов идёт апостроф, например U&'foo'
. (Заметьте, что при этом возникает неоднозначность с оператором &
. Чтобы её избежать, окружайте этот оператор пробелами.) Затем в апострофах можно записывать символы Unicode двумя способами: обратная косая черта, а за ней код символа из четырёх шестнадцатеричных цифр, либо обратная косая черта, знак плюс, а затем код из шести шестнадцатеричных цифр. Например, строку 'data'
можно записать так:
U&'d\0061t\+000061'
В следующем менее тривиальном примере закодировано русское слово «слон», записанное кириллицей:
U&'\0441\043B\043E\043D'
Если вы хотите использовать не обратную косую черту, а другой спецсимвол, его можно указать, добавив UESCAPE
после строки, например:
U&'d!0061t!+000061' UESCAPE '!'
В качестве спецсимвола можно выбрать любой символ, кроме шестнадцатеричной цифры, знака плюс, апострофа, кавычки или пробельного символа.
Чтобы включить спецсимвол в строку буквально, напишите его дважды.
Записывать суррогатные пары UTF-16 и таким образом составлять символы с кодами больше чем U+FFFF можно либо в четырёх-, либо в шестизначной форме, хотя наличие шестизначной формы технически делает это ненужным. (Суррогатные пары не сохраняются непосредственно, а объединяются в один символ, который затем кодируется в UTF-8.)
Когда кодировка сервера — не UTF-8, символ с кодом, указанным этой спецпоследовательностью, преобразуется в фактическую кодировку сервера; если такое преобразование невозможно, выдаётся ошибка.
Также заметьте, что спецпоследовательности Unicode в строковых константах работают, только когда параметр конфигурации standard_conforming_strings равен on
. Это объясняется тем, что иначе клиентские программы, проверяющие SQL-операторы, можно будет ввести в заблуждение и эксплуатировать это как уязвимость, например, для SQL-инъекций. Если этот параметр имеет значение off
, эти спецпоследовательности будут вызывать ошибку.
4.1.2.4. Строковые константы, заключённые в доллары
Хотя стандартный синтаксис для строковых констант обычно достаточно удобен, он может плохо читаться, когда строка содержит много апострофов, так как каждый такой символ приходится дублировать. Чтобы и в таких случаях запросы оставались читаемыми, Postgres Pro предлагает ещё один способ записи строковых констант — «заключение строк в доллары». Строковая константа, заключённая в доллары, начинается со знака доллара ($
), необязательного «тега» из нескольких символов и ещё одного знака доллара, затем содержит обычную последовательность символов, составляющую строку, и оканчивается знаком доллара, тем же тегом и замыкающим знаком доллара. Например, строку «Жанна д'Арк» можно записать в долларах двумя способами:
$$Жанна д'Арк$$ $SomeTag$Жанна д'Арк$SomeTag$
Заметьте, что внутри такой строки апострофы не нужно записывать особым образом. На самом деле, в строке, заключённой в доллары, все символы можно записывать в чистом виде: содержимое строки всегда записывается буквально. Ни обратная косая черта, ни даже знак доллара не являются спецсимволами, если только они не образуют последовательность, соответствующую открывающему тегу.
Строковые константы в долларах можно вкладывать друг в друга, выбирая на разных уровнях вложенности разные теги. Чаще всего это используется при написании определений функций. Например:
$function$ BEGIN RETURN ($1 ~ $q$[\t\r\n\v\\]$q$); END; $function$
Здесь последовательность $q$[\t\r\n\v\\]$q$
представляет в долларах текстовую строку [\t\r\n\v\\]
, которая будет обработана, когда Postgres Pro будет выполнять эту функцию. Но так как эта последовательность не соответствует внешнему тегу в долларах ($function$
), с точки зрения внешней строки это просто обычные символы внутри константы.
Тег строки в долларах, если он присутствует, должен соответствовать правилам, определённым для идентификаторов без кавычек, и к тому же не должен содержать знак доллара. Теги регистрозависимы, так что $tag$String content$tag$
— правильная строка, а $TAG$String content$tag$
— нет.
Строка в долларах, следующая за ключевым словом или идентификатором, должна отделяться от него пробельными символами, иначе доллар будет считаться продолжением предыдущего идентификатора.
Заключение строк в доллары не является частью стандарта SQL, но часто это более удобный способ записывать сложные строки, чем стандартный вариант с апострофами. Он особенно полезен, когда нужно представить строковую константу внутри другой строки, что часто требуется в определениях процедурных функций. Ограничившись только апострофами, каждую обратную косую черту в приведённом примере пришлось бы записывать четырьмя такими символами, которые бы затем уменьшились до двух при разборе внешней строки, и наконец до одного при обработке внутренней строки во время выполнения функции.
4.1.2.5. Битовые строковые константы
Битовые строковые константы похожи на обычные с дополнительной буквой B
(заглавной или строчной), добавленной непосредственно перед открывающим апострофом (без промежуточных пробелов), например: B'1001'
. В битовых строковых константах допускаются лишь символы 0
и 1
.
Битовые константы могут быть записаны и по-другому, в шестнадцатеричном виде, с начальной буквой X
(заглавной или строчной), например: X'1FF'
. Такая запись эквивалентна двоичной, только четыре двоичных цифры заменяются одной шестнадцатеричной.
Обе формы записи допускают перенос строк так же, как и обычные строковые константы. Однако заключать в доллары битовые строки нельзя.
4.1.2.6. Числовые константы
Числовые константы могут быть заданы в следующем общем виде:
цифры
цифры
.[цифры
][e[+-]цифры
] [цифры
].цифры
[e[+-]цифры
]цифры
e[+-]цифры
где цифры
— это одна или несколько десятичных цифр (0..9). До или после десятичной точки (при её наличии) должна быть минимум одна цифра. Как минимум одна цифра должна следовать за обозначением экспоненты (e
), если оно присутствует. В числовой константе не может быть пробелов или других символов. Заметьте, что любой знак минус или плюс в начале строки не считается частью числа; это оператор, применённый к константе.
Несколько примеров допустимых числовых констант:
42
3.5
4.
.001
5e2
1.925e-3
Числовая константа, не содержащая точки и экспоненты, изначально рассматривается как константа типа integer
, если её значение умещается в 32-битный тип integer
; затем как константа типа bigint
, если её значение умещается в 64-битный bigint
; в противном случае она принимает тип numeric
. Константы, содержащие десятичные точки и/или экспоненты, всегда считаются константами типа numeric
.
Изначально назначенный тип данных числовой константы это только отправная точка для алгоритмов определения типа. В большинстве случаев константа будет автоматически приведена к наиболее подходящему типу для данного контекста. При необходимости вы можете принудительно интерпретировать числовое значение как значение определённого типа, приведя его тип к нужному. Например, вы можете сделать, чтобы числовое значение рассматривалось как имеющее тип real
(float4
), написав:
REAL '1.23' -- строковый стиль 1.23::REAL -- стиль Postgres Pro (исторический)
На самом деле это только частные случаи синтаксиса приведения типов, который будет рассматриваться далее.
4.1.2.7. Константы других типов
Константу обычного типа можно ввести одним из следующих способов:
type
'string
' 'string
'::type
CAST ( 'string
' AStype
)
Текст строковой константы передаётся процедуре преобразования ввода для типа, обозначенного здесь type
. Результатом становится константа указанного типа. Явное приведение типа можно опустить, если нужный тип константы определяется однозначно (например, когда она присваивается непосредственно столбцу таблицы), так как в этом случае приведение происходит автоматически.
Строковую константу можно записать, используя как обычный синтаксис SQL, так и формат с долларами.
Также можно записать приведение типов, используя синтаксис функций:
typename
( 'string
' )
но это работает не для всех имён типов; подробнее об этом написано в Подразделе 4.2.9.
Конструкцию ::
, CAST()
и синтаксис вызова функции можно также использовать для преобразования типов обычных выражений во время выполнения, как описано в Подразделе 4.2.9. Во избежание синтаксической неопределённости, запись
можно использовать только для указания типа простой текстовой константы. Ещё одно ограничение записи тип
'строка
'
: она не работает для массивов; для таких констант следует использовать тип
'строка
'::
или CAST()
.
Синтаксис CAST()
соответствует SQL, а запись
является обобщением стандарта: в SQL такой синтаксис поддерживает только некоторые типы данных, но Postgres Pro позволяет использовать его для всех. Синтаксис с type
'string
'::
имеет исторические корни в Postgres Pro, как и запись в виде вызова функции.
4.1.3. Операторы
Имя оператора образует последовательность не более чем NAMEDATALEN
-1 (по умолчанию 63) символов из следующего списка:
+ - * / < > = ~ ! @ # % ^ & | ` ?
Однако для имён операторов есть ещё несколько ограничений:
Сочетания символов
--
и/*
не могут присутствовать в имени оператора, так как они будут обозначать начало комментария.Многосимвольное имя оператора не может заканчиваться знаком
+
или-
, если только оно не содержит также один из этих символов:
~ ! @ # % ^ & | ` ?Например,
@-
— допустимое имя оператора, а*-
— нет. Благодаря этому ограничению, Postgres Pro может разбирать корректные SQL-запросы без пробелов между компонентами.
Записывая нестандартные SQL-операторы, обычно нужно отделять имена соседних операторов пробелами для однозначности. Например, если вы определили префиксный оператор с именем @
, вы не можете написать X*@Y
, а должны написать X* @Y
, чтобы Postgres Pro однозначно прочитал это как два оператора, а не один.
4.1.4. Специальные знаки
Некоторые не алфавитно-цифровые символы имеют специальное значение, но при этом не являются операторами. Подробнее их использование будет рассмотрено при описании соответствующего элемента синтаксиса. Здесь они упоминаются только для сведения и обобщения их предназначения.
Знак доллара (
$
), предваряющий число, используется для представления позиционного параметра в теле определения функции или подготовленного оператора. В других контекстах знак доллара может быть частью идентификатора или строковой константы, заключённой в доллары.Круглые скобки (
()
) имеют обычное значение и применяются для группировки выражений и повышения приоритета операций. В некоторых случаях скобки — это необходимая часть синтаксиса определённых SQL-команд.Квадратные скобки (
[]
) применяются для выделения элементов массива. Подробнее массивы рассматриваются в Разделе 8.15.Запятые (
,
) используются в некоторых синтаксических конструкциях для разделения элементов списка.Точка с запятой (
;
) завершает команду SQL. Она не может находиться нигде внутри команды, за исключением строковых констант или идентификаторов в кавычках.Двоеточие (
:
) применяется для выборки «срезов» массивов (см. Раздел 8.15.) В некоторых диалектах SQL (например, в Embedded SQL) двоеточие может быть префиксом в имени переменной.Звёздочка (
*
) используется в некоторых контекстах как обозначение всех полей строки или составного значения. Она также имеет специальное значение, когда используется как аргумент некоторых агрегатных функций, а именно функций, которым не нужны явные параметры.Точка (
.
) используется в числовых константах, а также для отделения имён схемы, таблицы и столбца.
4.1.5. Комментарии
Комментарий — это последовательность символов, которая начинается с двух минусов и продолжается до конца строки, например:
-- Это стандартный комментарий SQL
Кроме этого, блочные комментарии можно записывать в стиле C:
/* многострочный комментарий * с вложенностью: /* вложенный блок комментария */ */
где комментарий начинается с /*
и продолжается до соответствующего вхождения */
. Блочные комментарии можно вкладывать друг в друга, как разрешено по стандарту SQL (но не разрешено в C), так что вы можете комментировать большие блоки кода, которые при этом уже могут содержать блоки комментариев.
Комментарий удаляется из входного потока в начале синтаксического анализа и фактически заменяется пробелом.
4.1.6. Приоритеты операторов
В Таблице 4.2 показаны приоритеты и очерёдность операторов, действующие в Postgres Pro. Большинство операторов имеют одинаковый приоритет и вычисляются слева направо. Приоритет и очерёдность операторов жёстко фиксированы в синтаксическом анализаторе. Если вы хотите, чтобы выражение с несколькими операторами разбиралось не в том порядке, который диктуют эти приоритеты, добавьте скобки.
Таблица 4.2. Приоритет операторов (от большего к меньшему)
Оператор/элемент | Очерёдность | Описание |
---|---|---|
. | слева-направо | разделитель имён таблицы и столбца |
:: | слева-направо | приведение типов в стиле Postgres Pro |
[ ] | слева-направо | выбор элемента массива |
+ - | справа-налево | унарный плюс, унарный минус |
COLLATE | слева-направо | выбор правила сортировки |
AT | слева-направо | AT TIME ZONE |
^ | слева-направо | возведение в степень |
* / % | слева-направо | умножение, деление, остаток от деления |
+ - | слева-направо | сложение, вычитание |
(любой другой оператор) | слева-направо | все другие встроенные и пользовательские операторы |
BETWEEN IN LIKE ILIKE SIMILAR | проверка диапазона, проверка членства, сравнение строк | |
< > = <= >= <> | операторы сравнения | |
IS ISNULL NOTNULL | IS TRUE , IS FALSE , IS NULL , IS DISTINCT FROM и т. д. | |
NOT | справа-налево | логическое отрицание |
AND | слева-направо | логическая конъюнкция |
OR | слева-направо | логическая дизъюнкция |
Заметьте, что правила приоритета операторов также применяются к операторам, определённым пользователем с теми же именами, что и вышеперечисленные встроенные операторы. Например, если вы определите оператор «+» для некоторого нестандартного типа данных, он будет иметь тот же приоритет, что и встроенный оператор «+», независимо от того, что он у вас делает.
Когда в конструкции OPERATOR
используется имя оператора со схемой, например так:
SELECT 3 OPERATOR(pg_catalog.+) 4;
тогда OPERATOR
имеет приоритет по умолчанию, соответствующий в Таблице 4.2 строке «любой другой оператор». Это не зависит от того, какие именно операторы находятся в конструкции OPERATOR()
.
Примечание
В PostgreSQL до версии 9.5 действовали немного другие правила приоритета операторов. В частности, операторы <=
, >=
и <>
обрабатывались по общему правилу; проверки IS
имели более высокий приоритет; а NOT BETWEEN
и связанные конструкции работали несогласованно — в некоторых случаях приоритетнее оказывался оператор NOT
, а не BETWEEN
. Эти правила были изменены для лучшего соответствия стандарту SQL и для уменьшения путаницы из-за несогласованной обработки логически равнозначных конструкций. В большинстве случаев эти изменения никак не проявятся, либо могут привести к ошибкам типа «нет такого оператора», которые можно разрешить, добавив скобки. Однако возможны особые случаи, когда запрос будет разобран без ошибки, но его поведение может измениться.