×
Мы обрабатываем cookies, чтобы сделать наш сайт удобнее и персонализированнее для вас. Подробнее: политика использования «cookies» и «политики конфиденциальности».

Для самостоятельной настройки ознакомьтесь с инструкцией

Дополнительные настройки cookies в браузерах

Файлы cookie автоматически загружаются в ваш браузер при посещении веб-сайта. У вас есть возможность управлять этими файлами. Если Вы не согласны с использованием файлов cookies, запретите их сохранение на своём устройстве, удалите уже имеющиеся файлы cookies через настройки браузера или прекратите использование сайта.

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

Инструкция по отключению cookies
Принять
Настроить
Отклонить

ДОКУМЕНТАЦИЯ

Выберите версию, форк и язык для СУБД Digital Q.DataBase, чтобы прочитать или скачать всю документацию.
Техподдержка
Документация
Диасофт
Авторские права © 2016–2025 ООО "Диасофт Экосистема"
Скачать всю документацию:

2.5.15. Массивы

2.5.15.1. Объявление типов массивов
2.5.15.2. Ввод значений массивов
2.5.15.3. Доступ к массивам
2.5.15.4. Изменение массивов
2.5.15.5. Поиск в массивах
2.5.15.6. Синтаксис ввода и вывода массивов

Digital Q.DataBase позволяет определять столбцы таблицы как многомерные массивы переменной длины. Допускается создание массивов любого встроенного или пользовательского базового типа, перечисляемого типа, составного типа, диапазонного типа или домена.

2.5.15.1. Объявление типов массивов #

Для иллюстрации использования типов массивов создается следующая таблица:

CREATE TABLE sal_emp (
    name            text,
    pay_by_quarter  integer[],
    schedule        text[][]
);

Как показано в примере, имя типа данных массива образуется путем добавления квадратных скобок ([]) к имени типа элементов массива. Приведенная выше команда создаст таблицу с именем sal_emp со столбцом типа text (name), а также одномерным массивом типа integer (pay_by_quarter), представляющий заработную плату сотрудника по кварталам, и двумерный массив text (schedule), представляющий еженедельный график сотрудника.

Синтаксис команды CREATE TABLE позволяет указывать точный размер массивов, например:

CREATE TABLE tictactoe (
    squares   integer[3][3]
);

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

В текущей реализации также не контролируется соблюдение объявленного количества измерений. Все массивы с определенным типом элементов считаются массивами одного типа независимо от их размера или количества измерений. Таким образом, указание размера массива или количества его измерений в CREATE TABLE является лишь документированием; это не влияет на поведение системы во время выполнения.

Альтернативный синтаксис, соответствующий стандарту SQL благодаря использованию ключевого слова ARRAY, можно использовать для одномерных массивов. pay_by_quarter можно было бы определить следующим образом:

    pay_by_quarter  integer ARRAY[4],

Или, если размер массива не указывается:

    pay_by_quarter  integer ARRAY,

Однако, как и прежде, Digital Q.DataBase в любом случае не ограничивает размер.

2.5.15.2. Ввод значений массивов #

Для записи значения массива в виде литеральной константы значения элементов заключаются в фигурные скобки и разделяются запятыми. (В языке C аналогичный синтаксис используется для инициализации структур.) Любое значение элемента можно заключить в двойные кавычки; это необходимо сделать, если оно содержит запятые или фигурные скобки. (Более подробная информация приведена ниже.) Таким образом, константа массива имеет следующий общий формат:

'{ val1 delim val2 delim ... }'

где delim является символом-разделителем для данного типа, согласно записи в его pg_type записи. Среди стандартных типов данных, представленных в Digital Q.DataBase дистрибутиве, во всех используется запятая (,), за исключением типа box в котором используется точка с запятой (;). Каждое val представляет собой либо константу типа элементов массива, либо подмассив. Пример константы массива:

'{{1,2,3},{4,5,6},{7,8,9}}'

Данная константа представляет собой двумерный массив 3x3, состоящий из трех подмассивов целых чисел.

Чтобы присвоить элементу константы массива значение NULL, необходимо записать NULL в качестве значения элемента. (Допускается любой вариант написания NULL в верхнем или нижнем регистре.) Если требуется использовать фактическое строковое значение «NULL», его необходимо заключить в двойные кавычки.

