PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

PostgreSQL có thể có ràng buộc về tính duy nhất đối với các phần tử mảng không?

Con đường chính nghĩa

Bạn có thể muốn xem xét lại chuẩn hóa lược đồ của bạn. Mọi người không nhất thiết phải "tham gia ngay cả với truy vấn đơn giản nhất" . Tạo VIEW cho điều đó.

Bảng có thể trông như thế này:

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

Khóa chính thay thế hostname_id tùy chọn . Tôi thích có một cái hơn. Trong trường hợp của bạn hostname có thể là khóa chính. Nhưng nhiều thao tác nhanh hơn với integer đơn giản, nhỏ Chìa khóa. Tạo ràng buộc khóa ngoại để liên kết với bảng host .
Tạo một dạng xem như thế này:

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+

Bắt đầu với pg 9.1 , khóa chính trong GROUP BY bao gồm tất cả các cột của bảng đó trong SELECT danh sách. Các ghi chú phát hành cho phiên bản 9.1:

Cho phép không phải GROUP BY trong danh sách đích truy vấn khi khóa chính được chỉ định trong GROUP BY mệnh đề

Các truy vấn có thể sử dụng dạng xem như một bảng. Tìm kiếm tên máy chủ sẽ nhiều nhanh hơn theo cách này:

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

Trong Postgres 9.2+ chỉ mục nhiều cột sẽ còn tốt hơn nếu bạn có thể nhận được bản quét chỉ chỉ mục ra khỏi nó:

CREATE INDEX hn_multi_idx ON hostname (hostname, host_id);

Bắt đầu với Postgres 9.3 , bạn có thể sử dụng MATERIALIZED VIEW , hoàn cảnh cho phép. Đặc biệt nếu bạn đọc thường xuyên hơn nhiều so với việc bạn ghi vào bảng.

Mặt tối (những gì bạn thực sự hỏi)

Nếu tôi không thể thuyết phục bạn về con đường chính nghĩa, tôi cũng sẽ hỗ trợ cho mặt tối. Tôi linh hoạt. :)

Đây là bản demo cách thực thi tính duy nhất của tên máy chủ. Tôi sử dụng một bảng hostname để thu thập tên máy chủ và trình kích hoạt trên bảng host để giữ cho nó được cập nhật. Các vi phạm duy nhất đưa ra một ngoại lệ và hủy bỏ hoạt động.

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

Chức năng kích hoạt:

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;

Kích hoạt:

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

SQL Fiddle với quá trình chạy thử nghiệm.

Sử dụng chỉ mục GIN trên cột mảng host.hostnames toán tử mảng để làm việc với nó:

  • Tại sao chỉ mục mảng PostgreSQL của tôi không được sử dụng (Rails 4)?
  • Kiểm tra xem có bất kỳ mảng giá trị nhất định nào trong mảng Postgres không


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm thế nào để loại bỏ cơ sở dữ liệu PostgreSQL nếu có các kết nối đang hoạt động với nó?

  2. Kiểm tra xem giá trị có tồn tại trong mảng Postgres không

  3. Xóa các hàng trùng lặp khỏi bảng nhỏ

  4. Hiệu suất khác biệt:điều kiện được đặt tại mệnh đề INNER JOIN so với WHERE

  5. Date_trunc của PostgreSQL trong mySQL