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

PostgreSQL:Tự động gia tăng dựa trên ràng buộc duy nhất nhiều cột

Sẽ thật tuyệt nếu PostgreSQL hỗ trợ tăng dần "trên một cột phụ trong chỉ mục nhiều cột" như các bảng MyISAM của MySQL

Vâng, nhưng lưu ý rằng khi làm như vậy, MyISAM sẽ khóa toàn bộ bảng của bạn. Sau đó, giúp an toàn khi tìm thấy +1 lớn nhất mà không phải lo lắng về các giao dịch đồng thời.

Trong Postgres, bạn cũng có thể làm điều này mà không cần khóa toàn bộ bảng. Một khóa cố vấn và một bộ kích hoạt sẽ đủ tốt:

CREATE TYPE animal_grp AS ENUM ('fish','mammal','bird');

CREATE TABLE animals (
    grp animal_grp NOT NULL,
    id INT NOT NULL DEFAULT 0,
    name varchar NOT NULL,
    PRIMARY KEY (grp,id)
);

CREATE OR REPLACE FUNCTION animals_id_auto()
    RETURNS trigger AS $$
DECLARE
    _rel_id constant int := 'animals'::regclass::int;
    _grp_id int;
BEGIN
    _grp_id = array_length(enum_range(NULL, NEW.grp), 1);

    -- Obtain an advisory lock on this table/group.
    PERFORM pg_advisory_lock(_rel_id, _grp_id);

    SELECT  COALESCE(MAX(id) + 1, 1)
    INTO    NEW.id
    FROM    animals
    WHERE   grp = NEW.grp;

    RETURN NEW;
END;
$$ LANGUAGE plpgsql STRICT;

CREATE TRIGGER animals_id_auto
    BEFORE INSERT ON animals
    FOR EACH ROW WHEN (NEW.id = 0)
    EXECUTE PROCEDURE animals_id_auto();

CREATE OR REPLACE FUNCTION animals_id_auto_unlock()
    RETURNS trigger AS $$
DECLARE
    _rel_id constant int := 'animals'::regclass::int;
    _grp_id int;
BEGIN
    _grp_id = array_length(enum_range(NULL, NEW.grp), 1);

    -- Release the lock.
    PERFORM pg_advisory_unlock(_rel_id, _grp_id);

    RETURN NEW;
END;
$$ LANGUAGE plpgsql STRICT;

CREATE TRIGGER animals_id_auto_unlock
    AFTER INSERT ON animals
    FOR EACH ROW
    EXECUTE PROCEDURE animals_id_auto_unlock();

INSERT INTO animals (grp,name) VALUES
    ('mammal','dog'),('mammal','cat'),
    ('bird','penguin'),('fish','lax'),('mammal','whale'),
    ('bird','ostrich');

SELECT * FROM animals ORDER BY grp,id;

Điều này dẫn đến:

  grp   | id |  name   
--------+----+---------
 fish   |  1 | lax
 mammal |  1 | dog
 mammal |  2 | cat
 mammal |  3 | whale
 bird   |  1 | penguin
 bird   |  2 | ostrich
(6 rows)

Có một cảnh báo. Các khóa tư vấn được giữ cho đến khi được phát hành hoặc cho đến khi phiên hết hạn. Nếu xảy ra lỗi trong quá trình giao dịch, khóa sẽ được giữ nguyên và bạn cần phải mở khóa theo cách thủ công.

SELECT pg_advisory_unlock('animals'::regclass::int, i)
FROM generate_series(1, array_length(enum_range(NULL::animal_grp),1)) i;

Trong Postgres 9.1, bạn có thể loại bỏ trình kích hoạt mở khóa và thay thế lệnh gọi pg_advisory_lock () bằng pg_advisory_xact_lock (). Cái đó sẽ tự động được giữ cho đến khi và được giải phóng vào cuối giao dịch.

Trên một lưu ý riêng, tôi muốn sử dụng một trình tự cũ tốt. Điều đó sẽ làm cho mọi thứ nhanh hơn - ngay cả khi nó không đẹp bằng khi bạn xem dữ liệu.

Cuối cùng, một chuỗi duy nhất cho mỗi tổ hợp (năm, tháng) cũng có thể được lấy bằng cách thêm một bảng bổ sung, có khóa chính là một chuỗi và giá trị (năm, tháng) có một ràng buộc duy nhất đối với nó.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Điều cần kiểm tra xem Khả năng sử dụng bộ nhớ PostgreSQL có cao không

  2. IntegrityError giá trị khóa trùng lặp vi phạm ràng buộc duy nhất - django / postgres

  3. Cách chèn dữ liệu CSV vào cơ sở dữ liệu PostgreSQL (cơ sở dữ liệu từ xa)

  4. Thời gian chờ truy vấn trong pg-promise

  5. Tham gia SQL cột bí danh