PostgreSQL / Массив өгөгдлийн төрөл

Массив өгөгдлийн төрөл

Нэг хэрэглэгчийн дуртай хоол хэд хэдэн байж болно. Нийтлэлд олон tag байж болно. Захиалгад олон бүтээгдэхүүн байж болно. Эдгээрийг хадгалахын тулд тусдаа хүснэгт үүсгэж JOIN хийх стандарт арга байдаг — гэвч заримдаа массив ашиглах нь хамаагүй хялбар шийдэл болдог. PostgreSQL нь TEXT[], INT[], BOOLEAN[] зэрэг дурын төрлийн массивыг нэг баганад хадгалах боломж олгодог.

Массив үүсгэх

Массив баганыг [] нэмж тодорхойлно:

sql
CREATE TABLE articles (
    id          SERIAL PRIMARY KEY,
    title       TEXT NOT NULL,
    tags        TEXT[],
    scores      INT[],
    published   BOOLEAN NOT NULL DEFAULT false
);

-- Массив оруулах — ARRAY[] синтакс
INSERT INTO articles (title, tags, scores, published) VALUES
    ('PostgreSQL гарын авлага',
     ARRAY['database', 'sql', 'postgresql'],
     ARRAY[95, 87, 92],
     true),
    ('React hooks тайлбар',
     ARRAY['javascript', 'react', 'frontend'],
     ARRAY[88, 91],
     true),
    ('Go concurrency',
     ARRAY['go', 'backend', 'concurrency'],
     ARRAY[79, 85, 90, 94],
     false);

-- Хашилтан синтакс ашиглах боломжтой
INSERT INTO articles (title, tags) VALUES
    ('Python эхлэгчдэд', '{"python", "tutorial", "beginner"}');

Массив унших ба индексжүүлэх

PostgreSQL-н массивын индекс 1-ээс эхэлдэг — ихэнх програмчлалын хэлнээс ялгаатай:

sql
-- Бүх массивыг унших
SELECT title, tags FROM articles;

-- Эхний элементийг авах (индекс 1-ээс эхэлнэ)
SELECT title, tags[1] AS эхний_tag FROM articles;

-- Сүүлийн элементийг авах
SELECT title, tags[array_length(tags, 1)] AS сүүлийн_tag FROM articles;

-- Хэсгийг авах (slice) — 1-ээс 2-р элемент
SELECT title, tags[1:2] AS эхний_хоёр FROM articles;
sql
-- Массивын хэмжээг авах
SELECT title, array_length(tags, 1) AS tag_тоо
FROM articles
ORDER BY tag_тоо DESC;

Массивт нөхцөл тавих

sql
-- Тодорхой элемент агуулсан мөрийг хайх (ANY)
SELECT title FROM articles
WHERE 'sql' = ANY(tags);

-- Олон элементийн аль нэгийг агуулсан эсэх
SELECT title FROM articles
WHERE tags && ARRAY['go', 'python'];
-- && оператор: массивууд огтлолцоно уу?

-- Массив нь нөгөөг бүрэн агуулж байна уу? (@> оператор)
SELECT title FROM articles
WHERE tags @> ARRAY['javascript', 'react'];
-- Үр дүн: 'React hooks тайлбар' (хоёуланг нь агуулсан)

Массив өөрчлөх

sql
-- Массивд элемент нэмэх
UPDATE articles
SET tags = array_append(tags, 'tutorial')
WHERE title = 'PostgreSQL гарын авлага';

-- Эхэнд нэмэх
UPDATE articles
SET tags = array_prepend('шинэ', tags)
WHERE id = 1;

-- Элемент устгах
UPDATE articles
SET tags = array_remove(tags, 'tutorial')
WHERE id = 1;

-- Хоёр массивыг нийлүүлэх
UPDATE articles
SET scores = scores || ARRAY[99]
WHERE id = 1;

Массивт хэрэгтэй функцүүд

sql
-- Массивыг мөрүүд болгон задлах (unnest)
SELECT title, UNNEST(tags) AS tag
FROM articles
WHERE published = true;
-- Нийтлэл бүрийн tag мөр болгон харагдана

-- Tag тус бүрийн нийтлэлийн тоог тоолох
SELECT tag, COUNT(*) AS нийтлэлийн_тоо
FROM articles, UNNEST(tags) AS tag
GROUP BY tag
ORDER BY нийтлэлийн_тоо DESC;

-- Массивыг текст болгох
SELECT title, ARRAY_TO_STRING(tags, ', ') AS tag_жагсаалт
FROM articles;

-- Текстийг массив болгох
SELECT STRING_TO_ARRAY('go,backend,api', ',') AS tags;

GIN индекс — массив хайлтыг хурдасгах

JSONB-тэй адил массивт GIN индекс тавьж хайлтыг хурдасгаж болно:

sql
-- tags баганад GIN индекс
CREATE INDEX idx_articles_tags ON articles USING GIN (tags);

-- Одоо энэ хайлт индексийг ашиглана
SELECT title FROM articles WHERE tags @> ARRAY['sql'];
SELECT title FROM articles WHERE 'react' = ANY(tags);

Массив нь холбоос хүснэгт шаардахгүй энгийн олон утгад тохиромжтой. Харин тухайн утгуудын хооронд нарийн харилцаа, нэмэлт талбар шаардлагатай бол тусдаа хүснэгт үүсгэх нь зөв хандлага юм.

Дараагийн хичээлд:

PostgreSQL-н full-text search буюу бүтэн текст хайлтаар их хэмжээний текст өгөгдлийг хурдан, оновчтой хайх аргыг сурна.