JavaRush /Курсы /SQL SELF /Извлечение данных из массива: unnest(),

Извлечение данных из массива: unnest(), array_length(), array_position()

SQL SELF
35 уровень , 2 лекция
Открыта

Работа с массивами не ограничивается их созданием и хранением — часто возникает необходимость извлечь отдельные элементы или проанализировать их содержимое. PostgreSQL предлагает несколько встроенных функций для таких операций. Рассмотрим их по порядку.

Функция unnest(): распаковка массива

Функция unnest() буквально распаковывает массив, превращая его элементы в отдельные строки. Это особенно полезно, если вам нужно работать с данными массива в виде таблицы.

Пример 1: Простая распаковка массива

Допустим, у нас есть массив с названиями факультетов:

SELECT ARRAY['Информатика', 'Математика', 'Физика'] AS факультеты;

Теперь нужно извлечь каждый элемент как отдельную строку. Используем unnest():

SELECT unnest(ARRAY['Информатика', 'Математика', 'Физика']) AS факультет;

Результат:

факультет
Информатика
Математика
Физика

Пример 2: Распаковка массива в таблице

Предположим, у нас есть таблица courses:

CREATE TABLE courses (
    course_id SERIAL PRIMARY KEY,
    course_name TEXT,
    tags TEXT[]
);

INSERT INTO courses (course_name, tags)
VALUES
    ('Алгоритмы', ARRAY['Программирование', 'Информатика']),
    ('Линейная алгебра', ARRAY['Математика', 'Алгебра']),
    ('Физика основ', ARRAY['Физика', 'Общая']);

Теперь извлечём все теги из массива:

SELECT course_name, unnest(tags) AS tag
FROM courses;

Результат:

course_name tag
Алгоритмы Программирование
Алгоритмы Информатика
Линейная алгебра Математика
Линейная алгебра Алгебра
Физика основ Физика
Физика основ Общая

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

Функция array_length(): определяем размер массива

Второй важной функцией для работы с массивами является array_length(). Она возвращает длину массива (то есть количество элементов) для заданного измерения.

Пример 1: Количество элементов в одномерном массиве

Возьмём массив:

SELECT ARRAY['Яблоко', 'Банан', 'Апельсин'] AS фрукты;

Если мы хотим узнать, сколько фруктов в массиве:

SELECT array_length(ARRAY['Яблоко', 'Банан', 'Апельсин'], 1) AS длина;

Результат:

длина
3

Здесь 1 указывает на измерение массива. У массивов в PostgreSQL может быть несколько измерений (например, двумерные массивы), но об этом мы поговорим в другом контексте.

Пример 2: Количество элементов в массиве таблицы

Посмотрим, сколько тегов у каждого курса:

SELECT course_name, array_length(tags, 1) AS количество_тегов
FROM courses;

Результат:

course_name количество_тегов
Алгоритмы 2
Линейная алгебра 2
Физика основ 2

Функция просто говорит: «Эй, здесь два элемента!», а это уже многое упрощает в анализе данных.

Функция array_position(): поиск значения в массиве

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

Пример 1: Поиск элемента

Допустим, у нас есть массив:

SELECT ARRAY['Красный', 'Синий', 'Зелёный', 'Жёлтый'] AS цвета;

Попробуем найти позицию элемента "Синий":

SELECT array_position(ARRAY['Красный', 'Синий', 'Зелёный', 'Жёлтый'], 'Синий') AS позиция;

Результат:

позиция
2

Если элемент отсутствует, функция возвращает NULL. Давайте проверим:

SELECT array_position(ARRAY['Красный', 'Синий', 'Зелёный', 'Жёлтый'], 'Чёрный') AS позиция;

Результат:

позиция
NULL

Пример 2: Поиск в массиве таблицы

Вы хотите узнать, у какого курса есть тег "Информатика". Сначала найдем нужные строки:

SELECT course_name, array_position(tags, 'Информатика') AS позиция
FROM courses;

Результат:

course_name позиция
Алгоритмы 2
Линейная алгебра NULL
Физика основ NULL

Теперь добавьте фильтрацию, чтобы оставить только те строки, где тег есть:

SELECT course_name
FROM courses
WHERE array_position(tags, 'Информатика') IS NOT NULL;

Результат:

course_name
Алгоритмы

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

