sql >> Database >  >> RDS >> PostgreSQL

PostgreSQL, triggers en gelijktijdigheid om een ​​tijdelijke sleutel af te dwingen

Een oplossing is om een ​​tweede tabel te gebruiken voor het detecteren van botsingen en die te vullen met een trigger. Gebruik het schema dat u aan de vraag hebt toegevoegd:

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

(Opmerking:dit is de tweede poging vanwege een verkeerde lezing van uw vereiste de eerste keer. Ik hoop dat het deze keer goed is).

Enkele functies om deze tabel te onderhouden:

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

En vul de tafel de eerste keer met:

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

Maak nu triggers om de datumkaart te vullen na wijzigingen aan medicinale_producten:na het invoegen van oproepen add_, na het bijwerken van oproepen clr_ (oude waarden) en add_ (nieuwe waarden), na het verwijderen van oproepen 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();

De uniciteitsbeperking op medicinal_product_date_map zal alle producten die op dezelfde dag met dezelfde code worden toegevoegd, tegenhouden:

[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

Dit hangt af van de waarden die worden gecontroleerd op een discrete spatie. Daarom vroeg ik naar datums versus tijdstempels. Hoewel tijdstempels technisch gezien discreet zijn, aangezien Postgresql alleen resolutie van microseconden opslaat, is het niet praktisch om een ​​item aan de kaarttabel toe te voegen voor elke microseconde waarvoor het product van toepassing is.

Dat gezegd hebbende, zou je waarschijnlijk ook weg kunnen komen met iets beters dan een volledige tabelscan om te controleren op overlappende tijdstempelintervallen, met wat bedrog bij het zoeken naar alleen het eerste interval, niet erna of niet ervoor... echter, voor gemakkelijke discrete ruimtes Ik geef de voorkeur aan deze aanpak, omdat IME ook voor andere dingen handig kan zijn (bijvoorbeeld rapporten waarin snel moet worden gevonden welke producten op een bepaalde dag van toepassing zijn).

Ik hou ook van deze benadering omdat het goed voelt om op deze manier gebruik te maken van het uniekheidsbeperkingsmechanisme van de database. Ik denk ook dat het betrouwbaarder zal zijn in de context van gelijktijdige updates van de hoofdtabel:zonder de tabel te vergrendelen tegen gelijktijdige updates, zou het mogelijk zijn voor een validatietrigger om geen conflict te zien en invoegingen toe te staan ​​in twee gelijktijdige sessies, die dan conflicterend wanneer de effecten van beide transacties zichtbaar zijn.



  1. Hoe kan ik de unieke karakters uit een string in Oracle halen?

  2. Veilige databaseverbindingen met Java-threads

  3. Niet-Engelse decimale punten invoegen in mysql

  4. kan ik een alleen-lezen database openen vanuit de res/asset-map in Android zonder te kopiëren naar de databasemap?