middle
Как работать с массивами в PostgreSQL?
PostgreSQL позволяет хранить массивы значений любого типа в одном поле. Массивы удобны для небольших списков тегов и меток, которые читаются целиком, но для сложных связей лучше использовать отдельную таблицу.
Пример
CREATE TABLE products (
id serial PRIMARY KEY,
name text,
tags text[],
prices numeric[]
);
INSERT INTO products (name, tags, prices) VALUES
('Кредит наличными', ARRAY['кредит', 'физлица', 'наличные'], ARRAY[100000, 500000, 1000000]),
('Вклад "Надёжный"', '{вклад,физлица,депозит}', '{50000,100000}');
Операции с массивами
-- Доступ к элементу (индексация с 1!)
SELECT tags[1] FROM products; -- 'кредит'
-- Срез массива
SELECT tags[1:2] FROM products; -- {'кредит','физлица'}
-- Проверка вхождения элемента
SELECT * FROM products WHERE 'кредит' = ANY(tags);
SELECT * FROM products WHERE tags @> ARRAY['кредит'];
-- Проверка пересечения массивов
SELECT * FROM products WHERE tags && ARRAY['вклад', 'кредит']; -- overlap
-- Конкатенация
SELECT tags || ARRAY['новый_тег'] FROM products;
SELECT array_append(tags, 'новый_тег') FROM products;
-- Удаление элемента
SELECT array_remove(tags, 'физлица') FROM products;
-- Длина массива
SELECT array_length(tags, 1) FROM products;
-- Разворачивание массива в строки
SELECT unnest(tags) AS tag FROM products;
-- Агрегация в массив
SELECT array_agg(name) FROM products WHERE 'физлица' = ANY(tags);
Индексирование массивов
Пример
-- GIN-индекс для поиска по массивам
CREATE INDEX idx_products_tags ON products USING GIN (tags);
-- После создания индекса эффективно работают: @>, &&, <@
SELECT * FROM products WHERE tags @> ARRAY['кредит', 'физлица'];
Когда массивы, а когда отдельная таблица
- Массивы — для небольших списков тегов/меток, которые в основном читаются целиком
- Отдельная таблица (many-to-many) — если нужны JOIN, агрегации, FOREIGN KEY, или если массивы большие
На собеседовании: индексация массивов в PostgreSQL начинается с 1, а не с 0 — классический вопрос-ловушка. Также стоит упомянуть, что для поиска по массивам нужен GIN-индекс, а не B-tree.