Продвинутые типы данных PostgreSQL

PostgreSQLBeginner
Практиковаться сейчас

Введение

В этой лабораторной работе вы изучите расширенные типы данных PostgreSQL, уделяя особое внимание JSON/JSONB, массивам и UUID. Вы научитесь хранить, запрашивать и манипулировать данными внутри этих типов.

Лабораторная работа начинается с демонстрации того, как хранить и запрашивать данные JSON и JSONB, включая создание таблицы с столбцом JSONB, вставку данных JSON и использование операторов, таких как -> и ->>, для извлечения конкретных значений. Затем вы перейдете к изучению столбцов массивов и UUID.

Хранение и запрос данных JSON и JSONB

На этом этапе вы научитесь хранить и запрашивать данные JSON и JSONB в PostgreSQL. PostgreSQL предоставляет два типа данных для хранения JSON-данных: JSON и JSONB. Тип данных JSON хранит точную копию входного текста JSON, в то время как тип данных JSONB хранит JSON-данные в разложенном бинарном формате. JSONB обычно предпочтительнее, поскольку он обеспечивает лучшую производительность для запросов и индексирования.

Начнем с открытия оболочки PostgreSQL. Сначала подключитесь к базе данных labex:

sudo -u postgres psql -d labex

Вы должны увидеть приглашение PostgreSQL:

labex=#

Теперь давайте создадим таблицу для хранения данных JSONB:

CREATE TABLE products (id SERIAL PRIMARY KEY, data JSONB);

Эта команда SQL создает таблицу с именем products. Таблица имеет два столбца: id (автоинкрементный целочисленный первичный ключ) и data (столбец JSONB для хранения данных JSON).

Вы должны увидеть вывод, похожий на этот:

CREATE TABLE

Теперь давайте вставим некоторые данные в таблицу products:

INSERT INTO products (data) VALUES ('{"name": "Laptop", "price": 1200, "features": ["16GB RAM", "512GB SSD"]}');
INSERT INTO products (data) VALUES ('{"name": "Keyboard", "price": 75, "features": ["Mechanical", "RGB Backlight"]}');

Эти команды вставляют две строки в таблицу products. Каждая строка содержит JSON-объект с информацией о продукте.

Для каждой вставки вы должны увидеть вывод, похожий на этот:

INSERT 0 1

Для запроса данных JSON вы можете использовать операторы -> и ->>. Оператор -> возвращает JSON-объект, а оператор ->> возвращает значение JSON в виде текста.

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

SELECT data ->> 'name' FROM products WHERE id = 1;

Эта команда выбирает значение, связанное с ключом name, из столбца data таблицы products, где id равен 1. Оператор ->> гарантирует, что результат будет возвращен в виде текста.

Вы должны увидеть вывод, похожий на этот:

  ?column?
----------
 Laptop
(1 row)

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

SELECT data -> 'features' ->> 0 FROM products WHERE id = 1;

Эта команда сначала выбирает массив features из столбца data, а затем выбирает элемент с индексом 0 из массива. Оператор ->> гарантирует, что результат будет возвращен в виде текста.

Вы должны увидеть вывод, похожий на этот:

  ?column?
----------
 16GB RAM
(1 row)

Вы также можете использовать оператор @> для проверки того, содержит ли JSON-объект определенную пару ключ-значение. Например, чтобы найти все продукты с ценой 75, вы можете использовать следующий запрос:

SELECT data ->> 'name' FROM products WHERE data @> '{"price": 75}';

Эта команда выбирает имя всех строк из таблицы products, где столбец data содержит JSON-объект с ключом price и значением 75.

Вы должны увидеть вывод, похожий на этот:

  ?column?
----------
 Keyboard
(1 row)

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

Добавление столбцов с массивами в существующую таблицу

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

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

ALTER TABLE products ADD COLUMN name VARCHAR(255);
ALTER TABLE products ADD COLUMN tags TEXT[];

Эти команды добавляют два новых столбца в нашу существующую таблицу products: name (строка) и tags (массив строк). Тип данных TEXT[] указывает, что столбец tags является массивом текстовых значений.

Для каждой команды ALTER вы должны увидеть вывод, похожий на этот:

ALTER TABLE

Теперь давайте обновим существующие данные и вставим новые данные с новыми столбцами:

UPDATE products SET name = data ->> 'name' WHERE id = 1;
UPDATE products SET name = data ->> 'name' WHERE id = 2;
UPDATE products SET tags = ARRAY['electronics', 'computers', 'portable'] WHERE id = 1;
UPDATE products SET tags = ARRAY['electronics', 'accessories', 'input'] WHERE id = 2;

Эти команды обновляют наши существующие продукты, добавляя информацию об имени и тегах, извлеченную из данных JSONB, и новые значения массивов.

Для каждого обновления вы должны увидеть вывод, похожий на этот:

