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

SQLite Discussion :

Problème de trigger


Sujet :

SQLite

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Inscrit en
    Décembre 2007
    Messages
    239
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 239
    Par défaut Problème de trigger
    Bonjour,

    J'ai beaucoup de mal avec SQL, notamment avec les triggers récement.

    Voila ce que j'aimerai faire : un trigger before insert qui vérifie si certain champ ne sont pas à NULL (ou vide, entre simple quote). Si certains de ces champs, ou tous ces champs, sont NULL, je veux les forcer à 0,00 (champs de type DOUBLE).

    Comment procéder ? Puis-je tester tous mes champs dans un seul trigger, ou faut-il un trigger pour chaque champ à tester ?

    Voila ce que j'ai entrepris de faire, pour un seul champ :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    CREATE TRIGGER triggerComptaLoc BEFORE INSERT ON ComptaLoc
    FOR EACH ROW 
    BEGIN
    WHERE (SELECT * FROM ComptaLoc WHERE divers ='') = (divers = '0,00'))
    END
    ça ne fonctionne pas et je m'y perds dans la syntaxe des triggers du coup...
    J'ai aussi vu qu'il existe un type de champ pour la monnaie dans certaine base de données (champ de type MN je crois) mais je n'ai rien vu de semblable dans la doc SQLite, je me trompe ?

    Si cela existe, est-ce que ce champ pour résoudre mon problème de trigger plus simplement ?
    Merci d'avance !

  2. #2
    Membre habitué
    Profil pro
    Inscrit en
    Février 2007
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 15
    Par défaut trigger (déclencheur)
    inutile d'utiliser des déclencheurs pour ce genre de test

    voici un exemple de déclaration de table

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    CREATE TABLE 'Systemes'
    (
        'codeSysteme' INT NOT NULL,
        'description' VARCHAR(50) NOT NULL,
        'sendMail' INT NOT NULL DEFAULT (1),
        CONSTRAINT PK_Systemes PRIMARY KEY (CodeSysteme)
    );
    remarque: les guillemets ne sont pas nécessaires s'il n'y a pas d'espace dans les noms des champs (ce qui serait un très mauvaise idée, comme les accents d'ailleurs).

    le mot-clé DEFAULT permet d'assigner une valeur d'office aux champs de valeur NULL: DEFAULT (0.0) par ex.

    jjc

  3. #3
    Membre expérimenté

    Inscrit en
    Décembre 2004
    Messages
    169
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 169
    Par défaut
    Voici une syntaxe possible de ton trigger :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    CREATE TRIGGER triggerComptaLoc BEFORE INSERT ON ComptaLoc
    FOR EACH ROW 
    BEGIN
      UPDATE ComptaLoc SET NEW.divers = CAST( 0 AS DOUBLE )
      WHERE NEW.divers is NULL or NEW.divers = '';
    END;
    Tu peux mettre autant de requêtes UPDATE que tu le veux dans un trigger, inutile donc de créer un trigger pour chaque champ.

    Le trigger permet de renforcer les contraintes et les valeurs par défaut comme l'a indiqué jjc_Mtl. Malgré la valeur par défaut, rien ne t'empêcherait de mettre la valeur '' (chaîne vide) dans le champ car celle-ci est différente de la valeur NULL.

    J'ai utilisé la commande CAST( xx AS yy) pour donner un exemple de son utilisation et aussi éviter une syntaxe de type NEW.divers = '0,00' car le nombre de 0 significatifs ne dépend pas du type (DOUBLE) mais uniquement de l'affichage lors de tes requêtes SELECT.


    a+

  4. #4
    Membre confirmé
    Inscrit en
    Décembre 2007
    Messages
    239
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 239
    Par défaut
    Merci beaucoup à vous deux !
    la commande DEFAULT est bien utile, mais en effet, je crois que sous mon programme lorsque je suis parfois obliger de gérer certaines opérations avec des simple quote, car "NOT NULL" ne me retourne pas ce que je demande.

    Je vais donc devoir opter pour le trigger dans ce cas de figure.

    Par contre, j'ai aussi une autre question.
    SQLite permet bien des choses lors des insert de certain type (par exemple, une chaine de caractère entre quote ('00001') peut être insérée dans un champ de type INTEGER (au même titre qu'une insertion d'un chiffre simple : 00001)

    J'ai expérimenté ceci car dans mon programme, je gére les champs DOUBLE avec des virgules (0,00) et non avec des points (0.00) est la virgule ne passe pas dans le champ DOUBLE de SQLite sauf lorsque qu'on met des simple quote ('0,00').

    Donc ma question : est ce que ça gène si je veux faire des opérations de mes DOUBLE sous SQLite dans un "trigger after insert" ?

    Merci d'avance !

  5. #5
    Membre confirmé
    Inscrit en
    Décembre 2007
    Messages
    239
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 239
    Par défaut
    Excuse moi Bigane,

    Je peux savoir ce que tu utilises comme éditeur de base de données SQLite ?
    J'utilise SQLiteman, est il ne me prend pas le code source que tu me fournis à chaque fois (pourtant j'essaie d'adapter, mais il me détecte des erreurs un peu partout à chaque fois...)

    En fait il ne veut pas prendre "new." ou encore "old." apparemment.
    Apparemment ça pose problème, le test d'insert que j'ai pu effectuer ne fonctionne pas.

    Merci d'avance

  6. #6
    Membre expérimenté

    Inscrit en
    Décembre 2004
    Messages
    169
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 169
    Par défaut
    Bonjour somato,

    Mea culpa : le script donné est bourré d'erreurs, ça m'apprendra à vouloir répondre trop vite...

    pour l'édition du code, je n'utilise rien de particulier. C'est avec un éditeur de texte que je construis mes requêtes, ensuite je les teste avec la version DOS de SQLite (pour un rendu plus graphique, j'utilise sqlite-administrator : http://sqliteadmin.orbmu2k.de/ ).

    Pour ce faire, je dépose SQLite3.exe et SQLite3.dll dans un répertoire pour faire simple disons C:\SQLite\Bin. Ensuite je me crée un répertoire de travail (disons C:\SQLite\Etudes ).

    Dans ce répertoire je crée un fichier etude.bat dans lequel je copie ce code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @echo off
    %~d0
    cd "%~p0"
    echo.
    echo.
    echo Ouverture de la base ...
    echo.
    echo.
    C:\SQLite\Bin\sqlite3.exe etudes.db
    pause
    Et me voici donc en présence du meilleur outil disponible : le moteur lui même ! Pour ce qui est de l'édition du code, tu peux utiliser Notepad++ ou Programmer's Notepad 2 avec une coloration syntaxique que tu peux modifier. Il y en a bien d'autres (utraedit32...), tu peux même créer des macros qui lancent tes scripts. Mais j'aime bien la simplicité... alors j'utilise le batch.

    Voici donc un nouveau script testé :
    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
    BEGIN TRANSACTION;
    drop table if exists ComptaLoc;
    create table ComptaLoc (
    id integer primary key,
    divers NUMBER (12,2) default 0.00);
     
    CREATE TRIGGER triggerComptaLoc AFTER INSERT ON ComptaLoc
    FOR EACH ROW 
    BEGIN
      UPDATE ComptaLoc SET divers = CAST( 0 AS DOUBLE )
      WHERE (NEW.divers IS NULL OR NEW.divers = '') AND NEW.rowid = rowid;
    END;
     
    insert into ComptaLoc values (1,0);
    insert into ComptaLoc values (2,1.01);
    insert into ComptaLoc values (3,2);
    insert into ComptaLoc values (4,NULL);
    insert into ComptaLoc values (5,'');
    insert into ComptaLoc values (6,'ok');
     
    END TRANSACTION;
     
    .mode tab
     
    select 'Resultats :';
    select id, divers from ComptaLoc;
    Voici le résultat :
    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
     
     
    Ouverture de la base ...
     
     
    SQLite version 3.6.1
    Enter ".help" for instructions
    Enter SQL statements terminated with a ";"
    sqlite> .read etude.sql
    Resultats :
    1       0
    2       1.01
    3       2
    4       0
    5       0
    6       ok
    sqlite>
    Que remarque-t-on ?

    - J'utilise NUMBER (12,2) pour signaler un nombre avec deux décimales, mais SQLite s'en moque et ne retient que NUMBER.
    - J'utilise 0.00 : comme valeur par défaut... je suis logique avec ma syntaxe et on ne sait pas ce que sera SQLite dans dix ans.
    - J'utilise CAST( 0 AS DOUBLE ) pour forcer le type encore une fois, pas grave : SQLite retient que c'est un nombre décimal et mémorise sa valeur : 0.
    - SQLite ne considère pas qu'une chaine { insert into ComptaLoc values (6,'ok'); } soit une erreur pour un champ typé en Number, c'est à nous de déclencher l'erreur par un trigger.

    Mes erreurs dans le script précédent : SET new.driver = xxx ne fonctionne pas, en effet les valeurs qui vont être insérées, modifiées ou supprimées sont en lecture seule. Il fallait donc passer en mode AFTER INSERT et modifier la donnée après son insertion dans la base. Un trigger BEFORE est surtout utile pour tester la validité de la donnée et déclencher une erreur pour éviter de polluer la base avec une donnée incohérente.
    (xxxx) AND NEW.rowid = rowid; cette instruction permet de ne modifier que la dernière donnée insérée et non toutes les lignes de la table !

    Pour finir, tu fais une erreur de penser qu'SQLite considère la chaine '0,00' comme étant un nombre. C'est bien une chaine, même si tu peux forcer son interprétation en nombre. Aussi, si tu dois écrire dans un champ un nombre, par exemple pour faire de la comptabilité, il faut utiliser le type NUMBER, ou NUMBER (x,y) ou DOUBLE... bref du nombre. Il faudra ensuite forcer un affichage de ce nombre avec des virgules depuis ton programme.
    Remarque en passant : le séparateur (interne) de décimale est le point et non la virgule. Il faut comprendre que ce séparateur n'est utilisé qu'à deux moments : lorsque SQLite décode une chaine SQL et lorsque SQLite génère le résultat d'une requête SQL. En interne la décimale n'est pas représentée. Il faut donc que fournisses une chaine SQL compréhensible par le moteur d'analyse, puis que tu fasses la conversion d'affichage du résultat selon les propriétés de ton pays.

    Voilà tout,
    a+

Discussions similaires

  1. PL/SQL problème sur Trigger
    Par kitsune dans le forum PL/SQL
    Réponses: 4
    Dernier message: 06/12/2005, 21h35
  2. [9i] problème avec trigger after logon
    Par Michael# dans le forum Oracle
    Réponses: 2
    Dernier message: 17/03/2005, 13h14
  3. [Interbase6] Problème de triggers
    Par emeraudes dans le forum Bases de données
    Réponses: 4
    Dernier message: 08/03/2005, 10h52
  4. [SQLPLUS] - Problème de Triggers Java
    Par farcis dans le forum Oracle
    Réponses: 7
    Dernier message: 23/12/2004, 10h21
  5. [PL/SQL] problème de trigger
    Par Chuck67 dans le forum Oracle
    Réponses: 14
    Dernier message: 10/12/2004, 00h17

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