sql >> Databasteknik >  >> RDS >> PostgreSQL

PostgreSQL, triggers och samtidighet för att genomdriva en temporär nyckel

En lösning är att ha en andra tabell att använda för att upptäcka sammandrabbningar, och fylla den med en utlösare. Med hjälp av schemat du lade till i frågan:

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

(obs:detta är det andra försöket på grund av att du misstolkade ditt krav första gången. hoppas att det stämmer den här gången).

Några funktioner för att underhålla denna tabell:

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

Och fyll i tabellen första gången med:

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

Skapa nu triggers för att fylla i datumkartan efter ändringar av medicinal_products:efter infoga anrop add_, efter uppdatering anrop clr_ (gamla värden) och add_ (nya värden), efter radera anrop 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();

Unikitetsbegränsningen på medicinal_product_date_map kommer att fånga alla produkter som läggs till med samma kod samma dag:

[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

Detta beror på de värden som kontrolleras för att ha ett diskret utrymme - det var därför jag frågade om datum vs tidsstämplar. Även om tidsstämplar tekniskt sett är diskreta eftersom Postgresql bara lagrar mikrosekundsupplösning, är det inte praktiskt att lägga till en post i karttabellen för varje mikrosekund som produkten är tillämplig för.

Med det sagt kan du förmodligen också komma undan med något bättre än en heltabellsskanning för att kontrollera om det finns överlappande tidsstämpelintervall, med lite knep för att leta efter endast det första intervallet inte efter eller inte före... dock för enkla diskreta utrymmen Jag föredrar detta tillvägagångssätt som IME också kan vara praktiskt för andra saker också (t.ex. rapporter som snabbt måste hitta vilka produkter som är tillämpliga en viss dag).

Jag gillar också detta tillvägagångssätt eftersom det känns rätt att utnyttja databasens unika begränsningsmekanism på detta sätt. Jag tror också att det kommer att vara mer tillförlitligt i samband med samtidiga uppdateringar av huvudtabellen:utan att låsa tabellen mot samtidiga uppdateringar skulle det vara möjligt för en valideringsutlösare att inte se någon konflikt och tillåta infogningar i två samtidiga sessioner, dvs. kan sedan komma i konflikt när båda transaktionens effekter är synliga.



  1. MySQL:Välj all data mellan två datumintervall

  2. PHP PDO och MySQLi

  3. Servering av läcker mat (och data) – En datamodell för restauranger

  4. De vanligaste frågorna om JAVA/JRE i Oracle Apps