PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Bisakah PostgreSQL memiliki batasan keunikan pada elemen array?

Jalan lurus

Anda mungkin ingin mempertimbangkan kembali menormalkan skema Anda. Semua orang tidak perlu "bergabung bahkan untuk kueri yang paling sederhana" . Buat VIEW untuk itu.

Tabel dapat terlihat seperti ini:

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

Kunci utama pengganti hostname_id adalah opsional . Saya lebih suka memiliki satu. Dalam kasus Anda hostname bisa menjadi kunci utama. Tetapi banyak operasi lebih cepat dengan integer yang sederhana dan kecil kunci. Buat batasan kunci asing untuk menautkan ke tabel host .
Buat tampilan seperti ini:

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+

Dimulai dengan hal 9.1 , kunci utama dalam GROUP BY mencakup semua kolom tabel itu di SELECT daftar. Catatan rilis untuk versi 9.1:

Izinkan non-GROUP BY kolom dalam daftar target kueri saat kunci utama ditentukan di GROUP BY klausa

Kueri dapat menggunakan tampilan seperti tabel. Mencari nama host akan banyak lebih cepat dengan cara ini:

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

Di Postgres 9.2+ indeks multikolom akan lebih baik jika Anda bisa mendapatkan scan hanya indeks dari itu:

CREATE INDEX hn_multi_idx ON hostname (hostname, host_id);

Dimulai dengan Postgres 9.3 , Anda dapat menggunakan MATERIALIZED VIEW , keadaan memungkinkan. Terutama jika Anda lebih sering membaca daripada menulis di meja.

Sisi gelap (apa yang sebenarnya Anda tanyakan)

Jika saya tidak dapat meyakinkan Anda tentang jalan yang benar, saya akan membantu di sisi gelap juga. saya fleksibel. :)

Berikut adalah demo cara menegakkan keunikan nama host. Saya menggunakan tabel hostname untuk mengumpulkan nama host dan pemicu di tabel host untuk tetap up to date. Pelanggaran unik menimbulkan pengecualian dan membatalkan operasi.

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

Fungsi pemicu:

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;

Pemicu:

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

SQL Fiddle dengan uji coba.

Gunakan indeks GIN pada kolom array host.hostnames dan operator larik untuk bekerja dengannya:

  • Mengapa indeks array PostgreSQL saya tidak digunakan (Rails 4)?
  • Periksa apakah ada larik nilai tertentu yang ada dalam larik 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. Mustahil untuk Menginstal permata PG di mac saya dengan Mavericks

  2. Kolom PostgreSQL tidak ada tetapi sebenarnya ada

  3. Startup aplikasi Spring Boot sangat lambat

  4. Rails 4 session.id kadang nihil

  5. Apa perbedaan antara LATERAL JOIN dan subquery di PostgreSQL?