IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

PL/SQL Oracle Discussion :

Emulation contrainte check avec fonction


Sujet :

PL/SQL Oracle

  1. #1
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut Emulation contrainte check avec fonction
    Bonjour,

    Voici mon code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    SET SERVEROUTPUT ON
    /
    create table RANDRIANO.DRIA_TEST (
    	"ID" varchar2(38),
    	"CONTENT" varchar2(38) NOT NULL,
    	"MYVALUE" INT,
    	"SYSTEM" NUMBER (38) DEFAULT 0,
    	CONSTRAINT "PK_DRIA_TEST" PRIMARY KEY(ID) 
        USING INDEX TABLESPACE RANDRIANOINDEX
        ) TABLESPACE RANDRIANODATA 
        LOGGING
    /
    CREATE OR REPLACE TRIGGER RANDRIANO.B_I_DRIA_TEST
    before
    INSERT ON RANDRIANO.DRIA_TEST 
    FOR EACH ROW
    DECLARE
    v_value int;
    BEGIN
     
      v_value := :new.MYVALUE;
     
      dbms_output.put_line('ligneAvant.MYVALUE = ' || v_value);
     
    	if (v_value <> 0 or v_value <>1) then
     
        raise_application_error(-20000,'Check_DRIA_TEST');
     
      end if   ;
     
    END ;
    J'émule donc la contrainte CHECK avec un trigger: ici, on a un simple CHECK sans fonction (MYVALUE <> 0 or MYVALUE <>1)

    Je teste la requête:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    insert into RANDRIANO.DRIA_TEST values('KUAKO','lalala',0,5)
    Ici, j'ai MYVALUE = 1 respectant la contrainte, le dbms_output.put_line l'affiche même mais j'ai toujours
    ERROR at line 1:
    ORA-20000: Check_DRIA_TEST
    ORA-06512: at "RANDRIANO.B_I_DRIA_TEST", line 11
    ORA-04088: error during execution of trigger 'RANDRIANO.B_I_DRIA_TEST'

  2. #2
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut
    Il semble (et testé) que ceci marche
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    DECLARE
    v_value int;
    BEGIN
     
      v_value := :new.MYVALUE;
     
      dbms_output.put_line('ligneAvant.MYVALUE = ' || v_value);
     
    	if ((v_value = 0) or (v_value = 1)) then
     
    	  null;
     
    	else
        raise_application_error(-20000,'Check_DRIA_TEST');
     
      end if   ;
     
    END ;
    Quelle gaffe de ma part: <> et != ne marchent pas avec INT !!!

    Donc, l'émulation de la contrainte est donc un TRIGGER BEFORE INSERT (mais aussi BEFORE UPDATE), FOR EACH ROW doit être présent

  3. #3
    McM
    McM est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Points : 7 740
    Points
    7 740
    Billets dans le blog
    4
    Par défaut

    Ben oui c'est normal, 1 <> 0

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    IF (v_value <> 0 OR v_value <>1) then raise ...

  4. #4
    McM
    McM est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Points : 7 740
    Points
    7 740
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par randriano Voir le message
    Il semble (et testé) que ceci marche

    Quelle gaffe de ma part: <> et != ne marchent pas avec INT !!!
    C'est pas ça, c'est ton test qui est foireux.

    Ce serait plutôt
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    IF v_value NOT IN (0,1) THEN RAISE
    Mais attention, il faut tester le NULL.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    IF NVL(v_value,-1) NOT IN (0,1) THEN RAISE

  5. #5
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut
    Merci McM pour la syntaxe correcte !

    J'ai une question concernant la nécessité d'un trigger sans AFTER EACH ROW, l'avec after each row n'est-il pas le standard? la différence c'est qu'il n'y a pas seulement de old et new

  6. #6
    McM
    McM est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Points : 7 740
    Points
    7 740
    Billets dans le blog
    4
    Par défaut
    LA différence, c'est que l'un se lance 1 seule fois pour un ordre, l'autre se lance pour chaque ligne.

    Donc pour un insert into select *, le trigger BEFORE INSERT ne s'exécutera qu'une seule fois, le trigger BEFORE INSERT FOR EACH ROW s'exécutera autant de fois qu'il y a de lignes.

  7. #7
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut
    Bof, je n'avais pas pensé à ce cas: "insert into select *"
    Donc, les autres SGBD qui n'ont donc que le trigger ligne ne sont pas vraiment optimisés comme le cas de SQL Server et MySql 5.1 ????

  8. #8
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut
    Voici un lien qui approuve la technique du trigger pour émuler une contrainte check avec fonction
    http://www.remote-dba.cc/t_garmany_e...t_triggers.htm
    Mais je me demande est-ce que cela n'est pas encore possible sous 11g?

  9. #9
    Membre confirmé Avatar de rvfranck
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2004
    Messages
    746
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2004
    Messages : 746
    Points : 534
    Points
    534
    Par défaut
    Citation Envoyé par McM Voir le message
    LA différence, c'est que l'un se lance 1 seule fois pour un ordre, l'autre se lance pour chaque ligne.

    Donc pour un insert into select *, le trigger BEFORE INSERT ne s'exécutera qu'une seule fois, le trigger BEFORE INSERT FOR EACH ROW s'exécutera autant de fois qu'il y a de lignes.
    J'ai toujours su la différence entre les deux mais j'ai jamais vraiment compris: est ce que cela veut dire que lorsque l'on insert une seule ligne a la fois on peut utiliser les deux (le resultat est le même), mais que lorsque l'on insert plusieurs lignes à la fois il faut "impérativement" utiliser FOR EACH ROW?

    A vous lire.

  10. #10
    Membre confirmé Avatar de rvfranck
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2004
    Messages
    746
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2004
    Messages : 746
    Points : 534
    Points
    534
    Par défaut
    Salut,

    J'attends toujours que quelqu'un m'aide à comprendre comment fonctionne ce "FOR EACH ROW".

    Merci d'avance,

  11. #11
    McM
    McM est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Points : 7 740
    Points
    7 740
    Billets dans le blog
    4
    Par défaut
    C'est pas compliqué !

    FOR = POUR
    EACH = CHAQUE
    ROW = LIGNE

  12. #12
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut
    Ex:
    INSERT INTO TATA VALUES('1','abc');
    Un trigger de tout niveau (enregistrement/instruction) n'est-il pas le même pour cet insert?
    Un trigger de niveau instruction ne s'exécute qu'une seule fois?
    En fait, peut-on avoir les deux pour une seule table? Est-ce un gâchis?
    Je répond à moi-même: après test, ça se fait!!! Il semble que FOR EACH ROW s'exécute avant le trigger instruction même si c'est un LMD simple

  13. #13
    Membre confirmé Avatar de rvfranck
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2004
    Messages
    746
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2004
    Messages : 746
    Points : 534
    Points
    534
    Par défaut
    Citation Envoyé par McM Voir le message
    C'est pas compliqué !

    FOR = POUR
    EACH = CHAQUE
    ROW = LIGNE
    ça je sais, merci quand même.

  14. #14
    McM
    McM est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Points : 7 740
    Points
    7 740
    Billets dans le blog
    4
    Par défaut
    Je ne vois pas ce que tu ne comprends pas :
    Le For Each Row se lance pour chaque ligne
    Le global (sans clause for each row) se lance une fois pour l'opération DML et ne "voit" donc pas les données des lignes.

    Imagine un UPDATE sur une table (plusieurs lignes)
    2 triggers sur la table,
    Un For Each Row qui pourra te dire quelle ligne a été mise à jour.
    L'autre sans qui pourra te dire 1 update a été passé par tel utilisateur, mais ne saura pas quelle(s) ligne(s) ont été mises à jour..

    Donc :
    est ce que cela veut dire que lorsque l'on insert une seule ligne a la fois on peut utiliser les deux (le resultat est le même)
    La réponse est non. Tu n'as pas accès aux mêmes données suivant les triggers.

  15. #15
    Membre confirmé Avatar de rvfranck
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2004
    Messages
    746
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2004
    Messages : 746
    Points : 534
    Points
    534
    Par défaut
    C'est très clair maintenant, merci.
    P.S: Tu peux être un bon prof, quand tu veux.

  16. #16
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut
    Si on a les 2 types de niveau sur une même table, qui s'exécute le premier lors d'un simple INSERT ?
    Je comprends que pour un DELETE FROM Mytable, c'est le EACH ROW qui s'exécute en 1er car en général il y a plusieurs lignes à supprimer dans ce cas et le sans EACH ROW quand tout est fini

  17. #17
    McM
    McM est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Points : 7 740
    Points
    7 740
    Billets dans le blog
    4
    Par défaut
    Non, c'est trop généraliser que de dire ça.
    Tu as les triggers BEFORE et AFTER, et ensuite la déclinaison FOR EACH ROW ou pas.

    Mes cours disent (mais c'était avant la version 8)
    1- Before
    2- Before For Each Row
    3- After For Each Row
    4- After

  18. #18
    Membre expérimenté
    Avatar de randriano
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Madagascar

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 219
    Points : 1 438
    Points
    1 438
    Par défaut
    Citation Envoyé par McM Voir le message
    Non, c'est trop généraliser que de dire ça.
    Tu as les triggers BEFORE et AFTER, et ensuite la déclinaison FOR EACH ROW ou pas.

    Mes cours disent (mais c'était avant la version 8)
    1- Before
    2- Before For Each Row
    3- After For Each Row
    4- After
    Je confirme cet ordre!!!
    J'aimerais seulement émettre mon soucis des Before/After simple (pas FER) car ils se déclenchent toujours dans le cas d'un DELETE même si 0 rows deleted

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Emuler contrainte CHECK
    Par CinePhil dans le forum SQL Procédural
    Réponses: 2
    Dernier message: 22/08/2010, 10h39
  2. contrainte check et fonction
    Par r83 dans le forum SQL
    Réponses: 3
    Dernier message: 05/01/2010, 08h46
  3. Probleme pour une contrainte CHECK avec MySQL
    Par dave260888 dans le forum Requêtes
    Réponses: 2
    Dernier message: 18/07/2008, 23h11
  4. Mettre un intervall avec une contrainte check
    Par vodevil dans le forum MS SQL Server
    Réponses: 6
    Dernier message: 06/12/2006, 07h32
  5. contraint CHECK avec lecture de données sur une autre table ?
    Par mamiberkof dans le forum Langage SQL
    Réponses: 1
    Dernier message: 22/05/2006, 10h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo