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

PostgreSQL, trình kích hoạt và đồng thời để thực thi khóa tạm thời

Một giải pháp là có một bảng thứ hai để sử dụng để phát hiện các cuộc đụng độ và điền vào bảng đó bằng một trình kích hoạt. Sử dụng lược đồ bạn đã thêm vào câu hỏi:

CREATE TABLE medicinal_product_date_map(
   aic_code char(9) NOT NULL,
   applicable_date date NOT NULL,
   UNIQUE(aic_code, applicable_date));

(lưu ý:đây là lần thử thứ hai do đọc sai yêu cầu của bạn trong lần đầu tiên. hy vọng lần này đúng).

Một số chức năng để duy trì bảng này:

CREATE FUNCTION add_medicinal_product_date_range(aic_code_in char(9), start_date date, end_date date)
RETURNS void STRICT VOLATILE LANGUAGE sql AS $$
  INSERT INTO medicinal_product_date_map
  SELECT $1, $2 + offset
  FROM generate_series(0, $3 - $2)
$$;
CREATE FUNCTION clr_medicinal_product_date_range(aic_code_in char(9), start_date date, end_date date)
RETURNS void STRICT VOLATILE LANGUAGE sql AS $$
  DELETE FROM medicinal_product_date_map
  WHERE aic_code = $1 AND applicable_date BETWEEN $2 AND $3
$$;

Và điền vào bảng lần đầu tiên với:

SELECT count(add_medicinal_product_date_range(aic_code, vs, ve))
FROM medicinal_products;

Bây giờ, hãy tạo trình kích hoạt để điền vào bản đồ ngày sau khi thay đổi sản phẩm dược:sau khi chèn lệnh gọi add_, sau khi cập nhật lệnh gọi clr_ (giá trị cũ) và add_ (giá trị mới), sau khi xóa lệnh gọi clr_.

CREATE FUNCTION sync_medicinal_product_date_map()
RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
  IF TG_OP = 'UPDATE' OR TG_OP = 'DELETE' THEN
    PERFORM clr_medicinal_product_date_range(OLD.aic_code, OLD.vs, OLD.ve);
  END IF;
  IF TG_OP = 'UPDATE' OR TG_OP = 'INSERT' THEN
    PERFORM add_medicinal_product_date_range(NEW.aic_code, NEW.vs, NEW.ve);
  END IF;
  RETURN NULL;
END;
$$;
CREATE TRIGGER sync_date_map
  AFTER INSERT OR UPDATE OR DELETE ON medicinal_products
  FOR EACH ROW EXECUTE PROCEDURE sync_medicinal_product_date_map();

Ràng buộc về tính duy nhất trên drug_product_date_map sẽ bẫy bất kỳ sản phẩm nào được thêm vào cùng một mã trong cùng một ngày:

[email protected]@[local] =# INSERT INTO medicinal_products VALUES ('1','A','2010-01-01','2010-04-01');
INSERT 0 1
[email protected]@[local] =# INSERT INTO medicinal_products VALUES ('1','A','2010-03-01','2010-06-01');
ERROR:  duplicate key value violates unique constraint "medicinal_product_date_map_aic_code_applicable_date_key"
DETAIL:  Key (aic_code, applicable_date)=(1        , 2010-03-01) already exists.
CONTEXT:  SQL function "add_medicinal_product_date_range" statement 1
SQL statement "SELECT add_medicinal_product_date_range(NEW.aic_code, NEW.vs, NEW.ve)"
PL/pgSQL function "sync_medicinal_product_date_map" line 6 at PERFORM

Điều này phụ thuộc vào các giá trị được kiểm tra xem có khoảng trống riêng biệt hay không - đó là lý do tại sao tôi hỏi về ngày tháng so với dấu thời gian. Mặc dù về mặt kỹ thuật, dấu thời gian là rời rạc vì Postgresql chỉ lưu trữ độ phân giải micro giây, việc thêm một mục vào bảng bản đồ cho mỗi micro giây mà sản phẩm có thể áp dụng là không thực tế.

Phải nói rằng, bạn có thể cũng có thể sử dụng một thứ gì đó tốt hơn là quét toàn bộ bảng để kiểm tra các khoảng thời gian chồng chéo, với một số thủ thuật chỉ tìm khoảng đầu tiên không phải sau hoặc không trước đó ... tuy nhiên, đối với các khoảng trống dễ dàng Tôi thích cách tiếp cận này vì IME cũng có thể hữu ích cho những việc khác (ví dụ:các báo cáo cần tìm nhanh sản phẩm nào có thể áp dụng vào một ngày nhất định).

Tôi cũng thích cách tiếp cận này vì nó cảm thấy đúng khi tận dụng cơ chế ràng buộc tính duy nhất của cơ sở dữ liệu theo cách này. Ngoài ra, tôi cảm thấy nó sẽ đáng tin cậy hơn trong bối cảnh cập nhật đồng thời cho bảng chính:không khóa bảng với các cập nhật đồng thời, có thể trình kích hoạt xác thực không thấy xung đột và cho phép chèn trong hai phiên đồng thời, nghĩa là sau đó được coi là xung đột khi cả hai hiệu ứng của giao dịch đều hiển thị.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Vấn đề làm tròn kỳ lạ

  2. Slick and bonecp:org.postgresql.util.PSQLException:FATAL:xin lỗi, quá nhiều khách hàng đã bị lỗi

  3. truy vấn đệ quy postgres trên cùng một bảng

  4. SQLite to Postgres (Heroku) GROUP BY

  5. Ứng dụng Spring Boot không thể truy cập PostgreSQL bằng thông tin đăng nhập từ Kubernetes secret