Chapter 4. Ситаксис SQL

Table of Contents
4.1. Лексическая структура
4.1.1. Идентификаторы и ключевые слова
4.1.2. Константы
4.1.3. Оперторы
4.1.4. Специальные символы
4.1.5. Комментарии
4.1.6. Лексические приоритеты
4.2. Value Expressions
4.2.1. Column References
4.2.2. Positional Parameters
4.2.3. Subscripts
4.2.4. Field Selection
4.2.5. Operator Invocations
4.2.6. Function Calls
4.2.7. Aggregate Expressions
4.2.8. Type Casts
4.2.9. Scalar Subqueries
4.2.10. Array Constructors
4.2.11. Row Constructors
4.2.12. Expression Evaluation Rules

Данная глава описывает синтакс SQL. Она является основой для понимания следующих глав, в которых будет подробно описываться какие команды SQL применяются для описания и изменения данных.

Мы также советуем пользователям которые уже знакомы с SQL, внимательно прочитать эту главу, потому что есть некоторые правила и концепты, которые реализованы неполностью или которые являются специфическими для PostgreSQL.

4.1. Лексическая структура

Входной поток SQL состоит из последовательности команд. А команда в свою очередь из последовательности токенов и завершается точкой с запятой (";"). Конец входного потока также завершает команду. Какие токены являются правильными а какие нет, зависит от синтаксиса отдельной команды.

Токен может быть ключевым словом, идентификтором, заключенным в кавычки идентификтором, литералом (или константой) или специальным символом. Токены обычно разделяются пробелами (табуляциями, символами новой строки), но это не является необходимым, если нет двусмысленности (которая обычно возникает только, если специальный символ примыкает к каким-либо другим типам токенов).

В дополнение, в потоке ввода SQL могут встречаться комментарии. Они не имеют токенов, они просто являются эквивалентом пробелов.

Например, следующие строки в потоке ввода SQL являются (синтаксически) правильными:

SELECT * FROM MY_TABLE;
UPDATE MY_TABLE SET A = 5;
INSERT INTO MY_TABLE VALUES (3, 'hi there');

Эта последовательность из трёх команд, по одной в каждой строке (что необязательно; в одной строке может быть несколько команд, но при этом, и команда может быть разбита на несколько строк).

Синтаксис SQL не является очень строгим относительно токенов, идентифиуирующих команды, а также операндов и параметров. Первые несколько токенов обычно являются именем команды, как в примере, данном выше и мы будем говорить обычно о командах "SELECT", "UPDATE" и "INSERT". Но, к примеру, команда UPDATE всегда требует токен SET, который должен к тому же находится в определённой позиции, а определённый вариант команды INSERT также требует, чтобы токен VALUES находился в надлежащем месте. Точные правила синтаксиса для каждой команды описываются в Part VI.

4.1.1. Идентификаторы и ключевые слова

Такие токены как SELECT, UPDATE или VALUES в показанном выше примере, являются примерами ключевых слов, т.е. таких слов, которые имеют фиксированное значение в языке SQL. Токены MY_TABLE и A являются примерами идентификаторов Они идентифицируют имена таблиц или других объектов базы данных, в зависимости от команды в которой они используются. Таким образом, они иногда просто называются "именами" Ключевые слова и идентификаторы имеют такую же лексическую структуру и это означает, что нельзя заранее знать является ли токен идентификатором или ключевым словом в неизвестном языке. Полный список ключевых слов можно найти в Appendix C.

Идентификаторы SQL и ключевые слова должны начинаться с букв (a-z, а также с букв с диакритическими отметками и нелатинских букв) или символа подчёркивания (_). Остальные символы в идентификаторе или ключевом слове могут быть буквами, подчёркиваниями, цифрами (0-9) или знаками доллара ($). Заметим, что знак доллара в идентификаторах, не разрешается по стандарту SQL, так что его использование может сделать приложения менее переносимыми. Стандарт SQL не будет определять никаких ключевых слов, содержащих цифры или начинающихся или заканчивающихся подчёркиванием, так что идентификаторы в таком виде являются наиболее безопасными с точки зрения их конфликтов с будущими расширениями этого стандарта.

