Привет, Я DocuDroid!
Оценка ИИ поиска
Спасибо за оценку нашего ИИ поиска!
Мы будем признательны, если вы поделитесь своими впечатлениями, чтобы мы могли улучшить наш ИИ поиск для вас и других читателей.
GitHub

SELECT

Извлекает строки из таблицы или представления.

Синтаксис

[ WITH [ RECURSIVE ] <with_query> [, ...] ]
SELECT [ALL | DISTINCT [ON (<expression> [, ...])]]
  * | <expression> [[AS] <output_name>] [, ...]
  [FROM <from_item> [, ...]]
  [WHERE <condition>]
  [GROUP BY <grouping_element> [, ...]]
  [HAVING <condition> [, ...]]
  [WINDOW <window_name> AS (<window_definition>) [, ...] ]
  [{UNION | INTERSECT | EXCEPT} [ALL | DISTINCT] <select>]
  [ORDER BY <expression> [ASC | DESC | USING <operator>] [NULLS {FIRST | LAST}] [, ...]]
  [LIMIT {<count> | ALL}]
  [OFFSET <start> [ ROW | ROWS ] ]
  [FETCH { FIRST | NEXT } [ <count> ] { ROW | ROWS } ONLY]
  [FOR {UPDATE | NO KEY UPDATE | SHARE | KEY SHARE} [OF <table_name> [, ...]] [NOWAIT] [...]]

TABLE { [ ONLY ] <table_name> [ * ] | <with_query_name> }

где with_query:

<with_query_name> [( <column_name> [, ...] )] AS ( <select> | <values> | <insert> | <update> | <delete> )

где from_item может быть:

[ONLY] <table_name> [ * ] [ [ AS ] <alias> [ ( <column_alias> [, ...] ) ] ]
( <select> ) [ AS ] <alias> [( <column_alias> [, ...] ) ]
<with_query_name> [ [ AS ] <alias> [ ( <column_alias> [, ...] ) ] ]
<function_name> ( [ <argument> [, ...] ] )
            [ WITH ORDINALITY ] [ [ AS ] <alias> [ ( <column_alias> [, ...] ) ] ]
<function_name> ( [ <argument> [, ...] ] ) [ AS ] <alias> ( <column_definition> [, ...] )
<function_name> ( [ <argument> [, ...] ] ) AS ( <column_definition> [, ...] )
ROWS FROM ( <function_name> ( [ <argument> [, ...] ] ) [ AS ( <column_definition> [, ...] ) ] [, ...] )
            [ WITH ORDINALITY ] [ [ AS ] <alias> [ ( <column_alias> [, ...] ) ] ]
<from_item> [ NATURAL ] <join_type> <from_item>
          [ ON <join_condition> | USING ( <join_column> [, ...] ) ]

где grouping_element может быть:

()
<expression>
ROLLUP (<expression> [,...])
CUBE (<expression> [,...])
GROUPING SETS ((<grouping_element> [, ...]))

где window_definition:

[<existing_window_name>]
[PARTITION BY <expression> [, ...]]
[ORDER BY <expression> [ASC | DESC | USING <operator>] [NULLS {FIRST | LAST}] [, ...]]
[{ RANGE | ROWS} <frame_start> | {RANGE | ROWS} BETWEEN <frame_start> AND <frame_end>]

где frame_start и frame_end могут быть:

UNBOUNDED PRECEDING
<value> PRECEDING
CURRENT ROW
<value> FOLLOWING
UNBOUNDED FOLLOWING

Когда указано условие блокировки (выражение FOR), Global Deadlock Detector влияет на то, как блокируются строки таблицы. См. пункт 11 в разделе Описание и Выражения блокировки ниже в этом разделе.

Описание

SELECT получает строки из множества (возможно, пустого) таблиц. Общий порядок выполнения SELECT выглядит следующим образом:

  1. Выполняются все запросы в списке WITH. Фактически они формируют временные таблицы, на которые можно ссылаться в списке FROM.

  2. Вычисляются все элементы в списке FROM. Каждый элемент списка FROM представляет собой реальную или виртуальную таблицу. Если в списке FROM указано более одного элемента, они объединяются перекрестным соединением.

  3. Если указано условие WHERE, все строки, не удовлетворяющие этому условию, исключаются из результата.

  4. Если указано выражение GROUP BY или в запросе вызываются агрегатные функции, выходные данные разделяются по группам строк, соответствующим одному или нескольким значениям, затем вычисляются результаты агрегатных функций. Если присутствует выражение HAVING, оно исключает группы, не удовлетворяющие указанному условию.

  5. Вычисляются фактические выходные строки по указанным в SELECT выражениям для каждой выбранной строки или группы строк.

  6. SELECT DISTINCT исключает повторяющиеся строки из результата. SELECT DISTINCT ON исключает строки, соответствующие всем указанным выражениям. SELECT ALL (по умолчанию) возвращает все строки, включая дубликаты.

  7. Если указано оконное выражение (и опциональное выражение WINDOW), вывод организуется в соответствии c заданной на основе количества строк (ROWS) или на основе значений (RANGE) рамкой окна.

  8. Операторы UNION, INTERSECT и EXCEPT объединяют результаты нескольких команд SELECT в один результирующий набор:

    • UNION — возвращает все строки, которые присутствуют в одном или обоих результирующих наборах;

    • INTERSECT — возвращает все строки, которые присутствуют строго в обоих результирующих наборах;

    • EXCEPT — возвращает строки, которые присутствуют в первом результирующем наборе, но отсутствуют во втором.

    Во всех трех случаях дублирующиеся строки исключаются, если не указан оператор ALL. Чтобы явно обозначить, что дублирующиеся строки не должны включаться в результат, можно добавить ключевое слово DISTINCT. Обратите внимание, что в данном контексте DISTINCT используется по умолчанию, хотя в самом SELECT по умолчанию используется ALL.

  9. Если присутствует выражение ORDER BY, возвращаемые строки сортируются в указанном порядке. При отсутствии ORDER BY строки возвращаются в том порядке, который система считает наиболее быстрым для обработки.

  10. Если указано выражение LIMIT (или FETCH FIRST) или OFFSET, оператор SELECT возвращает только подмножество строк результата.

  11. Если указано выражение FOR UPDATE, FOR NO KEY UPDATE, FOR SHARE или FOR KEY SHARE, оператор SELECT блокирует всю таблицу от одновременных обновлений.

Для каждого столбца, используемого в команде SELECT, необходимо иметь привилегию SELECT. Применение блокировок FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE или FOR KEY SHARE требует также наличия привилегии UPDATE (как минимум для одного столбца в каждой выбранной для блокировки таблице).

Параметры

Выражение WITH

Опциональное выражение WITH позволяет указать один или несколько подзапросов, на которые можно ссылаться по имени в основном запросе. Эти подзапросы фактически действуют как временные таблицы или представления на время выполнения основного запроса. Каждый подзапрос может быть оператором SELECT, INSERT, UPDATE или DELETE. При использовании в WITH оператора, изменяющего данные (INSERT, UPDATE или DELETE), обычно добавляется выражение RETURNING. Именно результат RETURNING, а не нижележащая таблица, изменяемая оператором, формирует временную таблицу, которую затем читает основной запрос. Если выражение RETURNING опущено, оператор все равно выполняется, но не выдает никакого результата, поэтому на него нельзя ссылаться как на таблицу в основном запросе.

