PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Има ли стандартен подход за работа с неподредени масиви (набори) в PostgreSQL?

В момента няма вграден начин.

Като масиви

Ако последователно ги нормализирате при записване, можете да третирате масивите като набори, като винаги ги съхранявате сортирани и дедупликирани. Би било чудесно, ако PostgreSQL имаше вградена C функция за това, но не е така. Погледнах да напиша един, но API за C масив е ужасен , така че въпреки че написах куп разширения, просто се отдръпнах внимателно от това.

Ако нямате нищо против умерено неприятната производителност, можете да го направите в SQL:

CREATE OR REPLACE FUNCTION array_uniq_sort(anyarray) RETURNS anyarray AS $$
SELECT array_agg(DISTINCT f ORDER BY f) FROM unnest($1) f;
$$ LANGUAGE sql IMMUTABLE;

след това обвийте всички записвания в извиквания към array_uniq_sort или да го наложите със спусък. След това можете просто да сравните вашите масиви за равенство. Можете да избегнете array_uniq_sort извиква данни от приложението, ако вместо това просто сте извършили сортирането/уникалното от страната на приложението.

Ако направите това моля съхранявайте вашите „набори“ като колони на масив, като text[] , а не текст, разделен със запетая или интервал. Вижте този въпрос поради някои от причините.

Трябва да внимавате за няколко неща, като факта, че кастанията между масивите са по-строги от кастингите между базовите им типове. Напр.:

regress=> SELECT 'a' = 'a'::varchar, 'b' = 'b'::varchar;
 ?column? | ?column? 
----------+----------
 t        | t
(1 row)

regress=> SELECT ARRAY['a','b'] = ARRAY['a','b']::varchar[];
ERROR:  operator does not exist: text[] = character varying[]
LINE 1: SELECT ARRAY['a','b'] = ARRAY['a','b']::varchar[];
                              ^
HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.
regress=> SELECT ARRAY['a','b']::varchar[] = ARRAY['a','b']::varchar[];
 ?column? 
----------
 t
(1 row)

Такива колони са GiST-индексируеми за операции като array-contains или array-overlaps; вижте документацията на PostgreSQL относно индексирането на масиви.

Като нормализирани редове

Другият вариант е просто да съхранявате нормализирани редове с подходящ ключ. Все още бих използвал array_agg за тяхното сортиране и сравняване, тъй като SQL операциите с множество могат да бъдат тромави за използване за това (особено като се има предвид липсата на XOR / двустранна операция за разлика в набора).

Това обикновено е известно като EAV (entity-attribute-value). Аз самият не съм фен, но има място от време на време. Освен че ще го използвате без value компонент.

Създавате таблица:

CREATE TABLE item_attributes (
    item_id integer references items(id),
    attribute_name text,
    primary key(item_id, attribute_name)
);

и вмъкнете ред за всеки набор от записи за всеки елемент, вместо всеки елемент да има колона със стойност на масив. Уникалното ограничение, наложено от първичния ключ, гарантира, че никой елемент не може да има дубликати на даден атрибут. Подреждането на атрибутите е неуместно/недефинирано.

Сравненията могат да се правят с оператори за SQL набор като EXCEPT или чрез array_agg(attribute_name ORDER BY attribute_name) за формиране на последователно сортирани масиви за сравнение.

Индексирането е ограничено до определяне дали даден елемент има/няма даден атрибут.

Лично аз бих използвал масиви вместо този подход.

hstore

Можете също да използвате hstores с празни стойности за съхраняване на набори, тъй като hstore премахва дублиращи се ключове. jsonb на 9.4 също ще работи за това.

regress=# create extension hstore;
CREATE EXTENSION
regress=# SELECT hstore('a => 1, b => 1') = hstore('b => 1, a => 1, b => 1');
 ?column? 
----------
 t
(1 row)

Това обаче е наистина полезно само за типове текст. напр.:

regress=# SELECT hstore('"1.0" => 1, "2.0" => 1') = hstore('"1.00" => 1, "1.000" => 1, "2.0" => 1');
 ?column? 
----------
 f
(1 row)

и мисля, че е грозно. Така че отново бих предпочел масивите.

Само за масиви с цели числа

intarray разширението предоставя полезни, бързи функции за третиране на масиви като набори. Те са достъпни само за масиви с цели числа, но са наистина полезни.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Създаване на таблично пространство в postgresql

  2. Подредете ли последните N реда в базата данни?

  3. Групово/партидна актуализация/внасяне в PostgreSQL

  4. Как да изброя всички подготвени извлечения за всички активни сесии?

  5. Деактивиране на групирането на връзки в Rails за използване на PgBouncer