PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

PostgreSQL, тригери и паралелност за налагане на временен ключ

Едно решение е да имате втора таблица, която да използвате за откриване на сблъсъци, и да я попълните с тригер. Използване на схемата, която добавихте във въпроса:

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

(забележка:това е вторият опит поради погрешно разчитане на вашето изискване първия път. Надявам се този път да е правилно).

Някои функции за поддържане на тази таблица:

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
$$;

И попълнете таблицата за първи път с:

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

Сега създайте тригери за попълване на картата с дати след промени в medicinal_products:след вмъкване извиква add_, след актуализиране извиква clr_ (стари стойности) и add_ (нови стойности), след изтриване извиква 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();

Ограничението за уникалност на medicinal_product_date_map ще прихване всички продукти, добавени със същия код в същия ден:

[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

Това зависи от стойностите, които се проверяват за наличие на дискретно пространство - поради което попитах за датите срещу времевите марки. Въпреки че технически клеймата са дискретни, тъй като Postgresql съхранява само микросекундна резолюция, добавянето на запис към таблицата с карти за всяка микросекунда, за която продуктът е приложим, не е практично.

Като казахте това, вероятно бихте могли да се измъкнете и с нещо по-добро от сканиране на цяла таблица, за да проверите за припокриващи се интервали на времеви клейма, с някои трикове за търсене само на първия интервал, а не след или не преди... обаче, за лесни дискретни интервали Предпочитам този подход, който IME може да бъде полезен и за други неща (напр. отчети, които трябва бързо да намерят кои продукти са приложими за определен ден).

Също така харесвам този подход, защото се чувствам правилно да използвам механизма за ограничение на уникалността на базата данни по този начин. Освен това смятам, че ще бъде по-надежден в контекста на едновременни актуализации на главната таблица:без да се заключва таблицата срещу едновременни актуализации, би било възможно тригерът за валидиране да не вижда конфликт и да позволява вмъквания в две едновременни сесии, които са след това се вижда в конфликт, когато ефектите от двете транзакции са видими.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Функция COPY в PostgreSQL

  2. Клауза Go и IN в Postgres

  3. Изпълнете .sql схема в psycopg2 в Python

  4. Как да създадете нова база данни с вече инсталирано разширение hstore?

  5. Възможно ли е да се напише преобразувател на тип данни за обработка на колони JSON на postgres?