Для команды SELECT, включающей выражение WITH, это выражение может содержать не более одного оператора, изменяющего данные таблицы (INSERT, UPDATE или DELETE).

Для каждого запроса в выражении WITH должно быть указано имя with_query_name (без схемы). Также можно указать необязательный список имен столбцов; если список не указан, имена столбцов определяются из подзапроса.

Если указано ключевое слово RECURSIVE, подзапрос SELECT может ссылаться сам на себя по имени. Такой подзапрос должен иметь вид:

<non_recursive_term> UNION [ALL | DISTINCT] <recursive_term>

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

Если указано ключевое слово RECURSIVE, запросы WITH не обязательно должны быть упорядочены: запрос может ссылаться на другой запрос, который находится в списке после него. Однако циклические ссылки или взаимная рекурсия не поддерживаются.

Без ключевого слова RECURSIVE запрос в WITH может ссылаться только на запрос в WITH того же уровня, который находится раньше в списке WITH.

WITH RECURSIVE имеет ограничения. Не поддерживается:

  • Рекурсивное выражение WITH, которое содержит в recursive_term:

    • подзапросы со ссылками на себя;

    • выражение DISTINCT;

    • выражение GROUP BY;

    • оконную функцию.

  • Рекурсивное выражение WITH, в котором with_query_name является частью оператора множеств.

Ниже приведен пример ограничения, связанного с оператором множеств. Этот запрос возвращает ошибку, поскольку оператор UNION содержит ссылку на таблицу foo:

WITH RECURSIVE foo(i) AS (
    SELECT 1
  UNION ALL
    SELECT i+1 FROM (SELECT * FROM foo UNION SELECT 0) bar
)
SELECT * FROM foo LIMIT 5;

Это рекурсивное общее табличное выражение (Common Table Expression, CTE) разрешено, поскольку оператор UNION не содержит ссылку на CTE foo:

WITH RECURSIVE foo(i) AS (
    SELECT 1
  UNION ALL
    SELECT i+1 FROM (SELECT * FROM bar UNION SELECT 0) bar, foo
    WHERE foo.i = bar.a
)
SELECT * FROM foo LIMIT 5;

Ключевое свойство запросов WITH заключается в том, что они выполняются только один раз за выполнение основного запроса, даже если основной запрос ссылается на них более одного раза. В частности, гарантируется, что операторы, изменяющие данные, будут выполнены только один раз, независимо от того, в каком объеме основной запрос будет считывать их выходные данные (полностью или только часть).

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

За дополнительной информацией обратитесь к статье Общие табличные выражения (CTE).

Список SELECT

Список SELECT (между ключевыми словами SELECT и FROM) содержит выражения, формирующие выходные строки оператора SELECT. Эти выражения могут ссылаться (и обычно ссылаются) на столбцы, вычисленные в выражении FROM.

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

Как и в таблице, каждый выходной столбец запроса SELECT имеет имя. В простом запросе SELECT это имя используется только для обозначения столбца при выводе, но когда SELECT является подзапросом большого запроса, имя воспринимается этим запросом как имя столбца виртуальной таблицы, созданной подзапросом. Чтобы указать имя для выходного столбца, нужно написать AS <output_name> после выражения столбца. Слово AS можно опустить, но только если желаемое имя выходного столбца не совпадает ни с одним ключевым словом SQL. Чтобы не зависеть от возможного добавления новых ключевых слов в будущем, рекомендуется всегда писать AS, либо заключать имя выходного столбца в двойные кавычки. Если имя столбца не указано, Greengage DB выберет имя автоматически. Если выражение столбца представляет собой просто ссылку на столбец, то выбранное имя совпадает с именем этого столбца. В более сложных случаях может использоваться имя функции или типа, или система может сгенерировать имя (например, ?column? или columnN).

Имя выходного столбца можно использовать для ссылки на значение столбца в выражениях ORDER BY и GROUP BY, но не WHERE или HAVING (в них должны быть выражения).

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

Выражение DISTINCT

Если указан SELECT DISTINCT, все повторяющиеся строки исключаются из результирующего набора (из каждой группы дубликатов остается одна строка). SELECT ALL указывает на обратное: сохраняются все строки (поведение по умолчанию).

SELECT DISTINCT ON (expression [, …​]) сохраняет только первую строку из каждого набора строк, для которого данное выражение дает одинаковые значения. Выражения DISTINCT ON обрабатываются по тем же правилам, что и выражения ORDER BY (см. выше). Обратите внимание, что "первая строка" каждого набора непредсказуема, если не используется ORDER BY для обеспечения того, чтобы желаемая строка отображалась первой. Например:

SELECT DISTINCT ON (location) location, time, report
    FROM weather_reports
    ORDER BY location, time DESC;

возвращает самый последний прогноз погоды для каждого местоположения. Но если бы здесь не использовалось ORDER BY для упорядочивания значений времени в порядке убывания для каждого местоположения, был бы получен отчет для каждого местоположения от непредсказуемого времени.

Выражения DISTINCT ON должны соответствовать самым левым выражениям ORDER BY. Выражение ORDER BY обычно содержит дополнительные выражения, определяющие желаемый порядок строк в каждой группе DISTINCT ON.

Выражение FROM

В выражении FROM указывается одна или несколько таблиц в качестве источника данных для запроса SELECT. Если указано несколько источников, результатом будет декартово произведение (перекрестное соединение) всех их строк. Но обычно добавляются уточняющие условия (с помощью WHERE), чтобы ограничить возвращаемые строки небольшим подмножеством декартова произведения. Выражение FROM может содержать следующие элементы.

Элемент FROM Описание

table_name

Имя (опционально указанное со схемой) существующей таблицы или представления. Если указан ONLY, сканируется только эта таблица. Без ONLY сканируется таблица и все ее дочерние таблицы (если таковые имеются)

alias

Альтернативное имя элемента FROM. Этот псевдоним используется для краткости или для устранения неоднозначности с замкнутыми соединениями (когда одна и та же таблица сканируется несколько раз). Когда псевдоним указан, он полностью скрывает фактическое имя таблицы или функции; например, при записи FROM foo AS f, остальная часть запроса SELECT должна ссылаться на этот элемент FROM как на f, а не на foo. Если указан псевдоним таблицы, можно также указать список псевдонимов столбцов, чтобы предоставить альтернативные имена для одного или нескольких столбцов таблицы

select

В выражении FROM может присутствовать подзапрос SELECT. Это означает, что его результат создается как временная таблица на время выполнения основной команды SELECT. Обратите внимание, что подзапрос SELECT должен быть заключен в скобки, и для него должен быть указан псевдоним. Здесь также можно использовать команду VALUES

with_query_name

В выражении FROM ссылка на with_query осуществляется по имени with_query_name, как если бы это было имя таблицы. with_query_name не может содержать спецификатор схемы. Псевдоним может быть указан так же, как и для таблицы.