Длина идентфикатора должна быть не более NAMEDATALEN-1 символов; в командах могуть использоваться и более длинные имена, но они будут урезаны. По умолчанию значение NAMEDATALEN составляет 64, так что максимальная длина идентификатора может быть 63 символа. Если это ограничение вызывает проблемы, вы можете изменить константу NAMEDATALEN в файле src/include/postgres_ext.h.

Идентификаторы и ключевые слова являются нечувствительными к регистру букв. Таким образом

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;

Заключённые в кавычки идентификаторы могут содержать любые символы, кроме самого символа двойной кавычки. (Чтобы включить символ двойной кавычки нужно использовать две двойные кавычки). Это позволяет конструировать такие имена таблиц или колонок, которые в других случаях были бы невозможны, например содержащие пробелы или амперсанды. Но ограничение на длину идентификатора остаётся в силе.

Заключение идентификатора в кавычки делает его чувствительным к регистру букв. Например, идентификаторы FOO, foo и "foo" считаются PostgreSQL одинаковыми, а "Foo" и "FOO" отличаются от предыдущих трёх и друг от друга. (Конвертация незаключённых в кавычки имен в нижний регистр в PostgreSQL является несовместимостью со стандартном SQL, который говорит, что незаключённые в кавычки имена должны конвертироваться в верхний регистр. Так, в соответствии со стандартном, имя foo должно быть эквивалентно "FOO", а не "foo". Если вы хотите писать переносимые приложения, вы должны позаботится о том, чтобы либо всегда использовать кавычки, либо никогда не использовать их.

4.1.2. Константы

В PostgreSQL существует три вида неявно-заданных констант: строки, битовые строки и числа. Константы могут также быть заданы с явным указанием типа, что может позволить более аккуратно представить значение константы и более эффективно ей управлять. Эти альтернативы описываются в следующих подсекциях.

4.1.2.1. Строковые константы

Строковая константа в SQL - это произвольная последовательность символов, заключённых в одинарные кавычки ('), например, 'This is a string'. Совместимый со стандартом способ написания символа одинарной кавычки внутри строковой константы состоит в написании двойной одинарной кавычки, т.е. 'Dianne''s horse'. PostgreSQL также позволяет заэкранировать одинарную кавычку с помощью обратной косой черты (\), так что для данного выше примера, та же самая строка может быть записана как 'Dianne\'s horse'.

Другое расширение PostgreSQL состоит в том, что доступны следующие экранирования с обратной косой чертой в стиле языка C: \b - это символ backspace, \f - это прогон формы, \n - это символ новой строки, \r - это возрат каретки, \t - это табуляция и \xxx где xxx является восьмиричным числом - это байт, соответствующий коду этого числа. (Это может пригодится, если последовательность байт, которую вы создаёте является строкой правильных символов в кодировке сервера). Любые другие символы, которые следуют за обратной косой чертой считаются простыми символами. Чтобы включить символ обратной косой черты в строковую константу, введите два символа обатная косая черта.

Символ с нулевым кодом нельзя указывать в строковой константе.

Две строковые константы, которые разделены только пустым пространством с как минимум одним переводом строки сливаются и будут считаться одной строковой константой. Например:

SELECT 'foo'
'bar';

эквивалентно

SELECT 'foobar';

но

SELECT 'foo'      'bar';

является неправильным синтаксисом. (Такое странное поведение задаётся в SQL; PostgreSQL следует стандарту).

4.1.2.2. Dollar-Quoted String Constants

While the standard syntax for specifying string constants is usually convenient, it can be difficult to understand when the desired string contains many single quotes or backslashes, since each of those must be doubled. To allow more readable queries in such situations, PostgreSQL provides another way, called "dollar quoting", to write string constants. A dollar-quoted string constant consists of a dollar sign ($), an optional "tag" of zero or more characters, another dollar sign, an arbitrary sequence of characters that makes up the string content, a dollar sign, the same tag that began this dollar quote, and a dollar sign. For example, here are two different ways to specify the string "Dianne's horse" using dollar quoting:

$$Dianne's horse$$
$SomeTag$Dianne's horse$SomeTag$

Notice that inside the dollar-quoted string, single quotes can be used without needing to be escaped. Indeed, no characters inside a dollar-quoted string are ever escaped: the string content is always written literally. Backslashes are not special, and neither are dollar signs, unless they are part of a sequence matching the opening tag.

It is possible to nest dollar-quoted string constants by choosing different tags at each nesting level. This is most commonly used in writing function definitions. For example:

$function$
BEGIN
    RETURN ($1 ~ $q$[\t\r\n\v\\]$q$);
END;
$function$

Here, the sequence $q$[\t\r\n\v\\]$q$ represents a dollar-quoted literal string [\t\r\n\v\\], which will be recognized when the function body is executed by PostgreSQL. But since the sequence does not match the outer dollar quoting delimiter $function$, it is just some more characters within the constant so far as the outer string is concerned.

The tag, if any, of a dollar-quoted string follows the same rules as an unquoted identifier, except that it cannot contain a dollar sign. Tags are case sensitive, so $tag$String content$tag$ is correct, but $TAG$String content$tag$ is not.

A dollar-quoted string that follows a keyword or identifier must be separated from it by whitespace; otherwise the dollar quoting delimiter would be taken as part of the preceding identifier.

Dollar quoting is not part of the SQL standard, but it is often a more convenient way to write complicated string literals than the standard-compliant single quote syntax. It is particularly useful when representing string constants inside other constants, as is often needed in procedural function definitions. With single-quote syntax, each backslash in the above example would have to be written as four backslashes, which would be reduced to two backslashes in parsing the original string constant, and then to one when the inner string constant is re-parsed during function execution.

4.1.2.3. Битово-строковые константы

Битово-строковые константы выглядят как обычные строковые константы с символом B (в нижнем или верхнем регистре) который идёт сразу перед открываюшей кавычкой (без пробелов), например, B'1001'. В битово-строковой константе допускаются только символы 0 и 1.

Кроме-того, битово-строковые константы могут быть заданы в шестнадцатеричной нотации, используя лидирующий символ X (в верхнем или нижнем регистре), например, X'1FF'. Такая нотация эквивалентна битово-строковой константе с четырмя двоичными разрядами для каждого шестнадцатеричного разряда.

Обе формы битово-строковые констант могут занимать несколько строк таким же образом как и обычные строковые константы. Экранирование символом доллара не может быть использовано в битово-строковых константах.

4.1.2.4. Числовые константы

Числовые константы принимаются в трёх общих формах:

цифры
цифры.[цифры][e[+-]цифры]
[цифры].цифры[e[+-]цифры]
цифрыe[+-]цифры

где цифры - это одна или более десятичных цифр (от 0 до 9). По крайней мере одна цифра должна следовать до или после десятичной точки, если она используется. По крайней мере одна цифра должна следовать за символом экспоненты (e), если этот символ есть. В константе не должно быть пробелов или других символов. Заметим, что все знаки плюс или минус вначале константы не являются фактической частью константы; эти знаки являются оператором, который применяется к константе.

Вот несколько примеров правильных числовых констант:

42
3.5
4.
.001
5e2
1.925e-3

Числовая константа, которая не имеет ни десятичной точки ни символа экспоненты, считается имеющей тип integer (целое), если её значение умещается в тип integer (32 бита); в противном случае считается, что константа имеет тип bigint (большое целое), если её значение умещается в тип bigint (64 бита); в противном случае считается, что константа имеет тип numeric. Константы, которые содержат десятичную точку и/или символ экпоненты всегда считаются имеющими тип numeric.

Первоначальное назначение типа данных числовой константы просто запускает алгоритмы определения типа. В большинстве случаев константа будет автоматически приведена к наиболее соответствующему ей типу, в зависимости от контекста. Когда это необходимо, вы можете заставить числовое значение принудительно интерпретироваться как специальный тип данных, через его указание. Например, вы можете принудительно заставить числовое значение интерпретироваться как тип real (float4), написав

REAL '1.23'  -- string style
1.23::REAL   -- PostgreSQL (historical) style

Фактически существует несколько специальных случаев нотаций приведения типов, которые обсуждаются далее.

4.1.2.5. Константы и другие типы

Константу произвольного типа можно ввести с помощью одной из следующих нотаций:

type 'string'
'string'::type
CAST ( 'string' AS type )

Тест строковой константы передаётся на вход подпрограммы конвертации для типа type. Результатом является константа, указанного типа. Явное указание типа может быть опущено, если нет неоднозначности в понимании того типа, которому должна соответствовать константа (например, когда она напрямую назначается для колонки таблицы), в этом случае она будет автоматически преобразована к нужному типу.

Строковая константа может быть написана или через обычную SQL нотацию или через экранирование знаком доллара.

Также возможно задать преобразование типа с помощью синтаксиса в стиле функции:

имя типа ( 'string' )

но таким способом могут быть использованы не все имена типов; подробности см. в Section 4.2.8 for details.

::, CAST() и синтаксис в стиле функции могут также быть использованы для задания преобразования типов произвольных выражений в момент их вычисления, как описывается в Section 4.2.8. Но форма тип 'строка' может быть использована только для задания типа литеральной константы. Другое ограничение на тип 'строка' состоит в том, что такая конструкция не работает для типов массивов; используйте :: или CAST() чтобы задать тип массив констант.

4.1.3. Оперторы

Имя оператора - это последовательность из NAMEDATALEN-1 символов (по умолчанию 63) из следующего списка:

+ - * / < > = ~ ! @ # % ^ & | ` ?

Для имён операторов существует несколько ограничений, однако:

  • -- и /* не могут быть в имени оператора, так как они будут восприняты как начало комментария.

  • Имя оператора, состоящее из нескольких символов не может заканчиваться на + или -, если только это имя также не содержит один из следующих символов:

    ~ ! @ # % ^ & | ` ?

    Например, @- является разрешённым именем оператора, а *- - нет. Это ограничение позволяет PostgreSQL производить разбор SQL запросов не требуя обязательного наличия пробелов между токенами.

При работе с именами операторов, которые не соответствуют стандарту SQL, вам обычно будет нужно разделять оперторы пробелами, чтобы избежать неоднозначности. Например, если вы задали в левой части оператор @, вы не можете писать X*@Y; вы должны писать X* @Y, чтобы иметь уверенность, что PostgreSQL прочтёт это выражение как два имени оператора, а не одно.

4.1.4. Специальные символы

Некоторые символы, которые не являются ни цифрами ни буквами, имеют специальное значение, которое зависит от оператора. Подробности использования этих символов можно найти в описании соответствующих синтаксических элементов. Данная секция только говорит о наличии таких символов и суммирует их предназначение.

  • Знак доллара ($) следующий за цифрами используется для представления позиционного параметра в теле описания функции или подготовляемого оператора. В других контекстах знак доллара может быть частью идентификатора или экранированной знаком доллара строковой константы.

  • Круглые скобки (()) имеют свой собственный смысл в групповых выражениях и при задании приоритета выполнения операций. В других случаях круглые скобки требуются как часть фиксированного синтаксиса определённых команд SQL.

  • Квадратные скобки ([]) используются для выбора элементов массива. Подробности о массивах см. в Section 8.10.

  • Запятые (,) используются в некоторых ситаксических конструкциях для разделения элментов списка.

  • Точка с запятой (;) завершает команду SQL. Она не может быть использована внутри команды за исключением использования внутри строковой константы или заключённого в кавычки идентификатора.

  • Двоеточие (:) используется для выбора "слайсов" из массива. (См. Section 8.10.) В определённых диалектах SQL (таких как Embedded SQL), двоеточие используется как префикс имён переменных.

  • Звёздочка (*) используется в некоторых случаях для указания всех колонок в строке таблицы или составных значений. Она также имеет специальное значение, когда используется как аргумент агрегатной функции COUNT.

  • Точка (.) используется в числовых константах и для разделения имён схемы, таблицы и поля.

4.1.5. Комментарии

Комментарий - это произвольная последовательность символов, которая начинается с двойного символа дефиса и продолжается до конца строки, например:

-- This is a standard SQL comment

Кроме того, можно использовать блок комментария в стиле языка C:

/* multiline comment
 * with nesting: /* вложенный блок комментариев */
 */

где комментарий начинается с /* и продолжается пока не встретится */. Показанный выше вложенный блок комментариев соответствует стандарту SQL, но не стандарту языка C, таким образом один комментарий может содержать большие блоки кода, которые также могут содержать блоки комментариев.

Комментарии удаляются из входного потока перед анализом синтаксиса и просто заменяются на пробелы.

4.1.6. Лексические приоритеты

Table 4-1 показывает приоритет и ассоциативность операторов в PostgreSQL. Приортитет и ассоциативность операторов жёстко встроенны в анализатор. Это может создать поведение, которое не является интуитивно-понятным; например логические операторы < и > имеют приоритет, который отличается от приоритета операторов <= и >=. Также, когда вы будете использовать комбинации бинарных и унарных операторов, вам иногда придётся добавлять круглые скобки. Например:

SELECT 5 ! - 6;

будет понято как

SELECT 5 ! (- 6);

потому что анализатор не знает — пока не станет слишком позно — что ! задаётся как постфиксный оператор, а не как инфиксный. Чтобы получить в данном случае желаемое поведение, вы должны написать так:

SELECT (5 !) - 6;

Такова плата за расширяемость.

Table 4-1. Приоритет операторов (в порядке снижения)

Оператор/ЭлементАссоциативностьОписание
.слеваразделитель имени таблицы/колонки
::слеваприведение типа в стиле PostgreSQL
[ ]слевавыбор элемента массива
-справаунарный минус
^слевазнак степени
* / %слеваумножение, деление, целочисленное деление
+ -слевасложение, вычитание
IS IS TRUE, IS FALSE, IS UNKNOWN, IS NULL
ISNULL проверка на null
NOTNULL проверка на не null
(все другие)слевавсе другие стандартные и заданные пользователем операторы
IN список членов
BETWEEN вместимостьдиапазон вместимости
OVERLAPS перекрытие временного интервала
LIKE ILIKE SIMILAR совпадение строкового шаблона
< > меньше чем, больше чем
=справаприсваивание, назначение
NOTсправалогическое отрицание
ANDслевалогическое умножение
ORслевалогическое сложение

Заметим, что данные правила приоритетов операторов также применимы к оператором, определённым пользователем, которые имеют такие же имена как и встроенные операторы, описанные выше. Например, если вы определили оператор "+" для какого-либо своего типа данных, он будет иметь такой же приоритет как и встроенный оператор "+", не зависимо от того, что его создали вы.

Когда в синтаксисе OPERATOR используется имя оператора вместе с именем схемы, как в этом примере

SELECT 3 OPERATOR(pg_catalog.+) 4;

OPERATOR сконструированный оператор имеет по умолчанию приоритет указанный в Table 4-1 для оператора "все другие". Это истина не зависит от того какое имя оператора используется внутри OPERATOR().