Тип данных hstore
- Операции со значениями hstore
- Получение значения по ключу
- Добавление пары ключ/значение к существующему значению
hstore
- Изменение пары ключ/значение
- Добавление нескольких пар ключ/значение
- Удаление пары ключ/значение
- Проверка существования ключа
- Проверка существования пары ключ/значение
- Получение строк, содержащих указанные ключи
- Получение всех ключей
- Получение всех значений
- Преобразование данных hstore в набор записей
- Преобразование данных hstore в JSON/JSONB
- Индексирование полей hstore
В PostgreSQL тип данных hstore
позволяет хранить пары ключ/значение в одном значении поля. Тип hstore
используется, когда ключи не могут быть определены заранее или отличаются для разных объектов.
Тип данных hstore
реализуется модулем hstore. Чтобы использовать этот тип, нужно создать расширение hstore
:
CREATE EXTENSION hstore;
Значение hstore
содержит пары ключ => значение
, разделенные запятыми. Ключи и значения хранятся в виде текстовых строк.
Создадим таблицу products
со столбцом hstore
, чтобы посмотреть, как работать с этим типом:
CREATE TABLE products (
id serial PRIMARY KEY,
name character varying(100),
attributes hstore
);
В этой таблице разные продукты могут иметь разные атрибуты. Добавим в таблицу следующие строки:
INSERT INTO products (name, attributes) VALUES (
'The Time Machine',
'author => "Herbert Wells",
pages => 202,
genre => "sci-fi"'),
('Hyperion',
'author => "Dan Simmons",
pages => 640,
genre => "sci-fi"'),
('The Great Gatsby',
'author => "F. Scott Fitzgerald",
pages => 256,
genre => "novel"'),
('People',
'publisher => "Time Inc",
number => 38,
date => "09.12.2022"'
);
Содержание таблицы:
id | name | attributes ----+------------------+----------------------------------------------------------------- 1 | The Time Machine | "genre"=>"sci-fi", "pages"=>"202", "author"=>"Herbert Wells" 2 | Hyperion | "genre"=>"sci-fi", "pages"=>"640", "author"=>"Dan Simmons" 3 | The Great Gatsby | "genre"=>"novel", "pages"=>"256", "author"=>"F. Scott Fitzgerald" 4 | People | "date"=>"09.12.2022", "number"=>"38", "publisher"=>"Time Inc"
Тип hstore
имеет следующие особенности синтаксиса:
-
Порядок пар
hstore
не имеет значения и может быть не воспроизведен на выходе. -
PostgreSQL игнорирует пробелы между парами или вокруг знака
=>
. Ключи и значения, содержащие пробелы, запятые, знаки=
или>
, должны быть заключены в двойные кавычки. Чтобы использовать двойную кавычку ("
) или обратную косую черту (\
) в ключе или значении, заэкранируйте их обратной косой чертой (\"
,\\
). -
Каждый ключ должен быть уникальным.
-
Значение может содержать SQL
NULL
(key => NULL
). Ключевое словоnull
не зависит от регистра. Заключите его в двойные кавычки, чтобы обрабатывать как строковое значение"NULL"
.
Операции со значениями hstore
PostgreSQL предоставляет большое количество операторов и функций для работы с типом hstore
. В этом разделе приведены примеры типовых операций, которые можно выполнять с помощью этого функционала. Для получения дополнительной информации об операторах и функциях hstore
обратитесь к документации PostgreSQL: Hstore operators and functions.
Получение значения по ключу
Вы можете использовать оператор ->
, чтобы получить значение определенного ключа из столбца hstore
. Если ключ отсутствует, соответствующая строка не включается в результат:
SELECT name, attributes->'author' as author
FROM products;
Результат:
name | author ------------------+--------------------- The Time Machine | Herbert Wells Hyperion | Dan Simmons The Great Gatsby | F. Scott Fitzgerald
Вы также можете использовать оператор ->
в выражении WHERE
. Следующий запрос выбирает продукты, для которых указан жанр sci-fi
:
SELECT name, attributes->'author' as author
FROM products
WHERE attributes -> 'genre' = 'sci-fi';
Результат:
name | author ------------------+--------------- The Time Machine | Herbert Wells Hyperion | Dan Simmons
Добавление пары ключ/значение к существующему значению hstore
Вы можете добавить новую пару ключ/значение в существующие строки. Для этого используйте оператор ||
, который объединяет два значения hstore
. Следующий запрос добавляет "freeshipping"⇒"yes"
ко всем существующим строкам:
UPDATE products
SET attributes = attributes || '"freeshipping"=>"yes"' :: hstore;
Изменение пары ключ/значение
Чтобы обновить существующую пару ключ/значение, используйте тот же оператор ||
. Следующий запрос изменяет значение freeshipping
книги Hyperion
на no
:
UPDATE products
SET attributes = attributes || '"freeshipping"=>"no"' :: hstore
WHERE name = 'Hyperion';
Содержание таблицы:
id | name | attributes ----+------------------+------------------------------------------------------------------------------------------ 1 | The Time Machine | "genre"=>"sci-fi", "pages"=>"202", "author"=>"Herbert Wells", "freeshipping"=>"yes" 2 | Hyperion | "genre"=>"sci-fi", "pages"=>"640", "author"=>"Dan Simmons", "freeshipping"=>"no" 3 | The Great Gatsby | "genre"=>"novel", "pages"=>"256", "author"=>"F. Scott Fitzgerald", "freeshipping"=>"yes" 4 | People | "date"=>"09.12.2022", "number"=>"38", "publisher"=>"Time Inc", "freeshipping"=>"yes"
Добавление нескольких пар ключ/значение
Чтобы добавить несколько пар ключ/значение, используйте двумерный массив, содержащий ключи и значения.
Следующее выражение заменяет значение поля attributes
в строке, где id = 4
:
UPDATE products SET attributes = hstore(ARRAY[['pages', '32'],['media', 'ebook']]) WHERE id = 4;
Запрос ниже добавляет новые значения к значению поля attributes
в строке, где id = 4
:
UPDATE products SET attributes = attributes || hstore(ARRAY[['pages', '32'],['media', 'ebook']]) WHERE id = 4;
Удаление пары ключ/значение
Используйте функцию delete
, чтобы удалить пару ключ/значение из столбца hstore
:
UPDATE products
SET attributes = delete(attributes, 'freeshipping');
Вы также можете использовать массив для удаления нескольких ключей:
UPDATE products
SET attributes = delete(attributes, ARRAY['genre', 'pages']);
Проверка существования ключа
Используйте оператор ?
, чтобы проверить, существует ли определенный ключ в столбце hstore
:
SELECT name, attributes -> 'publisher' as publisher
FROM products
WHERE attributes ? 'publisher';
Результат:
name | publisher --------+----------- People | Time Inc
Проверка существования пары ключ/значение
Чтобы проверить, существует ли пара ключ/значение, используйте оператор @>
, который определяет, содержит ли левый операнд правый. Следующее выражение возвращает все строки, в которых столбец attributes
содержит "freeshipping"=>"yes"
:
SELECT name, attributes -> 'freeshipping' as freeshipping
FROM products
WHERE attributes @> '"freeshipping"=>"yes"' :: hstore;
Результат:
name | freeshipping ------------------+-------------- The Time Machine | yes The Great Gatsby | yes People | yes
Получение строк, содержащих указанные ключи
Используйте оператор ?&
, чтобы получить строки с несколькими указанными ключами. Следующий запрос возвращает строки с ключами genre
и pages
:
SELECT name FROM products
WHERE attributes ?& ARRAY [ 'genre', 'pages' ];
Результат:
name ------------------ The Time Machine The Great Gatsby Hyperion
Получение всех ключей
Используйте функцию akeys
, чтобы получить все ключи hstore
в виде массива:
SELECT akeys (attributes) FROM products;
Результат:
akeys -------------------------------------- {genre,pages,author,freeshipping} {genre,pages,author,freeshipping} {date,number,publisher,freeshipping} {genre,pages,author,freeshipping}
Функция skeys
возвращает все ключи в виде набора записей:
SELECT skeys (attributes) FROM products;
Результат:
genre pages author freeshipping genre pages author freeshipping date number publisher freeshipping genre pages author freeshipping
Получение всех значений
Используйте функцию avals
, чтобы получить все значения hstore
в виде массива:
SELECT avals (attributes) FROM products;
Результат:
avals --------------------------------------- {sci-fi,202,"Herbert Wells",yes} {novel,256,"F. Scott Fitzgerald",yes} {09.12.2022,38,"Time Inc",yes} {sci-fi,640,"Dan Simmons",no}
Функция svals
возвращает все значения в виде набора записей:
SELECT svals (attributes) FROM products;
Результат:
sci-fi 202 Herbert Wells yes novel 256 F. Scott Fitzgerald yes 09.12.2022 38 Time Inc yes sci-fi 640 Dan Simmons no
Преобразование данных hstore в набор записей
Используйте функцию each
для извлечения данных hstore
в виде набора записей:
SELECT
name,
(each(attributes) ).*
FROM products;
Результат:
name | key | value ------------------+--------------+--------------------- The Time Machine | genre | sci-fi The Time Machine | pages | 202 The Time Machine | author | Herbert Wells The Time Machine | freeshipping | yes The Great Gatsby | genre | novel The Great Gatsby | pages | 256 The Great Gatsby | author | F. Scott Fitzgerald The Great Gatsby | freeshipping | yes People | date | 09.12.2022 People | number | 38 People | publisher | Time Inc People | freeshipping | yes Hyperion | genre | sci-fi Hyperion | pages | 640 Hyperion | author | Dan Simmons Hyperion | freeshipping | no
Преобразование данных hstore в JSON/JSONB
В PostgreSQL есть функции hstore_to_json
и hstore_to_jsonb
для преобразования данных hstore
в JSON или JSONB. Следующий запрос преобразует столбец attributes
в JSONB
:
SELECT hstore_to_jsonb (attributes) jsonb
FROM products;
Результат:
jsonb -------------------------------------------------------------------------------------------- {"genre": "sci-fi", "pages": "202", "author": "Herbert Wells", "freeshipping": "yes"} {"genre": "novel", "pages": "256", "author": "F. Scott Fitzgerald", "freeshipping": "yes"} {"date": "09.12.2022", "number": "38", "publisher": "Time Inc", "freeshipping": "yes"} {"genre": "sci-fi", "pages": "640", "author": "Dan Simmons", "freeshipping": "no"}
Индексирование полей hstore
Вы можете использовать индексы, чтобы сократить время, необходимое PostgreSQL для поиска ключей и значений.
Следующие операторы создают индексы GIN
и GiST
для столбца attributes
:
CREATE INDEX idx_gin_attributes ON products USING GIN(attributes);
CREATE INDEX idx_gist_attributes ON products USING GIST(attributes);
Следующие выражения создают индексы hash
и btree
для столбца attributes
:
CREATE INDEX idx_btree_attributes ON products USING BTREE(attributes);
CREATE INDEX idx_hash_attributes ON products USING HASH(attributes);