Запрос with_query скрывает таблицу с тем же именем для основного запроса. При необходимости можно обратиться к одноименной таблице, указав в имени таблицы схему

function_name

В выражении FROM могут содержаться вызовы функций (особенно может быть полезно если функции возвращают наборы результатов, но можно использовать любые функции). Это работает так, как если бы результат был создан в виде временной таблицы на время выполнения текущей команды SELECT. Для функции также можно использовать псевдоним. Если псевдоним указан, можно также указать список псевдонимов столбцов, чтобы предоставить альтернативные имена для одного или нескольких атрибутов составного типа возвращаемого функцией результата. Если функция определена как возвращающая тип данных record, то для нее нужно указать псевдоним или ключевое слово AS, за которым должен следовать список определений столбцов в формате (<column_name> <data_type> [, …​ ]). Список определений столбцов должен соответствовать фактическому количеству и типам столбцов, возвращаемых функцией

join_type

Один из следующих вариантов:

  • [INNER] JOIN

  • LEFT [OUTER] JOIN

  • RIGHT [OUTER] JOIN

  • FULL [OUTER] JOIN

  • CROSS JOIN

Для типов соединения INNER и OUTER необходимо указать условие соединения, а именно одно из следующих: NATURAL, ON <join_condition> или USING (<join_column> [, …​]). Эти выражения описываются ниже. Для CROSS JOIN ни одно из этих условий не допускается.

Оператор JOIN объединяет два элемента FROM, которые далее для простоты мы будем называть "таблицами", хотя на самом деле это могут быть любые элементы FROM. При необходимости используйте скобки для определения порядка вложенности. В отсутствие скобок операторы JOIN обрабатываются слева направо. В любом случае JOIN связывает элементы сильнее, чем запятые, разделяющие элементы в списке FROM.

Типы соединения CROSS JOIN и INNER JOIN создают простое декартово произведение, тот же результат, что и при перечислении двух таблиц на верхнем уровне FROM, но с ограничениями по условию соединения (если таковое имеется). CROSS JOIN эквивалентен INNER JOIN ON (TRUE), то есть строки не удаляются по условию. Эти типы соединения существуют просто для удобства записи, они не делают ничего такого, чего нельзя было бы сделать с помощью обычных FROM и WHERE.

LEFT OUTER JOIN возвращает все строки ограниченного декартова произведения (т.е. все объединенные строки, удовлетворяющие условию объединения) плюс одну копию каждой строки в левой таблице, для которой не находится строка в таблице справа, удовлетворяющая условию объединения. Строка, взятая из таблицы слева, дополняется до полной ширины объединенной таблицы путем вставки значений NULL в столбцах таблицы справа. Обратите внимание, что при определении того, какие строки имеют совпадения, проверяется только условие самого выражения JOIN. Внешние условия применяются позже.

Напротив, RIGHT OUTER JOIN возвращает все объединенные строки плюс одну строку для каждой строки справа, не имеющей соответствия слева (расширенную значениями NULL влево). Это выражение используется только для удобства записи, его можно свести к LEFT OUTER JOIN, поменяв местами левую и правую таблицы.

FULL OUTER JOIN возвращает все объединенные строки плюс все строки слева, не имеющие соответствия справа (расширенные значениями NULL вправо), плюс все строки справа, не имеющие соответствия слева (расширенные значениями NULL влево)

ON <join_condition>

join_condition — выражение, результатом которого является значение типа boolean (аналогично выражению WHERE), указывающее, какие строки в объединении считаются соответствующими условиям соединения

USING (<join_column> [, …​])

Условие вида USING (a, b, …​) является сокращенной записью для ON left_table.a = right_table.a AND left_table.b = right_table.b …​. Кроме того, USING подразумевает, что в результат соединения будет включен только один столбец из каждой пары эквивалентных столбцов, а не оба

NATURAL

NATURAL — сокращение для списка USING, в котором перечисляются все столбцы в двух таблицах, имеющие одинаковые имена. Если общих имен столбцов нет, NATURAL эквивалентно ON TRUE

Выражение WHERE

Синтаксис в общем виде опционального выражения WHERE:

WHERE <condition>

где condition — любое выражение, результатом которого является значение типа boolean. Любая строка, не удовлетворяющая этому условию, будет исключена из результата. Строка удовлетворяет условию, если она возвращает true при подстановке фактических значений строки вместо ссылок на переменные.

Выражение GROUP BY

Синтаксис в общем виде опционального выражения GROUP BY:

GROUP BY <grouping_element> [, ...]

где grouping_element может быть:

()
<expression>
ROLLUP (<expression> [,...])
CUBE (<expression> [,...])
GROUPING SETS ((<grouping_element> [, ...]))

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

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

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

Следует помнить, что все агрегатные функции вычисляются до вычисления любых скалярных выражений в предложении HAVING или списке SELECT. Это означает, что, например, выражение CASE нельзя использовать для пропуска вычисления агрегатной функции.

Greengage DB имеет следующие дополнительные расширения для группировки OLAP (часто называемые супергруппами).

Расширение для группировки Описание

ROLLUP

Группировка ROLLUP — это расширение для выражения GROUP BY, которое создает агрегированные промежуточные итоги, суммирующиеся от самого подробного уровня до общей суммы, в соответствии со списком столбцов группировки (или выражений). ROLLUP принимает упорядоченный список столбцов группировки, вычисляет стандартные агрегированные значения, указанные в выражении GROUP BY, затем создает промежуточные итоги более высокого уровня, двигаясь справа налево по списку. И в итоге, вычисляет общую сумму. Группировку ROLLUP можно рассматривать как серию наборов группировки. Например:

GROUP BY ROLLUP (a,b,c)

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

GROUP BY GROUPING SETS( (a,b,c), (a,b), (a), () )

Обратите внимание, что n элементов ROLLUP преобразуются в n+1 наборов группировки. Кроме того, в ROLLUP имеет значение порядок указания выражений группировки

CUBE

Группировка CUBE — это расширение для выражения GROUP BY, которое создает промежуточные итоги для всех возможных комбинаций заданного списка столбцов группировки (или выражений). В контексте многомерного анализа CUBE генерирует все промежуточные итоги, которые можно вычислить для куба данных с указанными измерениями. Например:

GROUP BY CUBE (a,b,c)

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

GROUP BY GROUPING SETS( (a,b,c), (a,b), (a,c), (b,c), (a), (b), (c), () )

Обратите внимание, что n элементов CUBE соответствуют числу наборов группировок. Рекомендуется использовать CUBE в любых ситуациях, требующих создания кросс-табличных отчетов. CUBE обычно наиболее подходит для запросов, использующих столбцы из нескольких измерений, а не столбцы, представляющие разные уровни одного измерения. Например, для часто запрашиваемой перекрестной таблицы могут потребоваться промежуточные итоги по всем комбинациям месяца, состояния и продукта.

ПРИМЕЧАНИЕ

Greengage DB поддерживает возможность указать максимум 12 столбцов группировки CUBE.

GROUPING SETS