Практическое применение функций

  • unnest() — использовать для преобразования массивов в строки. Это важно для анализа данных, создания отчетов и работы с тегами.
  • array_length() — идеально подходит для проверки длины массивов. Например, можно использовать её для валидации данных: проверять, чтобы массив не был пустым.
  • array_position() — отличный инструмент для поиска элементов, будь то категории товаров, участие студента в проекте или ключевые слова в описании.

Типичные ошибки при использовании функций

  1. unnest() может удвоить количество строк, если применяется к массивам сразу в нескольких столбцах. Это легко решить, добавив JOIN LATERAL или CROSS JOIN, но будьте внимательны.
  2. array_length() возвращает NULL для пустого массива. Если ваш массив может быть пустым, проверяйте это отдельно.
  3. array_position() может вернуть NULL, если элемент отсутствует. Поэтому лучше всегда учитывать этот случай в фильтрах (IS NOT NULL).

Примеры из реальной практики

Массивы в PostgreSQL — не просто теоретическая штука, а инструмент, который отлично работает в реальных проектах. Например, вы ведёте блог и у каждой статьи есть список тегов — массив позволяет легко фильтровать статьи по нужной теме или даже составлять топ популярных категорий.

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

А ещё массивы помогают валидировать данные: с помощью array_length() можно, скажем, ограничить количество элементов — например, чтобы пользователь не выбирал больше пяти пунктов.

2
Задача
SQL SELF, 35 уровень, 2 лекция
Недоступна
Распаковка массива с `unnest()`
Распаковка массива с `unnest()`
Комментарии (2)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Евгений Уровень 49 Expert
24 сентября 2025
unnest() может удвоить количество строк, если применяется к массивам сразу в нескольких столбцах. Это легко решить, добавив JOIN LATERAL или CROSS JOIN, но будьте внимательны. Данная ситуация воспроизводится только на версиях PostgreSQL ниже 10: ссылка. В этих версиях, если вы разворачиваете сразу два массива, и в них разное количество элементов, то в результате будет получено декартово произведение двух разворачиваемых массивов. Попробуйте:

CREATE TABLE IF NOT EXISTS arrays_test
(
    id      SERIAL PRIMARY KEY,
    array_1 INTEGER[] NOT NULL,
    array_2 INTEGER[] NOT NULL
);

INSERT INTO arrays_test (array_1, array_2)
VALUES (ARRAY [1, 2, 3], ARRAY [4, 5, 6]),
       (ARRAY [1, 2, 3], ARRAY [4, 5, 6, 7]);

-- Вернёт 3 строки
SELECT UNNEST(array_1) AS array_1_element,
       UNNEST(array_2) AS array_2_element
FROM arrays_test
WHERE id = 1;

-- Вернёт 12 строк (Декартово произведение)
SELECT UNNEST(array_1) AS array_1_element,
       UNNEST(array_2) AS array_2_element
FROM arrays_test
WHERE id = 2;
Евгений Уровень 49 Expert
24 сентября 2025
JOIN LATERAL позволяет нам устранить данную проблему. Вообще, данная конструкция позволяет нам получать доступ к левой части запроса из правой части запроса, что в обычном JOIN вообще-то нельзя.

CREATE TABLE IF NOT EXISTS arrays_test
(
    id      SERIAL PRIMARY KEY,
    array_1 INTEGER[] NOT NULL,
    array_2 INTEGER[] NOT NULL
);

INSERT INTO arrays_test (array_1, array_2)
VALUES (ARRAY [1, 2, 3, 4, 5], ARRAY [1, 2, 3]);

SELECT arr_1, jarr_2.arr_2
FROM arrays_test AS art
CROSS JOIN LATERAL UNNEST(art.array_1) AS arr_1(element)
LEFT JOIN LATERAL (SELECT arr_2
                   FROM UNNEST(art.array_2) AS arr_2(element)
                   WHERE arr_2.element <= arr_1.element
                   ORDER BY arr_2.element DESC
                   LIMIT 1) AS jarr_2(arr_2) ON TRUE
WHERE art.id = 1;
Чтобы не получать декартово произведение, я присвоил каждому значению из первого массива только одно значение из второго массива. В данном случае я решил использовать самое близкое значение, которое меньше или равно значению из первого массива. Результат:

arr_1	arr_2
1	1
2	2
3	3
4	3
5	3