UPDATE 1

Для запроса данных массива вы можете использовать индексацию массива. Индексы массива в PostgreSQL начинаются с 1.

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

SELECT tags[1] FROM products WHERE id = 1;

Эта команда выбирает элемент с индексом 1 из массива tags таблицы products, где id равен 1.

Вы должны увидеть вывод, похожий на этот:

   tags
-----------
 electronics
(1 row)

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

Например, чтобы получить все теги всех продуктов, вы можете использовать следующий запрос:

SELECT name, UNNEST(tags) AS tag FROM products;

Эта команда выбирает name и каждый отдельный tag из массива tags, создавая новую строку для каждого тега.

Вы должны увидеть вывод, похожий на этот:

  name   |     tag
---------+-------------
 Laptop  | electronics
 Laptop  | computers
 Laptop  | portable
 Keyboard| electronics
 Keyboard| accessories
 Keyboard| input
(6 rows)

Вы можете использовать оператор @> для проверки того, содержит ли массив определенное значение.

Например, чтобы найти все продукты с тегом 'electronics', вы можете использовать следующий запрос:

SELECT name FROM products WHERE tags @> ARRAY['electronics'];

Эта команда выбирает имя всех строк из таблицы products, где массив tags содержит значение 'electronics'.

Вы должны увидеть вывод, похожий на этот:

  name
----------
 Laptop
 Keyboard
(2 rows)

Вы также можете использовать оператор && для проверки того, имеют ли два массива общие элементы.

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

SELECT p2.name FROM products p1, products p2 WHERE p1.id = 1 AND p1.tags && p2.tags AND p2.id != 1;

Эта команда выбирает имя всех строк из таблицы products (с псевдонимом p2), которые имеют хотя бы один общий тег с тегами первого продукта (с псевдонимом p1), исключая сам первый продукт.

Вы должны увидеть вывод, похожий на этот:

  name
----------
 Keyboard
(1 row)

Отлично! Мы успешно добавили столбцы массивов в нашу существующую таблицу и научились работать с массивами. Наша таблица products теперь содержит типы данных JSONB и массивов, что делает ее готовой к следующему шагу.

Добавление столбца UUID и изучение генерации UUID

На этом этапе вы научитесь генерировать и использовать UUID (Universally Unique Identifiers) в PostgreSQL. UUID — это 128-битные числа, разработанные для обеспечения уникальности в пространстве и времени. Они часто используются в качестве уникальных идентификаторов в таблицах баз данных, чтобы избежать конфликтов при слиянии данных из разных источников.

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

Сначала давайте включим расширение UUID, которое предоставляет функции генерации UUID:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

Эта команда создает расширение uuid-ossp, если оно еще не существует.

Вы должны увидеть вывод, похожий на этот:

CREATE EXTENSION

Теперь давайте добавим столбец UUID в нашу существующую таблицу products:

ALTER TABLE products ADD COLUMN uuid_id UUID;

Эта команда добавляет новый столбец UUID в нашу существующую таблицу products.

Вы должны увидеть вывод, похожий на этот:

ALTER TABLE

Теперь мы можем обновить наши существующие строки значениями UUID, используя функцию uuid_generate_v4():

UPDATE products SET uuid_id = uuid_generate_v4() WHERE id = 1;
UPDATE products SET uuid_id = uuid_generate_v4() WHERE id = 2;

Эти команды обновляют наши существующие продукты уникальными значениями UUID. Функция uuid_generate_v4() генерирует новый UUID для каждой строки.

Для каждого обновления вы должны увидеть вывод, похожий на этот:

UPDATE 1

Для запроса данных с использованием UUID вы можете использовать значения UUID в ваших предложениях WHERE. Поскольку UUID генерируются случайным образом, давайте сначала посмотрим наши текущие данные:

SELECT id, name, uuid_id FROM products;

Эта команда выбирает все столбцы из таблицы products, чтобы увидеть сгенерированные UUID вместе с нашими другими данными.

Вы должны увидеть вывод, похожий на этот (ваш UUID будет отличаться):

                  id
------------------------------------
 a1b2c3d4-e5f6-7890-1234-567890abcdef
(1 row)

Теперь используйте этот UUID в следующей команде, заменив <YOUR_UUID_HERE> фактическим полученным вами UUID:

SELECT name FROM products WHERE id = '<YOUR_UUID_HERE>';

Эта команда выбирает name из таблицы products, где id соответствует указанному UUID.

Вы должны увидеть вывод, похожий на этот (в зависимости от того, какой UUID вы выбрали):

  name
----------
 Laptop
(1 row)

Наконец, давайте очистим созданную нами таблицу и расширение:

DROP TABLE products;
DROP EXTENSION "uuid-ossp";

Для каждой команды DROP вы должны увидеть вывод, похожий на этот:

DROP TABLE
DROP EXTENSION