Вы можете выборочно указать набор групп, которые хотите создать, используя выражение GROUPING SETS внутри выражения GROUP BY. Это позволяет получить точную спецификацию по нескольким измерениям без вычисления целого ROLLUP или CUBE. Например:

GROUP BY GROUPING SETS( (a,c), (a,b) )

При использовании расширений группировки ROLLUP, CUBE или GROUPING SETS возникают две проблемы. Во-первых, как определить, какие результирующие строки являются промежуточными итогами, и затем точный уровень агрегации для данного промежуточного итога? Или как отличить результирующие строки, содержащие как сохраненные значения NULL, так и значения NULL, возвращаемые ROLLUP или CUBE? Во-вторых, когда в выражении GROUP BY указаны повторяющиеся наборы группировок, как определить, какие результирующие строки являются дубликатами? Для решения этой проблемы можно использовать две дополнительные функции группировки в списке SELECT:

  • grouping(column [, …​]) — функция grouping может применяться к одному или нескольким атрибутам группировки чтобы отличать строки, которые представляют собой супергруппы, от строк, которые являются обычными группами. Это может быть полезно, чтобы отличать значение NULL, представляющее собой набор всех значений в строке-супергруппе, от значения NULL в обычной строке. Каждый аргумент этой функции возвращает бит — либо 1, либо 0, где 1 означает, что результирующая строка является супергруппой (то есть является промежуточным итогом), а 0 означает, что результирующая строка относится к обычной группировке. Функция grouping возвращает целое число, обрабатывая эти биты как двоичное число, а затем преобразуя его в десятичное целое число.

  • group_id() — для запросов с расширениями группировки, содержащих повторяющиеся наборы группировок, функция group_id используется для идентификации повторяющихся строк в выходных данных. Все уникальные выходные строки наборов группировок будут иметь значение group_id, равное 0. Для каждого обнаруженного повторяющегося набора группировки функция group_id присваивает номер больше 0. Все выходные строки в конкретном повторяющемся наборе группировки идентифицируются одним и тем же номером group_id.

Выражение WINDOW

Необязательное выражение WINDOW определяет поведение оконных функций, фигурирующих в списке SELECT или выражении ORDER BY запроса. Эти функции могут ссылаться на элементы WINDOW по именам в своих выражениях OVER. Однако элементы WINDOW не обязательно должны быть использованы в запросе; если они не используются, они просто игнорируются. Можно использовать оконные функции вообще без выражения WINDOW, поскольку в вызове оконной функции может напрямую указываться определение окна непосредственно в выражении OVER. Однако выражение WINDOW позволяет уменьшить текст запроса, когда одно и то же определение окна применяется при вызове нескольких оконных функций.

Например:

SELECT vendor, rank() OVER (mywindow) FROM sale
GROUP BY vendor
WINDOW mywindow AS (ORDER BY sum(prc*qty));

Синтаксис выражения WINDOW в общем виде:

WINDOW <window_name> AS (<window_definition>)

где window_name — это имя, на которое можно ссылаться из выражений OVER или последующих определений окон, а window_definition — описание окна, которое имеет следующий вид:

[<existing_window_name>]
[PARTITION BY <expression> [, ...]]
[ORDER BY <expression> [ASC | DESC | USING <operator>] [NULLS {FIRST | LAST}] [, ...] ]
[<frame_clause>]

Описание окна имеет следующие параметры.

Параметр Описание

existing_window_name

Если указано имя окна existing_window_name, оно должно ссылаться на более раннюю запись в списке WINDOW; новое окно копирует выражение разделения из этой записи, а также выражение сортировки, если оно присутствует. В этом случае для нового окна нельзя указать собственное выражение PARTITION BY, а ORDER BY можно указать только в том случае, если у копируемого окна его нет. Новое окно всегда использует собственное выражение рамки; в копируемом окне выражение рамки указываться не должно

PARTITION BY

Выражение PARTITION BY организует результирующий набор в логические группы на основе уникальных значений указанного выражения. Элементы выражения PARTITION BY интерпретируются практически так же, как и элементы GROUP BY, за исключением того, что это всегда простые выражения, но не имя или номер выходного столбца. Еще одно отличие заключается в том, что эти выражения могут содержать вызовы агрегатных функций, которые не допускаются в обычном выражении GROUP BY. Здесь они разрешены, поскольку формирование окна происходит после группировки и агрегирования. При использовании с оконными функциями функции применяются к каждому разделу независимо. Например, если после PARTITION BY указано имя столбца, результирующий набор разделяется по уникальным значениям этого столбца. Если выражение не указано, все строки рассматриваются как один раздел.

Аналогично, элементы списка ORDER BY интерпретируются почти так же, как и элементы выражения ORDER BY, за исключением того, что выражения всегда рассматриваются как простые выражения, но не как имя или номер выходного столбца

ORDER BY

Элементы выражения ORDER BY определяют способ сортировки строк в каждом разделе результирующего набора. Если выражение не указано, строки возвращаются в том порядке, который является наиболее эффективным и может меняться.

ПРИМЕЧАНИЕ

Столбцы типов данных, в которых отсутствует согласованный порядок, например, time, не являются подходящими для использования в выражении ORDER BY описания окна. Время, с часовым поясом или без него, не имеет согласованного порядка, поскольку сложение и вычитание не дают ожидаемых результатов. Например, следующее выражение, как правило, неверно: x::time < x::time + '2 hour'::interval.

frame_clause

Необязательное выражение frame_clause определяет рамку окна для оконных функций, зависящих от рамки (не все функции такие). Рамка окна представляет собой набор связанных строк для каждой строки запроса (называемой текущей строкой). В качестве frame_clause может быть указано:

{ RANGE|ROWS } <frame_start>
{ RANGE|ROWS } BETWEEN <frame_start> AND <frame_end>

где frame_start и frame_end могут принимать следующие значения:

  • UNBOUNDED PRECEDING

  • <value> PRECEDING

  • CURRENT ROW

  • <value> FOLLOWING

  • UNBOUNDED FOLLOWING

Если параметр frame_end опущен, по умолчанию используется CURRENT ROW. Ограничения: в качестве frame_start нельзя указывать UNBOUNDED FOLLOWING; в качестве frame_end не допускается UNBOUNDED PRECEDING; frame_end не может располагаться в списке <frame_start> AND <frame_end> раньше, чем frame_start (например, RANGE BETWEEN CURRENT ROW AND <value> PRECEDING не допускается).

По умолчанию рамка формируется выражением RANGE UNBOUNDED PRECEDING, что аналогично RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW — оно устанавливает рамку так, что она включает все строки от начала раздела до последней строки, родственной текущей (строки, которую ORDER BY считает эквивалентной текущей строке, или всех строк, если параметр ORDER BY отсутствует). В общем случае, UNBOUNDED PRECEDING означает, что рамка начинается с первой строки раздела, а UNBOUNDED FOLLOWING означает, что рамка заканчивается последней строкой раздела (независимо от режима RANGE или ROWS). В режиме ROWS указание CURRENT ROW означает, что рамка начинается или заканчивается текущей строкой; но в режиме RANGE это означает, что рамка начинается или заканчивается первой или последней строкой, родственной текущей, в порядке сортировки ORDER BY. В настоящее время значения PRECEDING и FOLLOWING разрешены только в режиме ROWS. Они указывают, что рамка начинается или заканчивается строкой, предшествующей или следующей за текущей строкой на указанное количество строк. Значение должно быть целочисленным выражением, не содержащим переменных, агрегатных функций или оконных функций. Значение не должно быть NULL или отрицательным; однако оно может быть равно нулю, что означает выбор текущей строки.

Следует помнить, что в режиме ROWS могут выдаваться непредсказуемые результаты, если сортировка ORDER BY не обеспечивает однозначного порядка строк. Режим RANGE предназначен для обеспечения одинаковой обработки строк, являющихся родственными в сортировке ORDER BY: все строки определенной группы будут находиться в одной и той же рамке.

Для указания границ окна используйте выражение ROWS или RANGE. Границы окна могут составлять одну, несколько или все строки раздела. Границы окна можно указать либо в виде диапазона значений данных, смещенных относительно значения в текущей строке (RANGE), либо в виде количества строк, смещенных относительно текущей строки (ROWS). При использовании RANGE необходимо также использовать ORDER BY. Это связано с тем, что для создания окна требуется сортировка значений. Кроме того, ORDER BY не может содержать более одного выражения, и результат выражения должен быть либо датой, либо числовым значением. При использовании ROWS или RANGE, если указана только начальная строка, текущая строка используется в качестве последней строки в окне.

  • PRECEDING — определяет первую строку окна, используя текущую строку в качестве точки отсчета. Начальная строка определяется количеством строк, предшествующих текущей строке. Например, в случае использования рамки на основе количества строк (ROWS), 5 PRECEDING устанавливает начало окна с пятой строки, предшествующей текущей строке. В случае использования рамки на основе значений (RANGE) началом окна устанавливается первая строка, значение которой в столбце упорядочивания меньше значения столбца текущей строки максимум на 5 в указанном порядке. Если указанный порядок — возрастание по дате, это будет первая строка в пределах 5 дней до текущей строки. UNBOUNDED PRECEDING устанавливает, что первой строкой в окне является первая строка в разделе.

  • BETWEEN — определяет первую и последнюю строки окна, используя текущую строку в качестве точки отсчета. Первая и последняя строки выражаются в количестве строк, предшествующих и следующих за текущей строкой, соответственно. Например, BETWEEN 3 PRECEDING AND 5 FOLLOWING устанавливает, что окно начинается с третьей строки, предшествующей текущей, и заканчивается пятой строкой, следующей за текущей. Используйте BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING, чтобы установить первую и последнюю строки в окне соответственно первой и последней строкой в ​​разделе. Это эквивалентно поведению по умолчанию, если не указано выражение ROWS или RANGE.

  • FOLLOWING — определяет последнюю строку окна, используя текущую строку в качестве точки отсчета. Последняя строка выражается в количестве строк, следующих за текущей строкой. Например, в случае использования рамки ROWS, 5 FOLLOWING устанавливает, что окно заканчивается пятой строкой, следующей за текущей. В случае использования рамки RANGE окно заканчивается строкой, значение которой в столбце упорядочивания больше значения текущей строки максимум на 5 в указанном порядке. Если указанный порядок — возрастание по дате, это будет последняя строка в пределах 5 дней после текущей строки. Используйте UNBOUNDED FOLLOWING, чтобы установить в качестве последней строки в окне последнюю строку в разделе.

Если выражение ROWS или RANGE не указано, окно начинается с первой строки в разделе (UNBOUNDED PRECEDING) и заканчивается текущей строкой (CURRENT ROW), если используется ORDER BY. Если выражение ORDER BY не указано, окно начинается с первой строки в разделе (UNBOUNDED PRECEDING) и заканчивается последней строкой в ​​разделе (UNBOUNDED FOLLOWING)

Выражение HAVING

Синтаксис опционального выражения HAVING в общем виде:

HAVING <condition>

где condition указывается так же, как для выражения WHERE. HAVING исключает из результата строки групп, которые не удовлетворяют условию. HAVING отличается от WHERE: WHERE фильтрует отдельные строки перед применением GROUP BY, а HAVING фильтрует строки групп, созданные выражением GROUP BY. Каждый столбец, присутствующий в условии, должен однозначно ссылаться на столбец группировки, за исключением случаев, когда ссылка находится внутри агрегатной функции или не сгруппированный столбец функционально зависит от столбцов группировки.

Наличие условия HAVING превращает запрос в группируемый, даже если в нем отсутствует GROUP BY. То же самое происходит, когда запрос содержит агрегатные функции, но не содержит выражения GROUP BY. Все выбранные строки считаются образующими одну группу, а в списке SELECT и выражении HAVING можно ссылаться на столбцы таблицы только из агрегатных функций. Такой запрос будет выдавать одну строку, если условие HAVING истинно, и ноль строк, если оно ложно.

Выражение UNION

Синтаксис выражения UNION в общем виде:

<select_statement> UNION [ALL | DISTINCT] <select_statement>

где select_statement — это любой оператор SELECT без выражений ORDER BY, LIMIT, FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE и FOR KEY SHARE. ORDER BY и LIMIT могут быть добавлены к вложенному выражению, если оно заключено в скобки. Без скобок эти выражения будут считаться применяемыми к результату UNION, а не к выражению в его правой части.

Оператор UNION вычисляет объединение множеств строк, возвращаемых связанными операторами SELECT. Строка входит в объединение двух результирующих наборов, если она присутствует хотя бы в одном из наборов. Два оператора SELECT, представляющие собой непосредственные операнды оператора UNION, должны выдавать одинаковое количество столбцов, и соответствующие столбцы должны иметь совместимые типы данных.

Результат выполнения команды UNION не будет содержать повторяющихся строк, если не указана опция ALL. ALL предотвращает исключение дубликатов. Таким образом, UNION ALL обычно выполняется значительно быстрее, чем UNION; поэтому следует указывать ALL, когда это возможно. Можно указать DISTINCT, чтобы явно обозначить, что дублирующиеся строки должны удаляться (поведение по умолчанию).

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

В настоящее время параметры FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE и FOR KEY SHARE нельзя указать ни для результата UNION, ни для любого из подзапросов UNION.

Выражение INTERSECT

Синтаксис выражения INTERSECT в общем виде:

<select_statement> INTERSECT [ALL | DISTINCT] <select_statement>

где select_statement — это любой оператор SELECT без выражений ORDER BY, LIMIT, FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE и FOR KEY SHARE.

Оператор INTERSECT вычисляет пересечение множеств строк, возвращаемых связанными операторами SELECT. Строка находится в пересечении двух результирующих наборов, если она присутствует в обоих наборах.

Результат выполнения команды INTERSECT не будет содержать повторяющихся строк, если не указана опция ALL. При использовании ALL строка, имеющая m дубликатов в левой таблице и n дубликатов в правой, будет встречаться в результирующем наборе min(m, n) раз. Можно указать DISTINCT, чтобы явно обозначить, что дублирующиеся строки должны удаляться (поведение по умолчанию).

