Съхраняване като масив (денормализирано)
Бих обмислил допълнителния модул intarray
който предоставя удобните (и бързи) функции uniq()
и sort()
. В типична съвременна инсталация на Postgres това е толкова лесно, колкото:
CREATE EXTENSION intarray;
С помощта на тях, проста CHECK
ограничението може да наложи възходящо масиви с различни елементи.
CHECK (uniq(sort(cat_arr)) = cat_arr)
Можете допълнително (по избор) имат тригер, който нормализира стойностите на масива ON INSERT OR UPDATE
автоматично. След това можете просто да преминете всички масив (възможно несортиран и с дупки) и всичко просто работи. Като:
CREATE OR REPLACE FUNCTION trg_search_insup_bef()
RETURNS trigger AS
$func$
BEGIN
NEW.cat_arr := uniq(sort(NEW.cat_arr);
RETURN NEW;
END
$func$ LANGUAGE plpgsql;
CREATE TRIGGER insup_bef
BEFORE INSERT OR UPDATE OF cat_arr ON search
FOR EACH ROW
EXECUTE PROCEDURE trg_search_insup_bef();
Допълнителният модул intarray не е задължителен, има и други начини:
Но функциите на вътрешния масив осигуряват превъзходна производителност.
Тогава можете просто да създадете UNIQUE
ограничението в колоната на масива, за да наложите уникалността на целия масив.
UNIQUE (cat_arr)
Написах повече за предимствата на комбинирането на (много строги и надеждни) ограничения с (по-малко надеждни, но по-удобни) тригери в този свързан отговор само преди два дни:
Ако за всяка комбинация всичко, което трябва да съхранявате за категория, е идентификаторът (и без допълнителна информация), това трябва да е достатъчно.
Въпреки това , референтната цялост не се осигурява лесно по този начин. Няма ограничения за външен ключ за елементи на масив (все още) - като документирани във вашата връзка
:Ако една от категориите бъде изтрита или промените идентификаторите, препратките се прекъсват ...
Нормализирана схема
Ако трябва да съхранявате повече или предпочитате да използвате нормализирана схема, за да наложите референтна цялост или по някаква причина, можете да направите и това и да добавите тригер за попълване на ръчно направен материализиран изглед (излишна таблица) и наложи уникалност по подобен начин:
CREATE TABLE search (
search_id serial PRIMARY KEY
, ... more columns
);
CREATE TABLE cat (
cat_id serial PRIMARY KEY
, cat text NOT NULL
);
CREATE TABLE search_cat (
search_id int REFERENCES search ON DELETE CASCADE
, cat_id int REFERENCES cat
, PRIMARY KEY (search_id, cat_id)
);
Свързан отговор (не за уникални комбинации, а за уникални елементи), който демонстрира тригера: