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

Може ли PostgreSQL да има ограничение за уникалност върху елементите на масива?

Праведният път

Може да искате да преразгледате нормализирането вашата схема. Не е необходимо всеки да се „присъединява дори за най-простата заявка“ . Създайте VIEW за това.

Таблицата може да изглежда така:

CREATE TABLE hostname (
  hostname_id serial PRIMARY KEY
, host_id     int  REFERENCES host(host_id) ON UPDATE CASCADE ON DELETE CASCADE
, hostname    text UNIQUE
);

Сурогатният първичен ключ hostname_id е по избор . Предпочитам да имам такъв. Във вашия случай hostname може да бъде първичен ключ. Но много операции са по-бързи с просто, малко integer ключ. Създайте ограничение за външен ключ за връзка към таблицата host .
Създайте изглед като този:

CREATE VIEW v_host AS
SELECT h.*
     , array_agg(hn.hostname) AS hostnames
--   , string_agg(hn.hostname, ', ') AS hostnames  -- text instead of array
FROM   host h
JOIN   hostname hn USING (host_id)
GROUP  BY h.host_id;   -- works in v9.1+

Започвайки от стр. 9.1 , първичният ключ в GROUP BY обхваща всички колони на тази таблица в SELECT списък. Бележки към версията за версия 9.1:

Разрешаване на не-GROUP BY колони в списъка с цели на заявката, когато първичният ключ е посочен в GROUP BY клауза

Заявките могат да използват изгледа като таблица. Търсенето на име на хост ще бъде много по-бързо по този начин:

SELECT *
FROM   host h
JOIN   hostname hn USING (host_id)
WHERE  hn.hostname = 'foobar';

В Postgres 9.2+ индекс с много колони би бил още по-добър, ако можете да получите сканиране само за индекс от това:

CREATE INDEX hn_multi_idx ON hostname (hostname, host_id);

Започвайки с Postgres 9.3 , можете да използвате MATERIALIZED VIEW , позволяващи обстоятелствата. Особено ако четете много по-често, отколкото пишете на масата.

Тъмната страна (това, което всъщност попитахте)

Ако не мога да те убедя в праведния път, ще помогна и на тъмната страна. аз съм гъвкав. :)

Ето демонстрация как да наложите уникалност на имената на хостове. Използвам таблица hostname за събиране на имена на хостове и тригер в таблицата host за да го поддържам актуален. Уникалните нарушения предизвикват изключение и прекратяват операцията.

CREATE TABLE host(hostnames text[]);
CREATE TABLE hostname(hostname text PRIMARY KEY);  --  pk enforces uniqueness

Функция за задействане:

CREATE OR REPLACE FUNCTION trg_host_insupdelbef()
  RETURNS trigger AS
$func$
BEGIN
-- split UPDATE into DELETE & INSERT
IF TG_OP = 'UPDATE' THEN
   IF OLD.hostnames IS DISTINCT FROM NEW.hostnames THEN  -- keep going
   ELSE RETURN NEW;  -- exit, nothing to do
   END IF;
END IF;

IF TG_OP IN ('DELETE', 'UPDATE') THEN
   DELETE FROM hostname h
   USING  unnest(OLD.hostnames) d(x)
   WHERE  h.hostname = d.x;

   IF TG_OP = 'DELETE' THEN RETURN OLD;  -- exit, we are done
   END IF;
END IF;

-- control only reaches here for INSERT or UPDATE (with actual changes)
INSERT INTO hostname(hostname)
SELECT h
FROM   unnest(NEW.hostnames) h;

RETURN NEW;
END
$func$ LANGUAGE plpgsql;

Задействане:

CREATE TRIGGER host_insupdelbef
BEFORE INSERT OR DELETE OR UPDATE OF hostnames ON host
FOR EACH ROW EXECUTE PROCEDURE trg_host_insupdelbef();

SQL Fiddle с пробно изпълнение.

Използвайте GIN индекс в колоната на масива host.hostnames и оператори за масив за да работите с него:

  • Защо моят PostgreSQL индекс на масива не се използва (Rails 4)?
  • Проверете дали някоя от даден масив от стойности присъства в масив на Postgres


  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. PostgreSQL:Сравнение на низове без регистри

  3. PostgreSQL - извличане на реда, който има максимална стойност за колона

  4. Запазване на часовата зона в PostgreSQL timestamptz тип

  5. Двойка ключови стойности в PostgreSQL