Несколько операторов INTERSECT в одном запросе SELECT вычисляются слева направо, если скобки не указывают иной порядок. INTERSECT связывает свои подзапросы сильнее, чем UNION. То есть, A UNION B INTERSECT C будет интерпретироваться как A UNION (B INTERSECT C).

В настоящее время параметры FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE и FOR KEY SHARE нельзя указать ни для результата INTERSECT, ни для любого из подзапросов INTERSECT.

Выражение EXCEPT

Синтаксис выражения EXCEPT в общем виде:

<select_statement> EXCEPT [ALL | DISTINCT] <select_statement>

где select_statement — любой оператор SELECT без выражений ORDER BY, LIMIT, FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE и FOR KEY SHARE.

Оператор EXCEPT вычисляет набор строк, которые присутствуют в результате левого запроса SELECT, но отсутствуют в результате правого.

Результат команды EXCEPT не содержит повторяющихся строк, если не указана опция ALL. При использовании ALL строка, повторяющаяся m раз в левой таблице и n раз в правой, будет встречаться в результирующем наборе max(m-n,0) раз. Можно указать DISTINCT, чтобы явно обозначить, что дублирующиеся строки должны удаляться (поведение по умолчанию).

Несколько операторов EXCEPT в одном запросе SELECT вычисляются слева направо, если скобки не указывают иной порядок. Оператор EXCEPT связывает свои подзапросы так же сильно, как UNION.

В настоящее время параметры FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE и FOR KEY SHARE нельзя указать ни для результата EXCEPT, ни для любого из подзапросов EXCEPT.

Выражение ORDER BY

Синтаксис опционального выражения ORDER BY в общем виде:

ORDER BY <expression> [ASC | DESC | USING <operator>] [NULLS {FIRST | LAST}] [,...]

где expression может быть именем или порядковым номером выходного столбца (элемента списка SELECT), либо произвольным выражением со значениями входных столбцов.

ORDER BY сортирует строки результата в соответствии с указанными выражениями. Если две строки равны по самому левому выражению, они сравниваются по следующему выражению и так далее. Если они равны по всем указанным выражениям, они возвращаются в порядке, зависящем от реализации.

Порядковый номер указывает на позицию (при нумерации слева направо) выходного столбца. Возможность указать порядковый номер позволяет выполнить сортировку по столбцу, не имеющему уникального имени. Это не абсолютно необходимо, поскольку выходному столбцу всегда можно присвоить имя с помощью AS.

В выражении ORDER BY также можно использовать произвольные выражения, в том числе со столбцами, отсутствующими в списке результатов SELECT. Таким образом, следующий запрос является корректным:

SELECT name FROM distributors ORDER BY code;

Однако если ORDER BY применяется к результату UNION, INTERSECT или EXCEPT, в выражении ORDER BY можно указывать только имя или номер выходного столбца, но не выражение.

Если выражение ORDER BY представляет собой простое имя, совпадающее как с именем выходного столбца, так и с именем входного столбца, то ORDER BY интерпретирует его как имя выходного столбца. Этот выбор противоположен тому, что делает GROUP BY в той же ситуации. Такая несогласованность допускается для соответствия стандарту SQL.

Дополнительно после любого выражения в выражении ORDER BY можно добавить ключевое слово ASC (по возрастанию) или DESC (по убыванию). По умолчанию используется ASC. Кроме того, в выражении USING можно указать имя конкретного оператора сортировки. ASC обычно эквивалентно USING <, а DESC — USING >. Однако при создании нестандартного типа данных можно определить по-другому порядок сортировки по умолчанию и поставить ему в соответствие операторы с другими именами.

Если указан NULLS LAST, значения NULL при сортировке оказываются после всех значений не NULL; при указании NULLS FIRST значения NULL оказываются перед всеми значениями не NULL. Если не указано ни то, ни другое, по умолчанию используется поведение NULLS LAST, если указан или подразумевается порядок ASC, и NULLS FIRST, если указан порядок DESC (таким образом, по умолчанию значения NULL считаются больше значений не NULL). При указании USING порядок значений NULL по умолчанию зависит от того, является ли указанный оператор оператором "меньше" или "больше".

Обратите внимание, что параметры сортировки применяются только к выражению, за которым они следуют; например, ORDER BY x, y DESC означает не то же самое, что ORDER BY x DESC, y DESC.

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

Символьно-строковые данные сортируются в соответствии с кодировкой, применяемой к сортируемому столбцу. При необходимости ее можно изменить, добавив в выражение COLLATE, например, ORDER BY mycolumn COLLATE "en_US". Информацию об определении кодировок можно посмотреть в статье CREATE COLLATION.

Выражение LIMIT

Выражение LIMIT состоит из двух независимых вложенных выражений:

LIMIT {<count> | ALL}
OFFSET <start>

где count определяет максимальное количество возвращаемых строк, а start — количество строк, которые следует пропустить, прежде чем начать возвращать строки. Если указаны оба параметра, сначала строки пропускаются в количестве start, затем возвращаются следующие строки в количестве, не превышающем значение count.

Если выражение count возвращает NULL, оно рассматривается как LIMIT ALL, то есть число строк не ограничивается. Если выражение start возвращает NULL, оно рассматривается как OFFSET 0.

В SQL:2008 был введен другой синтаксис для достижения того же результата, который также поддерживается Greengage DB. Он выглядит следующим образом:

OFFSET <start> [ ROW | ROWS ]
    FETCH { FIRST | NEXT } [ <count> ] { ROW | ROWS } ONLY

В этом синтаксисе значение start или count должно быть, согласно стандарту, литеральной константой, параметром или именем переменной; в Greengage DB допускаются и другие выражения, но, как правило, их необходимо заключать в скобки во избежание неоднозначности. Если count опускается в выражении FETCH, по умолчанию оно равно 1. ROW и ROWS, а также FIRST и NEXT являются незначащими словами, которые не влияют на действие этих выражений. Согласно стандарту, выражение OFFSET должно стоять перед FETCH, если они оба присутствуют; однако Greengage DB допускает любой порядок.

При использовании LIMIT рекомендуется добавлять условие ORDER BY, чтобы строки результата выдавались в определенном порядке. Иначе будут возвращаться непредсказуемые подмножества строк запроса — вы можете запрашивать строки с десятой по двадцатую, но в каком порядке? Порядок будет неизвестен, если не указать ORDER BY.

Планировщик запросов учитывает LIMIT при генерации плана выполнения запроса, поэтому, скорее всего, планы будут разными (а значит и порядок строк) в зависимости от значений LIMIT и OFFSET. Таким образом, использование разных значений LIMIT/OFFSET для выбора разных подмножеств результатов запроса приведет к непоследовательным результатам, если не установить предсказуемую сортировку с помощью ORDER BY. Это не недостаток, а неизбежное следствие того, что SQL не гарантирует предоставление результатов запроса в каком-либо определенном порядке, если порядок явно не определен выражением ORDER BY.

Выражения блокировки

FOR UPDATE, FOR NO KEY UPDATE, FOR SHARE и FOR KEY SHARE — выражения блокировки, которые влияют на то, как оператор SELECT блокирует строки, получаемые из таблицы.

