PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

PostgreSQL, wyzwalacze i współbieżność w celu wymuszenia klucza tymczasowego

Jednym z rozwiązań jest posiadanie drugiej tabeli do wykrywania kolizji i wypełnienie jej wyzwalaczem. Korzystając ze schematu dodanego do pytania:

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

(uwaga:to druga próba z powodu błędnego odczytania wymagań za pierwszym razem. Mam nadzieję, że tym razem to prawda).

Niektóre funkcje do obsługi tej tabeli:

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

I zapełnij tabelę za pierwszym razem:

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

Teraz utwórz wyzwalacze, aby wypełnić mapę dat po zmianach w produktach medycznych:po wstawieniu wywołań add_, po aktualizacji wywołań clr_ (stare wartości) i add_ (nowe wartości), po usunięciu wywołań 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();

Ograniczenie unikatowości na medical_product_date_map spowoduje uwięzienie wszelkich produktów dodanych z tym samym kodem tego samego dnia:

[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

Zależy to od sprawdzanych wartości pod kątem posiadania dyskretnej przestrzeni - dlatego zapytałem o daty i znaczniki czasu. Chociaż sygnatury czasowe są technicznie dyskretne, ponieważ Postgresql przechowuje tylko rozdzielczość mikrosekundową, dodawanie wpisu do tabeli mapy dla każdej mikrosekundy, w której produkt ma zastosowanie, nie jest praktyczne.

Powiedziawszy to, prawdopodobnie możesz również uciec z czymś lepszym niż skanowanie pełnej tabeli, aby sprawdzić nakładające się interwały znaczników czasu, z pewnymi sztuczkami polegającymi na wyszukiwaniu tylko pierwszego interwału nie po lub nie przed ... jednak dla łatwych dyskretnych spacji Wolę to podejście, które IME może być również przydatne w przypadku innych rzeczy (np. raportów, które muszą szybko znaleźć produkty, które mają zastosowanie w określonym dniu).

Podoba mi się również to podejście, ponieważ wydaje mi się, że w ten sposób można wykorzystać mechanizm ograniczania unikalności bazy danych. Uważam również, że będzie to bardziej niezawodne w kontekście współbieżnych aktualizacji tabeli głównej:bez blokowania tabeli przed współbieżnymi aktualizacjami, możliwe byłoby, aby wyzwalacz walidacji nie widział konfliktu i zezwalał na wstawianie w dwóch równoczesnych sesjach, które są następnie widać konflikt, gdy widoczne są efekty obu transakcji.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Zapytanie parametryczne:Sprawdź, czy pole znajduje się w tablicy wartości w instrukcji SELECT

  2. 2 sposoby zwracania wierszy zawierających tylko znaki alfanumeryczne w PostgreSQL

  3. Jak przekazać klucz tajny DB AWS do tomcat context.xml?

  4. upuść db w postgresie

  5. PostgreSQL - Jak wstawić ciągi obrazów Base64 do kolumny BYTEA?