Извлечение данных из продвинутых типов

На этом заключительном этапе вы попрактикуетесь в извлечении данных из всех продвинутых типов данных, которые мы добавили в нашу таблицу products на протяжении всей этой лабораторной работы. Наша таблица теперь содержит столбцы JSONB, массивов и UUID, что является исчерпывающим примером продвинутых типов данных PostgreSQL.

Поскольку мы продолжаем работать с нашей текущей сессией и таблицей, мы можем немедленно приступить к работе с данными, которые мы накапливали на предыдущих этапах.

Сначала давайте добавим дополнительные данные JSONB, чтобы наши примеры извлечения были более полными:

UPDATE products SET data = '{"brand": "Dell", "model": "XPS 13", "specs": {"ram": "16GB", "storage": "512GB SSD"}, "warranty": "3 years"}' WHERE id = 1;
UPDATE products SET data = '{"brand": "Logitech", "model": "G915", "specs": {"type": "Mechanical", "backlight": "RGB"}, "warranty": "2 years"}' WHERE id = 2;

Эти команды обновляют наши существующие данные JSONB более подробной информацией, включая вложенные объекты и дополнительные поля.

Для каждого обновления вы должны увидеть вывод, похожий на этот:

UPDATE 1

Теперь давайте попрактикуемся в извлечении данных из всех наших продвинутых типов данных. Чтобы извлечь данные из столбца JSONB data, вы можете использовать операторы -> и ->>. Например, чтобы извлечь бренд из наших обновленных данных:

SELECT data ->> 'brand' FROM products WHERE id = 1;

Эта команда извлекает значение, связанное с ключом brand, из столбца data.

Вы должны увидеть вывод, похожий на этот:

 ?column?
----------
 Dell
(1 row)

Чтобы извлечь вложенные данные из столбца JSONB, вы можете объединить операторы -> и ->>. Например, чтобы извлечь спецификацию ОЗУ (RAM):

SELECT data -> 'specs' ->> 'ram' FROM products WHERE id = 1;

Эта команда извлекает значение, связанное с ключом ram внутри объекта specs.

Вы должны увидеть вывод, похожий на этот:

 ?column?
----------
 16GB
(1 row)

Чтобы извлечь данные из столбца tags (массив), вы можете использовать индексацию массива, как было изучено в Шаге 2. Например, чтобы извлечь первый тег первого продукта:

SELECT tags[1] FROM products WHERE id = 1;

Эта команда извлекает элемент с индексом 1 из массива tags таблицы products, где id равен 1.

Вы должны увидеть вывод, похожий на этот:

   tags
-----------
 electronics
(1 row)

Теперь давайте создадим комплексный запрос, который извлекает данные из всех наших продвинутых типов данных — JSONB, массивов и UUID:

SELECT
    id,
    name,
    data ->> 'brand' AS brand,
    data -> 'specs' ->> 'ram' AS ram,
    tags[1] AS first_tag,
    uuid_id
FROM products;

Эта команда извлекает данные из всех продвинутых типов данных, с которыми мы работали: целочисленный id, name, brand из столбца JSONB data, вложенная спецификация ram, первый элемент массива tags и uuid_id.

Вы должны увидеть вывод, похожий на этот:

   name   |  ?column?  |   tags
----------+------------+-----------
 Laptop   | Dell       | electronics
 Keyboard | Logitech   | electronics
(2 rows)

Отлично! Вы успешно поработали со всеми тремя продвинутыми типами данных PostgreSQL в одной таблице. Этот комплексный пример демонстрирует, как JSONB, массивы и UUID могут использоваться вместе для создания гибких и мощных схем баз данных.

Когда вы закончите все шаги, вы можете выйти из оболочки PostgreSQL, набрав:

\q

Вы также можете оставить таблицу для дальнейшего экспериментирования с продвинутыми типами данных PostgreSQL.

Резюме

В этой лабораторной работе вы постепенно создали и работали с комплексной таблицей products, которая демонстрирует продвинутые типы данных PostgreSQL в действии. Вы начали с создания таблицы со столбцами JSONB и научились хранить и запрашивать данные JSON, используя операторы, такие как -> и ->>.

Затем вы расширили таблицу, добавив столбцы массивов, научившись хранить несколько значений в одном столбце и запрашивать их с использованием индексации массивов и функций, таких как UNNEST. Далее вы добавили функциональность UUID, включив расширение uuid-ossp и добавив столбец UUID для генерации уникальных идентификаторов.

Наконец, вы попрактиковались в комплексных методах извлечения данных, которые объединили все три продвинутых типа данных — JSONB, массивы и UUID — в сложных запросах. Этот пошаговый подход продемонстрировал, как эти типы данных могут работать вместе в реальных схемах баз данных, обеспечивая гибкость и мощные возможности запросов для современных приложений.