PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Czy PostgreSQL może mieć ograniczenie unikalności elementów tablicy?

Sprawiedliwa ścieżka

Być może zechcesz ponownie rozważyć normalizację twój schemat. Nie wszyscy muszą „dołączyć do nawet najprostszego zapytania” . Utwórz VIEW za to.

Tabela może wyglądać tak:

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

Zastępczy klucz podstawowy hostname_id jest opcjonalny . Wolę mieć. W Twoim przypadku hostname może być kluczem podstawowym. Ale wiele operacji jest szybszych dzięki prostej, małej integer klucz. Utwórz ograniczenie klucza obcego, aby połączyć się z tabelą host .
Utwórz taki widok:

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+

Począwszy od strony 9.1 , klucz podstawowy w GROUP BY obejmuje wszystkie kolumny tej tabeli w SELECT lista. Informacje o wydaniu wersji 9.1:

Zezwól na inne niż GROUP BY kolumny na liście celów zapytania, gdy klucz podstawowy jest określony w GROUP BY klauzula

Zapytania mogą używać widoku jak tabeli. Wyszukiwanie nazwy hosta będzie dużo szybciej w ten sposób:

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

W Postgresie 9.2+ indeks wielokolumnowy byłby jeszcze lepszy, gdyby można było uzyskać skanowanie tylko do indeksu poza tym:

CREATE INDEX hn_multi_idx ON hostname (hostname, host_id);

Począwszy od Postgresa 9.3 , możesz użyć MATERIALIZED VIEW , okoliczności na to pozwalają. Zwłaszcza jeśli czytasz znacznie częściej niż piszesz do stołu.

Ciemna strona (o co właściwie pytałeś)

Jeśli nie mogę cię przekonać o prawej ścieżce, będę asystować również po ciemnej stronie. Jestem elastyczny. :)

Oto demo, jak wymusić unikalność nazw hostów. Używam tabeli hostname do zbierania nazw hostów i wyzwalacza w tabeli host aby go aktualizować. Unikalne naruszenia powodują wyjątek i przerywają operację.

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

Funkcja wyzwalania:

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;

Wyzwalacz:

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

Skrzypce SQL z uruchomieniem testowym.

Użyj indeksu WZ w kolumnie tablicy host.hostnames i operatory tablicowe pracować z nim:

  • Dlaczego mój indeks tablicy PostgreSQL nie jest używany (Rails 4)?
  • Sprawdź, czy w tablicy Postgres znajduje się jakakolwiek z podanej tablicy wartości


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. rozpakuj tablicę postgresql w wiersze

  2. Docker — Jak uruchomić polecenie psql w kontenerze postgres?

  3. Numery seryjne na grupę wierszy dla klucza złożonego

  4. Zresetuj licznik automatycznego przyrostu w postgresie

  5. Niewrażliwe na wielkość liter unikalne pola modelu w Django?