Forum Programmation.autre Soucis de SQL....

Posté par  .
Étiquettes :
0
23
août
2004
Bon, voilà,
j'ai une table dans laquelle j'ai deux champs de type date, non nuls, appelés respectivement dat_deb et dat_fin (date de début et date de fin... trop original !). J'ai ajouté une contrainte d'intégrité sur dat_fin pour m'assurer que dat_fin > dat_deb comme suit :

create table blabla
(
...
dat_deb date not null,
dat_fin date not null check (dat_fin > dat_deb),
...);

Je travaille avec postgreSQL 7.3.4, et j'aimerai écrire un trigger qui interdise d'ajouter une ligne dans cette table blabla pour laquelle la période désignée par dat_deb et dat_fin ne soit pas incluse dans une période déjà déclarée dans une autre ligne (est-ce clair, j'en doute...). Bon, un exemple :

Si je fais :
insert into blabla (dat_deb, dat_fin) values ('01/09/2004', '31/12/2004');
je veux qu'ensuite un :
insert into blabla (dat_deb, dat_fin) values ('01/10/2004', '20/11/2004');

me renvoie une erreur , ou mieux encore :
me découpe la première en '01/09/2004' -> '30/09/2004', puis fasse l'ajout demandé, puis m'ajoute une nouvelle ligne allant du '21/11/2004' au '31/12/2004'...
Ca vous parait jouable ? Si oui, comment, de préférence en PlPgSQL ?
Merci de m'avoir lu jusque là !
  • # pour renvoyer une erreur

    Posté par  . Évalué à 3.

    Pour renvoyer une erreur lorsque des périodes se chevauchent, il faut à mon avis procéder en deux étapes : d'abord une fonction indiquant si deux périodes se chevauchent et ensuite un trigger appelant cette fonction pour déterminer s'il y a erreur ou non.

    Par exemple, une fonction
    CREATE FUNCTION areExclusivePeriods( DATE, DATE, DATE, DATE)
    RETURNS boolean AS'
    DECLARE
    debut1 ALIAS FOR $1;
    fin1 ALIAS FOR $2;
    debut2 ALIAS FOR $3;
    fin2 ALIAS FOR $4;
    BEGIN
    IF (debut1>fin1) OR (debut2>fin2) THEN
    RAISE EXCEPTION ''Périodes mal délimitées (début de période ne précède pas la fin) !'';
    END IF;

    IF (debut2<debut1 AND fin2<debut1) OR (debut2>fin1 AND fin2>fin1) THEN
    RETURN ''t'';
    ELSE
    RETURN ''f'';
    END IF;
    END;
    ' LANGUAGE 'plpgsql';

    Cette fonction renvoie 't' lorsque les périodes sont exclusives et 'f' sinon.

    puis une deuxième fonction sollicitée par le trigger ; par exemple :
    CREATE FUNCTION blabla_insert() RETURNS TRIGGER AS'
    DECLARE
    rec RECORD;
    BEGIN
    SELECT INTO rec * FROM blabla WHERE areExclusivePeriods( dat_deb, dat_fin, NEW.dat_deb, NEW.dat_fin )=''f'';
    IF FOUND THEN
    RAISE EXCEPTION ''Conflit entre les périodes du % au % et du % au %'', rec.dat_deb, rec.dat_fin, NEW.date_deb, NEW.date_fin;
    ELSE
    RETURN NEW;
    END;
    END;'
    LANGUAGE 'plpgsql';

    Enfin le trigger à proprement parler :
    CREATE TRIGGER trg_blabla_insert BEFORE INSERT OR UPDATE ON blabla FOR EACH ROW EXECUTE PROCEDURE blabla_insert();

    En espérant ne pas être trop à côté de la plaque ...

    P.S : découper les périodes si chevauchement il y a devrait être possible, mais je ne l'ai jamais fait ...
    En clair c'est jouable à mon avis ! (je vais pas tout faire à ta place non plus !)
    • [^] # Re: pour renvoyer une erreur

      Posté par  . Évalué à 1.

      Ok !
      Merci, ta réponse m'inspire... En fait, c'est plus simple que je ne pensais !
      Alors, la fonction simplifiée donnerait quelquechose de ce genre (pas encore eu le temps de tester, c'est juste l'inspiration du moment...) :

      CREATE FUNCTION areExclusivePeriods( DATE, DATE, DATE, DATE)
      RETURNS boolean AS'
      DECLARE
      debut1 ALIAS FOR $1;
      fin1 ALIAS FOR $2;
      debut2 ALIAS FOR $3;
      fin2 ALIAS FOR $4;
      retval boolean;
      BEGIN
      IF (((debut2 >= fin1) AND (fin2 > debut2)) or ((debut1 >= fin2) and (debut1 > fin1))
      then
      retval := true;
      else
      retval := false;
      end if;
      return retval;
      end;
      ' LANGUAGE 'plpgsql';

      En fait, de part les contraintes (check...), il est même probable que la deuxième partie du test (finN > debutN) ne soit pas indispensable, par contre il rend le code plus lisible, je le garde donc (en plus, sans, la fonction n'a plus aucun sens et ne fonctionne pas comme il faut.... ). J'ai fait des tests, même en renseignant des trucs bizare, ça à l'air de fonctionner.... Ca me plait bien.
      Pour le trigger, rien à redire, ça me plait bien aussi....
      Je m'en vais intégrer tout ça !
      Merci pour l'inspiration.... J'étais vraiment dans le gaz ce matin !

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.