Условие блокировки в общем виде:

FOR <lock_strength> [OF <table_name> [ , ... ] ] [ NOWAIT ]

где lock_strength может быть:

  • FOR UPDATE — блокирует таблицу в режиме EXCLUSIVE.

  • FOR NO KEY UPDATE — блокирует таблицу в режиме EXCLUSIVE.

  • FOR SHARE — блокирует таблицу в режиме ROW SHARE.

  • FOR KEY SHARE — блокирует таблицу в режиме ROW SHARE.

ПРИМЕЧАНИЕ

По умолчанию Greengage DB устанавливает более строгую блокировку EXCLUSIVE (в отличие от ROW EXCLUSIVE в PostgreSQL) для операций UPDATE, DELETE и SELECT …​ FOR UPDATE в heap-таблицах. При включении Global Deadlock Detector для операций UPDATE и DELETE в heap-таблицах устанавливается режим блокировки ROW EXCLUSIVE. Greengage DB всегда удерживает блокировку на уровне таблицы при использовании операторов SELECT …​ FOR UPDATE.

Для получения более подробной информации о каждом режиме блокировки на уровне строк обратитесь к статье Explicit Locking в документации PostgreSQL.

Чтобы операция не ждала завершения других транзакций, используйте опцию NOWAIT. С этой опцией оператор сообщает об ошибке, а не ждет, если выбранную строку не удается заблокировать немедленно. Обратите внимание, что NOWAIT влияет только на то, ожидает ли оператор SELECT получения блокировок на уровне строк. Необходимая блокировка на уровне таблицы всегда устанавливается обычным способом. Например, оператор SELECT FOR UPDATE NOWAIT всегда будет ожидать необходимой блокировки на уровне таблицы; он ведет себя так, как если опция NOWAIT не применяется. Если необходимо получить блокировку на уровне таблицы без ожидания, можно сначала выполнить LOCK с указанием NOWAIT.

Если в выражении блокировки указаны определенные таблицы, то блокируются только строки, получаемые из этих таблиц; любые другие таблицы, используемые в запросе SELECT, будут считываться как обычно. Выражение блокировки без списка таблиц влияет на все таблицы, используемые в запросе. Если выражение блокировки применяется к представлению или подзапросу, оно влияет на все таблицы, используемые в представлении или подзапросе. Однако эти выражения не применяются к запросам WITH, на которые ссылается основной запрос. Если требуется установить блокировку строк в запросе WITH, укажите выражение блокировки внутри запроса WITH.

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

Выражения блокировки нельзя использовать в контекстах, где возвращаемые строки не могут быть четко идентифицированы с отдельными строками таблицы; например, блокировку нельзя использовать при агрегировании.

Если в запросе SELECT на верхнем уровне присутствует выражение блокировки, блокируются только те строки, которые возвращаются запросом; в случае запроса с объединением блокируются строки, из которых составляются возвращаемые строки объединения. Кроме того, будут заблокированы строки, удовлетворяющие условиям запроса на момент создания снимка запроса, хотя они не будут возвращены, если изменятся с момента снимка и перестанут удовлетворять условиям. Если используется условие LIMIT, блокировка прекращается, как только будет возвращено достаточное количество строк для удовлетворения лимита (но обратите внимание, что строки, пропускаемые условием OFFSET, будут заблокированы). Аналогично, если выражение блокировки используется в запросе курсора, будут заблокированы только строки, фактически полученные или пройденные курсором.

Когда в подзапросе SELECT присутствует выражение блокировки, блокируются те строки, которые подзапрос возвращает во внешний запрос. Таких строк может оказаться меньше, чем можно предположить, проанализировав только сам подзапрос, так как условия из внешнего запроса могут способствовать оптимизации выполнения подзапроса. Например,

SELECT * FROM (SELECT * FROM mytable FOR UPDATE) ss WHERE col1 = 5;

заблокирует только строки, у которых col1 = 5, даже если это условие не указано в тексте подзапроса.

Команда SELECT, выполняющаяся на уровне изоляции транзакций READ COMMITTED и использующая ORDER BY вместе с блокировкой, может возвращать строки в неправильном порядке. Это происходит потому, что ORDER BY применяется первым. Команда отсортирует результат, но затем может быть заблокирована, пытаясь получить блокировку на одну или несколько строк. После разблокировки SELECT некоторые значения сортируемых столбцов могут быть изменены, в результате чего их порядок может быть нарушен (хотя они были упорядочены по исходным значениям столбцов). При необходимости эту проблему можно обойти, поместив выражение FOR UPDATE/SHARE в подзапрос, например:

SELECT * FROM (SELECT * FROM mytable FOR UPDATE) ss ORDER BY column1;

Обратите внимание, что это приведет к блокировке всех строк таблицы mytable, тогда как указание FOR UPDATE на верхнем уровне могло бы заблокировать только фактически возвращаемые строки. Это может существенно повлиять на производительность, особенно если ORDER BY сочетается с LIMIT или другими ограничениями. Поэтому этот метод рекомендуется только в том случае, если ожидается параллельное обновление столбцов сортировки и требуется строго отсортированный результат.

На уровне изоляции транзакций REPEATABLE READ или SERIALIZABLE это приведет к ошибке сериализации (с SQLSTATE равным 40001), поэтому на этих уровнях изоляции невозможно получить строки не по порядку.

Команда TABLE

Команда

TABLE <name>

равнозначна

SELECT * FROM <name>

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

Примеры

Соединение таблицы films с таблицей distributors:

SELECT f.title, f.did, d.name, f.date_prod, f.kind
FROM distributors d,
     films f
WHERE f.did = d.did

Суммирование значений столбца length для всех фильмов и группирование результатов по столбцу kind:

SELECT kind, sum(length) AS total
FROM films
GROUP BY kind;

Суммирование значений столбца length для всех фильмов, группирование результатов по столбцу kind и вывод только тех групп, в которых общая продолжительность фильмов меньше 5 часов:

SELECT kind, sum(length) AS total
FROM films
GROUP BY kind
HAVING sum(length) < interval '5 hours';

Вычисление промежуточных и общих сумм всех продаж по категориям kind и distributor:

SELECT kind, distributor, sum(prc * qty)
FROM sales
GROUP BY ROLLUP (kind, distributor)
ORDER BY 1, 2, 3;

Вычисление рейтинга кинокомпаний на основе общего объема продаж:

SELECT distributor,
       sum(prc * qty),
       rank() OVER (ORDER BY sum(prc * qty) DESC)
FROM sale
GROUP BY distributor
ORDER BY 2 DESC;

Следующие два примера демонстрируют идентичные способы сортировки результатов по содержимому второго столбца (name):

SELECT * FROM distributors ORDER BY name;
SELECT * FROM distributors ORDER BY 2;

В следующем примере показано, как получить объединение таблиц distributors и actors, ограниченное именами, начинающимися с буквы W в каждой таблице. Необходимо вывести только уникальные строки, поэтому ключевое слово ALL опущено:

SELECT distributors.name
FROM distributors
WHERE distributors.name LIKE 'W%'
UNION
SELECT actors.name
FROM actors
WHERE actors.name LIKE 'W%';