(Подобные константы массивов фактически являются лишь частным случаем констант общих типов, рассматриваемых в Раздел 2.1.1.2.7. Константа изначально обрабатывается как строка и передается процедуре преобразования входных данных массива. (Может потребоваться явное указание типа.)

Ниже приведены несколько операторов INSERT:

INSERT INTO sal_emp
    VALUES ('Билл',
    '{10000, 10000, 10000, 10000}',
    '{{"meeting", "lunch"}, {"training", "presentation"}}');

INSERT INTO sal_emp
    VALUES ('Кэрол',
    '{20000, 25000, 25000, 25000}',
    '{{"breakfast", "consulting"}, {"meeting", "lunch"}}');

Результат выполнения двух предыдущих операций вставки выглядит следующим образом:

SELECT * FROM sal_emp;
 name  |      pay_by_quarter       |                 schedule
-------+---------------------------+-------------------------------------------
 Билл  | {10000,10000,10000,10000} | {{meeting,lunch},{training,presentation}}
 Кэрол | {20000,25000,25000,25000} | {{breakfast,consulting},{meeting,lunch}}
(2 rows)

Многомерные массивы должны иметь одинаковую длину по каждой размерности. Несоответствие размерностей приводит к ошибке, например:

INSERT INTO sal_emp
    VALUES ('Билл',
    '{10000, 10000, 10000, 10000}',
    '{{"meeting", "lunch"}, {"meeting"}}');
ERROR:  malformed array literal: "{{"meeting", "lunch"}, {"meeting"}}"
DETAIL:  Multidimensional arrays must have sub-arrays with matching dimensions.

Также можно использовать синтаксис ARRAY конструктора:

INSERT INTO sal_emp
    VALUES ('Билл',
    ARRAY[10000, 10000, 10000, 10000],
    ARRAY[['meeting', 'lunch'], ['training', 'presentation']]);

INSERT INTO sal_emp
    VALUES ('Кэрол',
    ARRAY[20000, 25000, 25000, 25000],
    ARRAY[['breakfast', 'consulting'], ['meeting', 'lunch']]);

Следует отметить, что элементы массива являются обычными SQL-константами или выражениями; например, строковые литералы заключаются в одинарные кавычки, а не в двойные, как в литерале массива. ARRAY Синтаксис конструктора более подробно рассматривается в Раздел 2.1.2.12.

2.5.15.3. Доступ к массивам #

Теперь можно выполнить несколько запросов к таблице. Сначала будет показано, как получить доступ к одному элементу массива. Данный запрос извлекает имена сотрудников, чья оплата изменилась во втором квартале:

SELECT name FROM sal_emp WHERE pay_by_quarter[1] <> pay_by_quarter[2];

 name
-------
 Кэрол
(1 row)

Индексы массива записываются в квадратных скобках. По умолчанию Digital Q.DataBase используется соглашение о нумерации элементов массива, начинающейся с единицы, то есть массив из n элементов начинается с array[1] и заканчивается array[n].

Данный запрос извлекает значение оплаты за третий квартал для всех сотрудников:

SELECT pay_by_quarter[3] FROM sal_emp;

 pay_by_quarter
----------------
          10000
          25000
(2 строки)

Также можно обращаться к произвольным прямоугольным срезам массива или подмассивам. Срез массива обозначается путем указания нижняя-граница:верхняя-граница для одного или нескольких измерений массива. Например, данный запрос извлекает первый пункт в расписании Билла для первых двух дней недели:

SELECT schedule[1:2][1:1] FROM sal_emp WHERE name = 'Bill';

        schedule
------------------------
 {{meeting},{training}}
(1 строка)

Если какое-либо измерение записано как срез (т. е. содержит двоеточие), то все измерения рассматриваются как срезы. Любое измерение, содержащее только одно число (без двоеточия), рассматривается как диапазон от 1 до указанного числа. Например, [2] рассматривается как [1:2], как в следующем примере:

SELECT schedule[1:2][2] FROM sal_emp WHERE name = 'Билл';

                 schedule
-------------------------------------------
 {{meeting,lunch},{training,presentation}}
(1 строка)

Во избежание путаницы со случаями, не являющимися срезами, лучше использовать синтаксис срезов для всех размерностей, например, [1:2][1:1], а не [2][1:1].

Можно опустить нижняя-граница и/или верхняя-граница спецификатора среза; отсутствующая граница заменяется нижней или верхней границей индексов массива. Например:

SELECT schedule[:2][2:] FROM sal_emp WHERE name = 'Билл';

        schedule
------------------------
 {{lunch},{presentation}}
(1 строка)

SELECT schedule[:][1:1] FROM sal_emp WHERE name = 'Билл';

        schedule
------------------------
 {{meeting},{training}}
(1 строка)

Выражение индекса массива возвращает null, если сам массив или любое из выражений индекса имеют значение null. Кроме того, значение null возвращается, если индекс выходит за границы массива (в этом случае ошибка не возникает). Например, если schedule в настоящий момент имеет размерности [1:3][1:2] то обращение к schedule[3][3] возвращает NULL. Аналогично, обращение к массиву с неверным количеством индексов возвращает NULL вместо ошибки.

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

Текущие размерности любого значения массива могут быть получены с помощью array_dims функции:

SELECT array_dims(schedule) FROM sal_emp WHERE name = 'Кэрол';

 array_dims
------------
 [1:2][1:2]
(1 строка)

array_dims формирует text результат, который удобен для чтения человеком, но, возможно, неудобен для программ. Размерности также можно получить с помощью функций array_upper и array_lower, возвращающих верхнюю и нижнюю границы указанной размерности массива соответственно:

SELECT array_upper(schedule, 1) FROM sal_emp WHERE name = 'Кэрол';

 array_upper
-------------
           2
(1 row)

array_length возвращает длину указанной размерности массива:

SELECT array_length(schedule, 1) FROM sal_emp WHERE name = 'Кэрол';

 array_length
--------------
            2
(1 row)

cardinality возвращает общее количество элементов в массиве по всем размерностям. Фактически это количество строк, которое было бы получено в результате вызова unnest would yield:

SELECT cardinality(schedule) FROM sal_emp WHERE name = 'Кэрол';

 cardinality
-------------
           4
(1 row)

2.5.15.4. Изменение массивов #

Значение массива можно заменить полностью:

UPDATE sal_emp SET pay_by_quarter = '{25000,25000,27000,27000}'
    WHERE name = 'Кэрол';

или с использованием ARRAY синтаксиса выражений:

UPDATE sal_emp SET pay_by_quarter = ARRAY[25000,25000,27000,27000]
    WHERE name = 'Кэрол';

В массиве также можно обновить один элемент:

UPDATE sal_emp SET pay_by_quarter[4] = 15000
    WHERE name = 'Билл';

или обновить срез данных:

UPDATE sal_emp SET pay_by_quarter[1:2] = '{27000,27000}'
    WHERE name = 'Кэрол';

Синтаксис срезов с опущенными нижняя-граница и/или верхняя-граница параметрами также можно использовать, но только при обновлении значения массива, не являющегося NULL или нульмерным (в противном случае отсутствует существующая граница индекса для подстановки).

Хранимое значение массива можно увеличить, присвоив значения элементам, которые еще не существуют. Любые позиции между ранее существовавшими и новыми элементами будут заполнены значениями null. Например, если массив myarray в данный момент содержит 4 элемента, то после обновления, в ходе которого значение присваивается myarray[6]; myarray[5] будет содержать null. В настоящее время расширение таким способом допускается только для одномерных массивов и не разрешено для многомерных.

Присваивание с использованием индексов позволяет создавать массивы, в которых не применяется индексация с единицы. Например, можно указать myarray[-2:7] для создания массива со значениями индексов от -2 до 7.

Новые значения массива также можно создавать с помощью оператора конкатенации, ||:

SELECT ARRAY[1,2] || ARRAY[3,4];
 ?column?
-----------
 {1,2,3,4} (1 строка)  SELECT ARRAY[5,6] || ARRAY[[1,2],[3,4]];       ?column?
---------------------
 {{5,6},{1,2},{3,4}}
(1 строка)

Оператор конкатенации позволяет добавлять один элемент в начало или в конец одномерного массива. Он также может принимать два N-мерных массива, или N-мерный и N+1-мерный массив.

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

SELECT array_dims(1 || '[0:1]={2,3}'::int[]);
 array_dims
------------
 [0:2]
(1 строка)

SELECT array_dims(ARRAY[1,2] || 3);
 array_dims
------------
 [1:3]
(1 строка)

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

SELECT array_dims(ARRAY[1,2] || ARRAY[3,4,5]);
 array_dims
------------
 [1:5]
(1 строка)

SELECT array_dims(ARRAY[[1,2],[3,4]] || ARRAY[[5,6],[7,8],[9,0]]);
 array_dims
------------
 [1:5][1:2]
(1 строка)

Когда N-мерный массив добавляется в начало или конец N+1-мерного массива, результат является аналогичным вышеописанному случаю «элемент-массив». Каждый N-мерный подмассив по сути является элементом N+1-мерного внешнего измерения массива. Например:

SELECT array_dims(ARRAY[1,2] || ARRAY[[3,4],[5,6]]);
 array_dims
------------
 [1:3][1:2]
(1 строка)

Массив также можно сконструировать с помощью функций array_prepend, array_append, или array_cat. Первые две функции поддерживают только одномерные массивы, тогда как array_cat поддерживает многомерные массивы. Примеры:

SELECT array_prepend(1, ARRAY[2,3]);
 array_prepend
---------------
 {1,2,3}
(1 строка)

SELECT array_append(ARRAY[1,2], 3);
 array_append
--------------
 {1,2,3}
(1 строка)

SELECT array_cat(ARRAY[1,2], ARRAY[3,4]);
 array_cat
-----------
 {1,2,3,4}
(1 строка)

SELECT array_cat(ARRAY[[1,2],[3,4]], ARRAY[5,6]);
      array_cat
---------------------
 {{1,2},{3,4},{5,6}}
(1 строка)

SELECT array_cat(ARRAY[5,6], ARRAY[[1,2],[3,4]]);
      array_cat
---------------------
 {{5,6},{1,2},{3,4}}

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

SELECT ARRAY[1, 2] || '{3, 4}';  -- нетипизированный литерал воспринимается как массив
 ?column?
-----------
 {1,2,3,4}

SELECT ARRAY[1, 2] || '7';                 -- как и в этом случае
ERROR:  malformed array literal: "7"

SELECT ARRAY[1, 2] || NULL;                -- как и нетипизированный NULL
 ?column?
----------
 {1,2}
(1 row)

SELECT array_append(ARRAY[1, 2], NULL);    -- возможно, подразумевалось следующее
 array_append
--------------
 {1,2,NULL}

В приведенных выше примерах анализатор обнаруживает массив целых чисел с одной стороны оператора конкатенации и константу неопределенного типа с другой. Используемая эвристика для определения типа константы заключается в предположении, что она имеет тот же тип, что и другой входной аргумент оператора, в данном случае — целочисленный массив. Таким образом, предполагается, что оператор конкатенации представляет собой array_cat, а не array_append. В случаях, когда данный выбор оказывается неверным, это можно исправить путем приведения константы к типу элементов массива; однако явное использование array_append может стать предпочтительным решением.

2.5.15.5. Поиск в массивах #

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

SELECT * FROM sal_emp WHERE pay_by_quarter[1] = 10000 OR
                            pay_by_quarter[2] = 10000 OR
                            pay_by_quarter[3] = 10000 OR
                            pay_by_quarter[4] = 10000;

Однако для больших массивов этот способ быстро становится трудоемким и не подходит, если размер массива неизвестен. Альтернативный метод описан в Раздел 2.6.25. Приведенный выше запрос может быть заменен следующим:

SELECT * FROM sal_emp WHERE 10000 = ANY (pay_by_quarter);

Кроме того, найти строки, в которых все значения массива равны 10000, можно с помощью:

SELECT * FROM sal_emp WHERE 10000 = ALL (pay_by_quarter);

В качестве альтернативы может быть использована generate_subscripts функция. Например:

SELECT * FROM
   (SELECT pay_by_quarter,
           generate_subscripts(pay_by_quarter, 1) AS s
      FROM sal_emp) AS foo
 WHERE pay_by_quarter[s] = 10000;

Данная функция описана в Таблица 2.6.68.

Также поиск в массиве можно осуществить с помощью оператора && , который проверяет наличие пересечений левого операнда с правым. Например:

SELECT * FROM sal_emp WHERE pay_by_quarter && ARRAY[10000];

Этот и другие операторы для работы с массивами подробно описаны в Раздел 2.6.19. Данный процесс может быть ускорен при помощи соответствующего индекса, как описано в Раздел 2.8.2.

Также поиск определенных значений в массиве можно осуществлять с использованием array_position и array_positions функций. Первая функция возвращает индекс первого вхождения значения в массиве; вторая возвращает массив с индексами всех вхождений значения в массиве. Например:

SELECT array_position(ARRAY['sun','mon','tue','wed','thu','fri','sat'], 'mon');
 array_position
----------------
              2
(1 row)

SELECT array_positions(ARRAY[1, 4, 3, 1, 3, 4, 2, 1], 1);
 array_positions
-----------------
 {1,4,8}
(1 row)

Подсказка

Массивы не являются множествами; поиск конкретных элементов массива может свидетельствовать о неверном проектировании базы данных. Рекомендуется рассмотреть возможность использования отдельной таблицы, в которой для каждого элемента массива будет выделена отдельная строка. Это упростит поиск и, вероятно, обеспечит лучшую масштабируемость при большом количестве элементов.

2.5.15.6. Синтаксис ввода и вывода массивов #

Внешнее текстовое представление значения массива состоит из элементов, интерпретируемых согласно правилам преобразования ввода-вывода для соответствующего типа элементов, и дополнительного оформления, обозначающего структуру массива. Оформление состоит из фигурных скобок ({ и }) вокруг значения массива и символов-разделителей между соседними элементами. В качестве разделителя обычно используется запятая (,), но может использоваться и другой символ: он определяется параметром typdelim в настройках типа элементов массива. Среди стандартных типов данных, представленных в составе Digital Q.DataBase дистрибутива, во всех используется запятая, за исключением типа box, для которого используется точка с запятой (;). В многомерном массиве для каждого измерения (строка, плоскость, куб и т. д.) предусматривается свой уровень фигурных скобок, а разделители должны указываться между соседними элементами в фигурных скобках одного уровня.

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

По умолчанию значение индекса нижней границы размерностей массива устанавливается равным единице. Чтобы представить массивы с другими нижними границами, диапазоны индексов массива можно явно указать перед записью содержимого массива. Это оформление состоит из квадратных скобок ([]) вокруг нижней и верхней границ каждой размерности массива с двоеточием (:) в качестве символа-разделителя между ними. После оформления размерностей массива следует знак равенства (=). Например:

SELECT f1[1][-2][3] AS e1, f1[1][-1][5] AS e2
 FROM (SELECT '[1:1][-2:-1][3:5]={{{1,2,3},{4,5,6}}}'::int[] AS f1) AS ss;

 e1 | e2
----+----
  1 |  6
(1 row)

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

Если записываемое значение элемента соответствует NULL (в любом регистре), то элемент воспринимается как NULL. Использование кавычек или обратных косых черт отменяет это правило и позволяет вводить строковый литерал «NULL» to be entered. Кроме того, для обратной совместимости с версиями Digital Q.DataBaseдо 8.2 включительно, array_nulls параметр конфигурации может быть изменен выключено для подавления распознавания NULL в качестве NULL.

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

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

Подсказка

Синтаксис ARRAY конструктора (см. Раздел 2.1.2.12) зачастую более удобен при написании значений массивов в командах SQL, чем синтаксис литералов массива. В ARRAYзначения отдельных элементов записываются так же, как и в тех случаях, когда они не являются членами массива.

Наверх
свяжитесь
с нами
контакты
Для прямой связи с нами вы можете использовать контакты ниже, либо оставить заявку через форму обратной связи, и мы обязательно свяжемся с вами

*поля обязательные к заполнению