Выражения значений используются в различных контекстах, например в целевом списке SELECT
команды, в качестве новых значений столбца в INSERT
или UPDATE
или в условиях поиска в ряде команд. Результат выражения значения иногда называют скаляром , чтобы отличить его от результата табличного выражения (которое является таблицей). Поэтому выражения значений также называются скалярными выражениями (или даже просто выражениями ). Синтаксис выражения позволяет вычислять значения из примитивных частей с помощью арифметических, логических операций, операций над множествами и других.
Выражение значения может быть одним из следующих:
- Постоянное или буквальное значение
- Ссылка на столбец
- Ссылка на позиционный параметр в теле определения функции или подготовленного оператора.
- Выражение с индексом
- Выражение выбора поля
- Вызов оператора
- Вызов функции
- Агрегатное выражение
- Вызов оконной функции
- Приведение типа
- Выражение сопоставления
- Скалярный подзапрос
- Конструктор массива
- Конструктор строк
- Другое выражение значения в круглых скобках (используется для группировки подвыражений и переопределения приоритета)
Ссылки на столбцы
На столбец можно ссылаться в форме:
correlation.columnname
correlation
— это имя таблицы (возможно, дополненное именем схемы) или псевдоним для таблицы, определенной с помощью FROM
предложения. Имя корреляции и разделяющую точку можно не указывать, если имя столбца уникально во всех таблицах, используемых в текущем запросе.
Позиционные параметры
Ссылка на позиционный параметр используется для указания значения, которое предоставляется извне для оператора SQL. Параметры используются в определениях функций SQL и в подготовленных запросах. Некоторые клиентские библиотеки также поддерживают указание значений данных отдельно от командной строки SQL, и в этом случае параметры используются для ссылки на внешние значения данных. Форма ссылки на параметр:
$number
Например, рассмотрим определение функции dept
, как:
CREATE FUNCTION dept(text) RETURNS dept
AS $$ SELECT * FROM dept WHERE name = $1 $$
LANGUAGE SQL;
Здесь $1
ссылается на значение первого аргумента функции всякий раз, когда вызывается функция.
Индексы
Если выражение возвращает значение типа массива, то конкретный элемент значения массива можно извлечь, написав
expression[ subscript]
или несколько соседних элементов ( « срез массива » ) можно извлечь, написав
expression[ lower_subscript: upper_subscript]
(Здесь скобки [ ]
должны появляться буквально.) Каждое subscript
само по себе является выражением, которое будет округлено до ближайшего целого числа.
Как правило, массив expression
должен быть заключен в круглые скобки, но круглые скобки могут быть опущены, если выражение, которое должно быть индексировано, является просто ссылкой на столбец или позиционным параметром. Кроме того, несколько индексов могут быть объединены, если исходный массив является многомерным. Например:
mytable.arraycolumn[4]
mytable.two_d_column[17][34]
$1[10:42]
(arrayfunction(a,b))[42]
Скобки в последнем примере обязательны.
Выбор поля
Если выражение возвращает значение составного типа (типа строки), то конкретное поле строки можно извлечь, написав
expression.fieldname
Как правило, строка expression
должна быть заключена в круглые скобки, но круглые скобки могут быть опущены, если выражение, из которого нужно выбрать, является просто ссылкой на таблицу или позиционным параметром. Например:
mytable.mycolumn
$1.somecolumn
(rowfunction(a,b)).col3
(Таким образом, уточненная ссылка на столбец на самом деле является частным случаем синтаксиса выбора поля.) Важным частным случаем является извлечение поля из столбца таблицы составного типа:
(compositecol).somefield
(mytable.compositecol).somefield
Круглые скобки здесь необходимы, чтобы показать, что compositecol
это имя столбца, а не имя таблицы, или что mytable
во втором случае это имя таблицы, а не имя схемы.
Вы можете запросить все поля составного значения, написав .*
:
(compositecol).*
Вызовы оператора
Существует два возможных синтаксиса для вызова оператора:
expression operator expression (бинарный инфиксный оператор) |
operator expression (унарный префиксный оператор) |
где operator
является одним из ключевых слов AND
, OR
и NOT
, или является квалифицированным именем оператора в форме:
OPERATOR(schema.operatorname)
Какие конкретные операторы существуют и являются ли они унарными или бинарными, зависит от того, какие операторы были определены системой или пользователем.
Вызовы функций
Синтаксис вызова функции — это имя функции (возможно, дополненное именем схемы), за которым следует список ее аргументов, заключенный в круглые скобки:
function_name([ expression[ , expression... ] ] )
Например, следующий код вычисляет квадратный корень из 2:
sqrt(2)
Агрегированные выражения
Агрегатное выражение представляет собой применение агрегатной функции к строкам, выбранным запросом. Агрегатная функция сводит несколько входных данных к одному выходному значению, такому как сумма или среднее значение входных данных. Синтаксис агрегатного выражения может быть одним из следующих:
aggregate_name (expression [ , ... ] [ order_by_clause ] ) [ FILTER ( WHERE filter_clause ) ]
aggregate_name (ALL expression [ , ... ] [ order_by_clause ] ) [ FILTER ( WHERE filter_clause ) ]
aggregate_name (DISTINCT expression [ , ... ] [ order_by_clause ] ) [ FILTER ( WHERE filter_clause ) ]
aggregate_name ( * ) [ FILTER ( WHERE filter_clause ) ]
aggregate_name ( [ expression [ , ... ] ] ) WITHIN GROUP ( order_by_clause ) [ FILTER ( WHERE filter_clause ) ]
где aggregate_name
— предварительно определенный агрегат (возможно, дополненный именем схемы) и expression
любое выражение значения, которое само по себе не содержит агрегатного выражения или вызова оконной функции. Необязательные order_by_clause
и filter_clause
описаны ниже.
Первая форма агрегатного выражения вызывает агрегат один раз для каждой входной строки. Вторая форма аналогична первой, так ALL
как используется по умолчанию. Третья форма вызывает агрегат один раз для каждого отдельного значения выражения (или отдельного набора значений для нескольких выражений), найденного во входных строках. Четвертая форма вызывает агрегат один раз для каждой входной строки; поскольку конкретное входное значение не указано, оно обычно полезно только для count(*)
агрегатной функции. Последняя форма используется с агрегатными функциями упорядоченного набора , которые описаны ниже.
Большинство агрегатных функций игнорируют входные данные null, поэтому строки, в которых одно или несколько выражений дают null, отбрасываются. Можно предположить, что это верно, если не указано иное, для всех встроенных агрегатов.
Например, count(*)
дает общее количество входных строк; count(f1)
выдает количество входных строк, в которых f1
не равно NULL, поскольку значения NULL count
игнорируются; и count(distinct f1)
дает количество различных ненулевых значений f1
.
Обычно входные строки передаются агрегатной функции в неопределенном порядке. Во многих случаях это не имеет значения; например, min
выдает один и тот же результат независимо от порядка получения входных данных. Однако некоторые агрегатные функции (такие как array_agg
и string_agg
) выдают результаты, зависящие от порядка входных строк. При использовании такого агрегата order_by_clause
можно использовать необязательный параметр для указания желаемого порядка. Имеет тот order_by_clause
же синтаксис, что и предложение уровня запроса ORDER BY
, за исключением того, что его выражения всегда являются просто выражениями и не могут быть именами выходных столбцов или числами. Например:
SELECT array_agg(ORDER BY b DESC) FROM table;
Имея дело с агрегатными функциями с несколькими аргументами, обратите внимание, что ORDER BY
предложение идет после всех агрегатных аргументов. Например, напишите это:
SELECT string_agg(a, ',' ORDER BY a) FROM table;
не этот:
SELECT string_agg(a ORDER BY a, ',') FROM table; -- incorrect
Последнее синтаксически допустимо, но представляет собой вызов агрегатной функции с одним аргументом и двумя ORDER BY
ключами (второй довольно бесполезен, поскольку является константой).
Если DISTINCT
указано в дополнение к order_by_clause
, то все ORDER BY
выражения должны соответствовать обычным аргументам агрегата; то есть вы не можете сортировать по выражению, которое не включено в DISTINCT
список.
Размещение ORDER BY
в обычном списке аргументов агрегата, как описано выше, используется при упорядочении входных строк для агрегатов общего назначения и статистических агрегатов, для которых порядок необязателен. Существует подкласс агрегатных функций, называемых агрегатами с упорядоченным набором, для которых order_by_clause
требуется , обычно потому, что вычисление агрегата имеет смысл только с точки зрения определенного порядка его входных строк. Типичные примеры агрегатов с упорядоченным набором включают расчеты рангов и процентилей. Для агрегата с упорядоченным набором order_by_clause
внутри записывается WITHIN GROUP (...)
, как показано в последнем варианте синтаксиса выше. Выражения order_by_clause
оцениваются один раз для каждой входной строки, как и обычные агрегатные аргументы, отсортированные в соответствии сorder_by_clause
требования и передаются агрегатной функции в качестве входных аргументов. (Это отличается от случая не- WITHIN GROUP
order_by_clause
, который не рассматривается как аргумент(ы) агрегатной функции.) Выражения аргументов, предшествующие WITHIN GROUP
, если они есть, называются прямыми аргументами , чтобы отличить их от агрегированных аргументов, перечисленных в order_by_clause
. В отличие от обычных агрегатных аргументов, прямые аргументы оцениваются только один раз для каждого агрегатного вызова, а не один раз для каждой входной строки. Это означает, что они могут содержать переменные, только если эти переменные сгруппированы поGROUP BY
; это ограничение такое же, как если бы прямые аргументы вообще не находились внутри агрегатного выражения. Прямые аргументы обычно используются для таких вещей, как доли процентилей, которые имеют смысл только как одно значение для каждого вычисления агрегации. Список прямых аргументов может быть пустым; в этом случае пишите просто ()
не (*)
. ( PostgreSQL на самом деле принимает любое написание, но только первый вариант соответствует стандарту SQL.)
Пример агрегатного вызова упорядоченного набора:
SELECT percentile_cont(0.5) WITHIN GROUP (ORDER BY income) FROM households;
percentile_cont
-----------------
50489
который получает 50-й процентиль или медиану значения income
столбца из таблицы households
. Здесь 0.5
прямой аргумент; было бы бессмысленно, чтобы доля процентиля была значением, меняющимся в разных строках.
Если FILTER
указано, то filter_clause
в агрегатную функцию передаются только те входные строки, для которых значение true; другие строки отбрасываются. Например:
SELECT
count(*) AS unfiltered,
count(*) FILTER (WHERE i < 5) AS filtered
FROM generate_series(1,10) AS s(i);
unfiltered | filtered
------------+----------
10 | 4
(1 row)
Другие агрегатные функции могут быть добавлены пользователем.
Агрегатное выражение может отображаться только в списке результатов или HAVING
предложении SELECT
команды. Это запрещено в других предложениях, таких как WHERE
, потому что эти предложения логически оцениваются до того, как будут сформированы результаты агрегатов.
Когда агрегатное выражение появляется в подзапросе, агрегат обычно вычисляется по строкам подзапроса. Но возникает исключение, если аргументы агрегата (и filter_clause
если они есть) содержат только переменные внешнего уровня: тогда агрегат принадлежит ближайшему такому внешнему уровню и оценивается по строкам этого запроса. Совокупное выражение в целом является внешней ссылкой для подзапроса, в котором оно появляется, и действует как константа при любой оценке этого подзапроса. Ограничение появления только в списке результатов или HAVING
предложении применяется в отношении уровня запроса, к которому принадлежит агрегат.
Вызовы оконных функций
Вызов оконной функции представляет собой применение агрегатной функции к некоторой части строк, выбранных запросом. В отличие от неоконных агрегатных вызовов, это не связано с группировкой выбранных строк в одну строку вывода — каждая строка остается отдельной в выводе запроса. Однако оконная функция имеет доступ ко всем строкам, которые должны быть частью группы текущей строки в соответствии со спецификацией группировки ( PARTITION BY
list ) вызова оконной функции. Синтаксис вызова оконной функции может быть одним из следующих:
function_name ([expression [, expression ... ]]) [ FILTER ( WHERE filter_clause ) ] OVER window_name
function_name ([expression [, expression ... ]]) [ FILTER ( WHERE filter_clause ) ] OVER ( window_definition )
function_name ( * ) [ FILTER ( WHERE filter_clause ) ] OVER window_name
function_name ( * ) [ FILTER ( WHERE filter_clause ) ] OVER ( window_definition )
где window_definition
синтаксис
[ existing_window_name ]
[ PARTITION BY expression [, ...] ]
[ ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...] ]
[ frame_clause ]
Необязательным frame_clause
может быть один из
{ RANGE | ROWS | GROUPS } frame_start [ frame_exclusion ]
{ RANGE | ROWS | GROUPS } BETWEEN frame_start AND frame_end [ frame_exclusion ]
где frame_start
и frame_end
может быть одним из
UNBOUNDED PRECEDING
offset PRECEDING
CURRENT ROW
offset FOLLOWING
UNBOUNDED FOLLOWING
и frame_exclusion
может быть одним из
EXCLUDE CURRENT ROW
EXCLUDE GROUP
EXCLUDE TIES
EXCLUDE NO OTHERS
Здесь expression
представляет любое выражение значения, которое само по себе не содержит вызовов оконных функций.
window_name
является ссылкой на спецификацию именованного окна, определенную в предложении запроса WINDOW
. В качестве альтернативы полное значение window_definition
может быть указано в круглых скобках с использованием того же синтаксиса, что и для определения именованного окна в WINDOW
предложении. Стоит отметить, что OVER wname
это не совсем эквивалентно OVER (wname ...)
; последнее подразумевает копирование и изменение определения окна и будет отклонено, если указанная спецификация окна включает предложение фрейма.
Предложение PARTITION BY
группирует строки запроса в разделы , которые обрабатываются оконной функцией отдельно. PARTITION BY
работает аналогично предложению уровня запроса GROUP BY
, за исключением того, что его выражения всегда являются просто выражениями и не могут быть именами выходных столбцов или числами. Без PARTITION BY
, все строки, созданные запросом, обрабатываются как один раздел. Предложение ORDER BY
определяет порядок, в котором строки раздела обрабатываются оконной функцией. Он работает аналогично предложению уровня запроса ORDER BY
, но также не может использовать имена или номера выходных столбцов. Без ORDER BY
строки обрабатываются в неопределенном порядке.
Задает frame_clause
набор строк, составляющих рамку окна , которая является подмножеством текущего раздела, для тех оконных функций, которые воздействуют на рамку, а не на весь раздел. Набор строк в кадре может варьироваться в зависимости от того, какая строка является текущей строкой. Рамка может быть указана в режиме RANGE
, ROWS
или GROUPS
; в каждом случае он проходит frame_start
от frame_end
. Если frame_end
опущено, конец по умолчанию равен CURRENT ROW
.
A frame_start
of UNBOUNDED PRECEDING
означает, что фрейм начинается с первой строки раздела, и аналогично означает frame_end
, UNBOUNDED FOLLOWING
что фрейм заканчивается последней строкой раздела.
В режиме RANGE
or GROUPS
a frame_start
of CURRENT ROW
означает, что кадр начинается с первой равноправной строки текущей строки (строка, которую предложение окна ORDER BY
сортирует как эквивалентную текущей строке), а a frame_end
of CURRENT ROW
означает, что кадр заканчивается последней равноправной строкой текущей строки. В ROWS
режиме CURRENT ROW
просто означает текущую строку.
В параметрах кадра и должно быть выражение, не содержащее никаких переменных, агрегатных функций или оконных функций. Значение зависит от режима кадра:offset
PRECEDINGoffset
FOLLOWINGoffsetoffset
- В
ROWS
режимеoffset
должно возвращаться ненулевое неотрицательное целое число, а параметр означает, что кадр начинается или заканчивается на указанное количество строк до или после текущей строки. - В
GROUPS
режимеoffset
снова должно возвращаться ненулевое, неотрицательное целое число, а параметр означает, что кадр начинает или заканчивает указанное количество групп одноранговых узлов до или после группы одноранговых элементов текущей строки, где группа одноранговых узлов представляет собой набор строки, которые эквивалентны вORDER BY
порядке. (Для использования режимаORDER BY
в определении окна должно быть предложение.)GROUPS
- В
RANGE
режиме эти параметры требуют, чтобы вORDER BY
предложении был указан ровно один столбец. Указываетoffset
максимальную разницу между значением этого столбца в текущей строке и его значением в предыдущих или последующих строках кадра. Тип данныхoffset
выражения зависит от типа данных столбца упорядочивания. Для числовых столбцов упорядочивания он обычно имеет тот же тип, что и столбец упорядочивания, но для столбцов упорядочивания даты и времени это типinterval
. Например, если столбец упорядочения имеет типdate
илиtimestamp
, можно написатьRANGE BETWEEN '1 day' PRECEDING AND '10 days' FOLLOWING
. Поoffset
-прежнему требуется, чтобы он был ненулевым и неотрицательным, хотя значение « неотрицательного » зависит от его типа данных.
В любом случае расстояние до конца фрейма ограничено расстоянием до конца раздела, так что для строк рядом с концами раздела фрейм может содержать меньше строк, чем где-либо еще.
Обратите внимание, что в обоих режимах ROWS
и эквивалентны . Это обычно выполняется и в режиме для соответствующего значения « zero » , специфичного для типа данных .GROUPS0 PRECEDING0 FOLLOWINGCURRENT ROWRANGE
Этот frame_exclusion
параметр позволяет исключить строки вокруг текущей строки из кадра, даже если они будут включены в соответствии с параметрами начала и конца кадра. EXCLUDE CURRENT ROW
исключает текущую строку из кадра. EXCLUDE GROUP
исключает из кадра текущую строку и ее упорядоченные одноранговые узлы. EXCLUDE TIES
исключает любые одноранговые элементы текущей строки из кадра, но не саму текущую строку. EXCLUDE NO OTHERS
просто явно указывает поведение по умолчанию, не исключающее текущую строку или ее одноранговые узлы.
Параметр кадрирования по умолчанию — RANGE UNBOUNDED PRECEDING
, то же самое, что и RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
. С помощью ORDER BY
этого кадра устанавливаются все строки от начала раздела до последнего ORDER BY
однорангового узла текущей строки. Без ORDER BY
, это означает, что все строки раздела включены в рамку окна, поскольку все строки становятся равными текущей строке.
Ограничения заключаются в том, что frame_start
не может быть UNBOUNDED FOLLOWING
, frame_end
не может быть UNBOUNDED PRECEDING
, и frame_end
выбор не может появиться в приведенном выше списке frame_start
и frame_end
вариантов раньше, чем frame_start
выбор — например , не разрешено. Но, например, разрешено, даже если он никогда не выберет ни одной строки.RANGE BETWEEN CURRENT ROW AND offset PRECEDINGROWS BETWEEN 7 PRECEDING AND 8 PRECEDING
Если FILTER
указано, то filter_clause
в оконную функцию передаются только те входные строки, для которых значение true; другие строки отбрасываются. Только оконные функции, которые являются агрегатами, принимают FILTER
предложение.
Другие оконные функции могут быть добавлены пользователем. Кроме того, в качестве оконной функции может использоваться любой встроенный или определяемый пользователем агрегат общего назначения или статистический агрегат. (Агрегаты упорядоченного набора и гипотетического набора в настоящее время не могут использоваться в качестве оконных функций.)
Использование синтаксисов *
используется для вызова агрегатных функций без параметров в качестве оконных функций, например count(*) OVER (PARTITION BY x ORDER BY y)
. Звездочка ( *
) обычно не используется для конкретных оконных функций. Специфичные для окна функции не разрешены DISTINCT
и ORDER BY
не могут использоваться в списке аргументов функции.
Вызовы оконных функций разрешены только в SELECT
списке и ORDER BY
предложении запроса.
Type Casts
Приведение типа определяет преобразование из одного типа данных в другой. PostgreSQL поддерживает два эквивалентных синтаксиса для приведения типов:
CAST ( expression AS type )
expression::type
Синтаксис CAST
соответствует SQL; синтаксис with ::
является историческим использованием PostgreSQL .
Когда приведение применяется к выражению значения известного типа, оно представляет собой преобразование типа во время выполнения. Приведение будет успешным, только если определена подходящая операция преобразования типа. Обратите внимание, что это немного отличается от использования приведения типов с константами. Приведение, примененное к неукрашенному строковому литералу, представляет собой начальное присвоение типа константному значению литерала, поэтому оно будет успешным для любого типа (если содержимое строкового литерала является приемлемым синтаксисом ввода для типа данных).
Явное приведение типа обычно можно опустить, если нет двусмысленности в отношении типа, который должно создавать выражение значения (например, когда оно присваивается столбцу таблицы); в таких случаях система автоматически применит приведение типов. Однако автоматическое приведение выполняется только для приведений, помеченных в системных каталогах как « Применить неявно » . Другие приведения должны вызываться с явным синтаксисом приведения. Это ограничение предназначено для предотвращения скрытого применения неожиданных преобразований.
Также можно указать приведение типа, используя синтаксис, подобный функциям:
typename( expression)
Однако это работает только для типов, имена которых также допустимы в качестве имен функций. Например, double precision
нельзя использовать таким образом, но float8
можно использовать эквивалент. Кроме того, имена interval
, time
и timestamp
могут использоваться таким образом только в том случае, если они заключены в двойные кавычки из-за синтаксических конфликтов. Таким образом, использование функционально-подобного синтаксиса приведения приводит к несоответствиям, и его, вероятно, следует избегать.
Выражения сопоставления
Предложение COLLATE
переопределяет сопоставление выражения. Он добавляется к выражению, к которому относится:
expr COLLATE collation
где collation
возможно идентификатор с указанием схемы. Предложение COLLATE
связывает сильнее, чем операторы; при необходимости можно использовать круглые скобки.
Если параметры сортировки не указаны явно, система базы данных либо получает параметры сортировки из столбцов, участвующих в выражении, либо по умолчанию использует параметры сортировки базы данных, если в выражении не участвует ни один столбец.
Два распространенных варианта использования COLLATE
предложения переопределяют порядок сортировки в ORDER BY
предложении, например:
SELECT a, b, c FROM tbl WHERE ... ORDER BY a COLLATE "C";
и переопределение сопоставления вызова функции или оператора, который имеет результаты, чувствительные к языковым настройкам, например:
SELECT * FROM tbl WHERE a > 'foo' COLLATE "C";
Обратите внимание, что в последнем случае COLLATE
предложение присоединяется к входному аргументу оператора, на который мы хотим воздействовать. Неважно, к какому аргументу вызова оператора или функции COLLATE
присоединено предложение, потому что параметры сортировки, применяемые оператором или функцией, определяются с учетом всех аргументов, а явное COLLATE
предложение переопределяет параметры сортировки всех других аргументов. (Однако присоединение несовпадающих COLLATE
предложений к более чем одному аргументу является ошибкой. Таким образом, это дает тот же результат, что и в предыдущем примере:
SELECT * FROM tbl WHERE a COLLATE "C" > 'foo';
Но это ошибка:
SELECT * FROM tbl WHERE (a > 'foo') COLLATE "C";
потому что он пытается применить сопоставление к результату >
оператора, который имеет несопоставляемый тип данных boolean
.
Скалярные подзапросы
Скалярный подзапрос — это обычный SELECT
запрос в круглых скобках, возвращающий ровно одну строку с одним столбцом. SELECT
Запрос выполняется, и единственное возвращаемое значение используется в выражении окружающего значения. Использование запроса, возвращающего более одной строки или более одного столбца, в качестве скалярного подзапроса является ошибкой. (Но если во время конкретного выполнения подзапрос не возвращает строк, ошибки нет; скалярный результат принимается равным нулю.) Подзапрос может ссылаться на переменные из окружающего запроса, которые будут действовать как константы во время любого вычисления. подзапроса.
Например, следующее находит самое большое городское население в каждом штате:
SELECT name, (SELECT max(pop) FROM cities WHERE cities.state = states.name)
FROM states;
Конструкторы массивов
Конструктор массива — это выражение, которое создает значение массива, используя значения для его элементов-членов. Простой конструктор массива состоит из ключевого слова ARRAY
, левой квадратной скобки [
, списка выражений (разделенных запятыми) для значений элементов массива и, наконец, правой квадратной скобки ]
. Например:
SELECT ARRAY[1,2,3+4];
array
---------
{1,2,7}
(1 row)
По умолчанию тип элемента массива является общим типом выражений-членов, определяемым по тем же правилам, что и конструкции for UNION
или CASE
Вы можете переопределить это, явно приведя конструктор массива к нужному типу, например:
SELECT ARRAY[1,2,22.7]::integer[];
array
----------
{1,2,23}
(1 row)
Это имеет тот же эффект, что и индивидуальное приведение каждого выражения к типу элемента массива.
Значения многомерного массива могут быть созданы с помощью конструкторов вложенных массивов. Во внутренних конструкторах ключевое слово ARRAY
можно опустить. Например, они дают тот же результат:
SELECT ARRAY[ARRAY[1,2], ARRAY[3,4]];
array
---------------
{{1,2},{3,4}}
(1 row)
SELECT ARRAY[[1,2],[3,4]];
array
---------------
{{1,2},{3,4}}
(1 row)
Поскольку многомерные массивы должны быть прямоугольными, внутренние конструкторы одного уровня должны создавать подмассивы одинаковых размеров. Любое приведение, примененное к внешнему ARRAY
конструктору, автоматически распространяется на все внутренние конструкторы.
Элементами конструктора многомерного массива могут быть все, что дает массив надлежащего вида, а не только подконструкция ARRAY
. Например:
CREATE TABLE arr(f1 int[], f2 int[]);
INSERT INTO arr VALUES (ARRAY[[1,2],[3,4]], ARRAY[[5,6],[7,8]]);
SELECT ARRAY[f1, f2, '{{9,10},{11,12}}'::int[]] FROM arr;
array
------------------------------------------------
{{{1,2},{3,4}},{{5,6},{7,8}},{{9,10},{11,12}}}
(1 row)
Вы можете создать пустой массив, но, поскольку массив без типа невозможен, вы должны явно привести пустой массив к желаемому типу. Например:
SELECT ARRAY[]::integer[];
array
-------
{}
(1 row)
Также возможно построить массив из результатов подзапроса. В этой форме конструктор массива записывается с ключевым словом ARRAY
, за которым следует заключенный в круглые скобки (не заключенный в квадратные скобки) подзапрос. Например:
SELECT ARRAY(SELECT oid FROM pg_proc WHERE proname LIKE 'bytea%');
array
------------------------------------------------------------------
{2011,1954,1948,1952,1951,1244,1950,2005,1949,1953,2006,31,2412}
(1 row)
SELECT ARRAY(SELECT ARRAY[i, i*2] FROM generate_series(1,5) AS a(i));
array
----------------------------------
{{1,2},{2,4},{3,6},{4,8},{5,10}}
(1 row)
Подзапрос должен возвращать один столбец. Если выходной столбец подзапроса имеет тип, отличный от массива, результирующий одномерный массив будет иметь элемент для каждой строки в результате подзапроса с типом элемента, соответствующим типу выходного столбца подзапроса. Если выходной столбец подзапроса имеет тип массива, результатом будет массив того же типа, но с одним более высоким измерением; в этом случае все строки подзапроса должны давать массивы одинаковой размерности, иначе результат не будет прямоугольным.
Нижние индексы значения массива, построенного с помощью, ARRAY
всегда начинаются с единицы.
Конструкторы строк
Конструктор строк — это выражение, которое создает значение строки (также называемое составным значением), используя значения для его полей-членов. Конструктор строки состоит из ключевого слова ROW
, левой скобки, нуля или более выражений (разделенных запятыми) для значений поля строки и, наконец, правой скобки. Например:
SELECT ROW(1,2.5,'this is a test');
Ключевое слово ROW
является необязательным, если в списке более одного выражения.
Конструктор строки может включать синтаксис , который будет расширен до списка элементов значения строки, как это происходит, когда синтаксис используется на верхнем уровне списка. Например, если в таблице есть столбцы и , они одинаковы:rowvalue.*.*SELECTtf1f2
SELECT ROW(t.*, 42) FROM t;
SELECT ROW(t.f1, t.f2, 42) FROM t;
По умолчанию значение, созданное ROW
выражением, относится к типу анонимной записи. При необходимости его можно привести к именованному составному типу — либо к типу строки таблицы, либо к составному типу, созданному с помощью CREATE TYPE AS
. Чтобы избежать двусмысленности, может потребоваться явное приведение типов. Например:
CREATE TABLE mytable(f1 int, f2 float, f3 text);
CREATE FUNCTION getf1(mytable) RETURNS int AS 'SELECT $1.f1' LANGUAGE SQL;
-- No cast needed since only one getf1() exists
SELECT getf1(ROW(1,2.5,'this is a test'));
getf1
-------
1
(1 row)
CREATE TYPE myrowtype AS (f1 int, f2 text, f3 numeric);
CREATE FUNCTION getf1(myrowtype) RETURNS int AS 'SELECT $1.f1' LANGUAGE SQL;
-- Now we need a cast to indicate which function to call:
SELECT getf1(ROW(1,2.5,'this is a test'));
ERROR: function getf1(record) is not unique
SELECT getf1(ROW(1,2.5,'this is a test')::mytable);
getf1
-------
1
(1 row)
SELECT getf1(CAST(ROW(11,'this is a test',2.5) AS myrowtype));
getf1
-------
11
(1 row)
Конструкторы строк можно использовать для создания составных значений, которые будут храниться в столбце таблицы составного типа или передаваться в функцию, которая принимает составной параметр. Кроме того, можно сравнить два значения строки или проверить строку с помощью IS NULL
или IS NOT NULL
, например:
SELECT ROW(1,2.5,'this is a test') = ROW(1, 3, 'not the same');
SELECT ROW(table.*) IS NULL FROM table; -- detect all-null rows
Правила оценки выражений
Порядок вычисления подвыражений не определен. В частности, входные данные оператора или функции не обязательно оцениваются слева направо или в любом другом фиксированном порядке.
Более того, если результат выражения можно определить, вычислив только некоторые его части, то другие подвыражения могут вообще не вычисляться. Например, если кто-то написал:
SELECT true OR somefunc();
тогда somefunc()
бы (вероятно) вообще не вызывали. То же самое было бы, если бы кто-то написал:
SELECT somefunc() OR true;
Обратите внимание, что это не то же самое, что « замыкание » булевых операторов слева направо, встречающееся в некоторых языках программирования.
Как следствие, неразумно использовать функции с побочными эффектами в составе сложных выражений. Особенно опасно полагаться на побочные эффекты или порядок оценки в пунктах WHERE
и HAVING
, поскольку эти пункты подвергаются значительной переработке в рамках разработки плана выполнения. Булевы выражения ( комбинации AND
/ OR
/ NOT
) в этих предложениях могут быть реорганизованы любым способом, допускаемым законами булевой алгебры.
Когда необходимо принудительно установить порядок вычислений, можно использовать CASE
конструкцию. Например, это ненадежный способ избежать деления на ноль в WHERE
предложении:
SELECT ... WHERE x > 0 AND y/x > 1.5;
Но это безопасно:
SELECT ... WHERE CASE WHEN x > 0 THEN y/x > 1.5 ELSE false END;
Конструкция CASE
, используемая таким образом, будет препятствовать попыткам оптимизации, поэтому это следует делать только при необходимости. (В этом конкретном примере было бы лучше обойти проблему, написав y > 1.5*x
вместо этого.)
CASE
Однако это не панацея от таких проблем. Одним из ограничений метода, показанного выше, является то, что он не препятствует раннему вычислению подвыражений-констант. Помеченные функции и операторы IMMUTABLE
могут быть оценены, когда запрос планируется, а не когда он выполняется. Таким образом, например
SELECT CASE WHEN x > 0 THEN x ELSE 1/0 END FROM tab;
вероятно, приведет к ошибке деления на ноль из-за того, что планировщик пытается упростить постоянное подвыражение, даже если каждая строка в таблице имеет x > 0
так, что ELSE
рука никогда не будет введена во время выполнения.
Хотя этот конкретный пример может показаться глупым, связанные случаи, которые явно не включают константы, могут возникать в запросах, выполняемых внутри функций, поскольку значения аргументов функций и локальных переменных могут быть вставлены в запросы как константы для целей планирования. Например, в функциях PL/pgSQL использование оператора -- дляIF
защиты THEN
рискованных ELSE
вычислений намного безопаснее, чем просто вложение его в CASE
выражение.
Другое ограничение того же типа состоит в том, что a CASE
не может предотвратить вычисление содержащегося в нем агрегатного выражения, поскольку агрегатные выражения вычисляются до того, как будут рассмотрены другие выражения в SELECT
списке или HAVING
предложении. Например, следующий запрос может вызвать ошибку деления на ноль, несмотря на то, что, казалось бы, он защищен от нее:
SELECT CASE WHEN min(employees) > 0
THEN avg(expenses / employees)
END
FROM departments;
Агрегаты min()
и avg()
вычисляются одновременно по всем входным строкам, поэтому, если какая employees
-либо строка равна нулю, ошибка деления на ноль произойдет до того, как появится возможность проверить результат min()
. Вместо этого используйте предложение WHERE
or FILTER
, чтобы предотвратить попадание проблемных входных строк в агрегатную функцию.
0 комментариев