В этом примере показано, как использовать функцию в выражении FROM, со списком определений столбцов и без него:

CREATE FUNCTION distributors(int)
    RETURNS SETOF distributors
AS
$$
SELECT *
FROM distributors
WHERE did = $1;
$$ LANGUAGE SQL;

SELECT *
FROM distributors(111);

CREATE FUNCTION distributors_2(int)
    RETURNS SETOF record AS
$$
SELECT *
FROM distributors
WHERE did = $1;
$$ LANGUAGE SQL;

SELECT *
FROM distributors_2(111) AS (dist_id int, dist_name text);

Пример использования простого выражения WITH:

WITH test AS (SELECT random() as x
              FROM generate_series(1, 3))
SELECT * FROM test
UNION ALL
SELECT * FROM test;

В этом примере используется выражение WITH для отображения итоговых продаж по каждому продукту только в регионах с наибольшими объемами продаж:

WITH regional_sales AS (SELECT region, SUM(amount) AS total_sales
                        FROM orders
                        GROUP BY region),
     top_regions AS (SELECT region
                     FROM regional_sales
                     WHERE total_sales > (SELECT SUM(total_sales)
                                          FROM regional_sales))
SELECT region,
       product,
       SUM(quantity) AS product_units,
       SUM(amount)   AS product_sales
FROM orders
WHERE region IN (SELECT region FROM top_regions)
GROUP BY region, product;

Запрос можно было бы написать и без WITH, но тогда потребовалось бы два уровня вложенных операторов SELECT.

В этом примере используется выражение WITH RECURSIVE для поиска всех подчиненных (прямых или косвенных) сотрудника Mary и вывода их уровня косвенности из таблицы с информацией только о прямых подчиненных:

WITH RECURSIVE employee_recursive(distance, employee_name, manager_name) AS (
    SELECT 1, employee_name, manager_name
    FROM employee
    WHERE manager_name = 'Mary'
  UNION ALL
    SELECT er.distance + 1, e.employee_name, e.manager_name
    FROM employee_recursive er, employee e
    WHERE er.employee_name = e.manager_name
  )
SELECT distance, employee_name FROM employee_recursive;

Типичная форма рекурсивных запросов: начальное условие, за которым следует UNION [ALL], а затем рекурсивная часть запроса. Убедитесь, что рекурсивная часть запроса в конечном итоге не вернет ни одного кортежа, иначе запрос окажется в бесконечном цикле. Дополнительные примеры можно посмотреть в статье Общие табличные выражения (CTE).

Совместимость

Оператор SELECT совместим со стандартом SQL, но имеет некоторые расширения, а некоторые возможности, наоборот, не реализованы.

Необязательное выражение FROM

В Greengage DB можно опустить выражение FROM, что позволяет легко вычислять результаты простых выражений. Например:

SELECT 2+2;

В некоторых других SQL-базах данных это невозможно — требуется использовать фиктивную таблицу с одной строкой, из которой затем выполняется запрос SELECT.

Обратите внимание, что если выражение FROM не указано, запрос не сможет ссылаться ни на какие таблицы базы данных. Например, следующий запрос является недопустимым:

SELECT distributors.* WHERE distributors.name = 'Westward';

Необязательное ключевое слово AS

В стандарте SQL необязательное ключевое слово AS можно опускать перед именем выходного столбца, если новое имя столбца является допустимым именем столбца (то есть не совпадает ни с одним зарезервированным ключевым словом). Greengage DB немного более строг: AS требуется, если новое имя столбца совпадает с любым ключевым словом, зарезервированным или нет. Рекомендуется использовать AS или имена выходных столбцов в двойных кавычках, чтобы предотвратить возможные конфликты с будущими добавлениями ключевых слов.

В списке FROM как стандартная база данных, так и Greengage DB позволяют опускать AS перед псевдонимом, являющимся незарезервированным ключевым словом. Однако это не подходит для имен выходных столбцов из-за синтаксической неоднозначности.

ONLY и наследование

В соответствии со стандартом SQL, при написании ONLY имя таблицы должно заключаться в скобки, например:

SELECT * FROM ONLY (tab1), ONLY (tab2) WHERE ...

В Greengage DB эти скобки считаются необязательными.

В Greengage DB допускается добавление символа * в конце, чтобы явно указать, что дочерние таблицы включаются в обработку. Стандарт не позволяет этого.

Эти положения в равной степени относятся ко всем командам SQL, поддерживающим опцию ONLY.

Пространства имен в GROUP BY и ORDER BY

В стандарте SQL-92 выражение ORDER BY может содержать ссылки только на выходные столбцы, тогда как GROUP BY может содержать выражения с именами только входных столбцов. Greengage DB расширяет оба этих выражения, допуская также другие варианты (но использует интерпретацию стандарта в случае неоднозначности). Greengage DB также позволяет в обоих предложениях указывать произвольные выражения. Обратите внимание, что имена, фигурирующие в выражении, всегда рассматриваются как имена входных, а не выходных столбцов.

В SQL:1999 и более поздних версиях используется несколько иное определение, которое не полностью совместимо с SQL-92. Однако в большинстве случаев Greengage DB интерпретирует выражения ORDER BY и GROUP BY так, как требует SQL:1999.

Функциональные зависимости

Greengage DB распознает функциональную зависимость (позволяя опускать столбцы в GROUP BY) только в том случае, если первичный ключ таблицы включен в список GROUP BY. Стандарт SQL определяет дополнительные условия, которые должны быть учтены.

LIMIT и OFFSET

Операторы LIMIT и OFFSET — синтаксис, специфичный для Greengage DB, поддерживаемый также в MySQL. В стандарте SQL:2008 для той же цели вводятся операторы OFFSET .. FETCH {FIRST|NEXT} …​, рассмотренные ранее. Этот синтаксис также используется в IBM DB2. В приложениях для Oracle для реализации действия этих операторов часто используется обходной путь с применением автоматически генерируемого столбца rownum, который отсутствует в Greengage DB.

FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE и FOR KEY SHARE

Хотя оператор FOR UPDATE присутствует в стандарте SQL, стандарт позволяет его использовать только в качестве опции оператора DECLARE CURSOR. Greengage DB допускает его использование в любом запросе SELECT, а также в подзапросах SELECT, но это является расширением. Варианты FOR NO KEY UPDATE, FOR SHARE и FOR KEY SHARE, а также опция NOWAIT в стандарте отсутствуют.

Изменение данных в WITH

В Greengage DB можно использовать INSERT, UPDATE и DELETE в качестве запросов WITH. Стандарт SQL этого не предусматривает.

Нестандартные выражения

В стандарте SQL не определено выражение DISTINCT ON.

Ограниченное использование функций STABLE и VOLATILE

Чтобы предотвратить рассинхронизацию данных между сегментами в Greengage DB, любая функция, классифицированная как STABLE или VOLATILE, не может быть запущена на уровне сегмента, если она содержит SQL или каким-либо образом изменяет базу данных. Дополнительную информацию можно посмотреть в статье CREATE FUNCTION.

См. также