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 :

Primary Key sur mois et année d'une date


Sujet :

SQLite

  1. #1
    Membre régulier
    Inscrit en
    Décembre 2007
    Messages
    239
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 239
    Points : 92
    Points
    92
    Par défaut Primary Key sur mois et année d'une date
    Bonjour,

    Je voudrais créer une table dans ma base de données ou le mois et l'année serait ma primary key.
    Dans mon programme j'entre bien la date toute entière: 1 juin 2008
    Dans ma base de données je sauvegarde bien la date toute entiere aussi: 1 juin 2008.
    Cela dis, je veux que le prochain enregistrement possible soit celui d'un nouveau mois.

    Si je sauvegarde 1 juin 2008, je veux qu'il soit impossible de sauvegarder 2 juin 2008... jusqu'à la fin du mois. Le prochain enregistrement sera donc celui d'un autre jour d'un autre mois (il ne faut pas que l'enregistrement soit limité au 1 juillet 2008, mais à n'importe quel jour de juillet 2008)

    J'espère me faire comprendre
    et dans l'attente d'une aide quelconque, vous souhaite bonne journée.

  2. #2
    Membre actif

    Inscrit en
    Décembre 2004
    Messages
    169
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 169
    Points : 225
    Points
    225
    Par défaut
    Citation Envoyé par Somato Voir le message
    Bonjour,

    Je voudrais créer une table dans ma base de données ou le mois et l'année serait ma primary key.
    Dans mon programme j'entre bien la date toute entière: 1 juin 2008
    Dans ma base de données je sauvegarde bien la date toute entiere aussi: 1 juin 2008.
    Cela dis, je veux que le prochain enregistrement possible soit celui d'un nouveau mois.

    Si je sauvegarde 1 juin 2008, je veux qu'il soit impossible de sauvegarder 2 juin 2008... jusqu'à la fin du mois. Le prochain enregistrement sera donc celui d'un autre jour d'un autre mois (il ne faut pas que l'enregistrement soit limité au 1 juillet 2008, mais à n'importe quel jour de juillet 2008)

    J'espère me faire comprendre
    et dans l'attente d'une aide quelconque, vous souhaite bonne journée.
    Salut,

    Humm... c'est faisable en passant par un trigger (évidemment) et pas par la primary key. En effet, ton rejet est basé sur un élément de ta colonne et non sur sa valeur complète.

    Je te propose un trigger before insert. Lorsque tu tentes d'insérer un nouvel enregistrement, le trigger recherche la présence d'une clé déjà existante. S'il en trouve une, on retourne une erreur.
    Pour la clé, il suffit de reformater le champ en "YYYYMM" pour obtenir ce que tu veux.

    Voici un exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    DROP TABLE IF EXISTS ma_table;
    CREATE TABLE ma_table (pdate date primary key not null, value text);
     
    CREATE TRIGGER tg1 BEFORE INSERT ON ma_table
    FOR EACH ROW BEGIN
      SELECT RAISE(ROLLBACK, 'pdate doit etre unique')
      WHERE (SELECT 1 FROM ma_table WHERE 
           strftime('%Y%m',pdate) = strftime('%Y%m',NEW.pdate)) IS NOT NULL;
    END;
     
    INSERT INTO ma_table VALUES ( '2008-01-02','a');
    INSERT INTO ma_table VALUES ( '2008-05-15','b');
    INSERT INTO ma_table VALUES ( '2008-06-25','c');
    INSERT INTO ma_table VALUES ( '2008-06-05','d');
    Ce qui donne :

    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
    SQLite version 3.5.9
    Enter ".help" for instructions
    sqlite> DROP TABLE IF EXISTS ma_table;
    sqlite> CREATE TABLE ma_table (pdate date primary key not null, value text);
    sqlite>
    sqlite> CREATE TRIGGER tg1 BEFORE INSERT ON ma_table
       ...> FOR EACH ROW BEGIN
       ...>   SELECT RAISE(ROLLBACK, 'pdate doit etre unique')
       ...>   WHERE (SELECT 1 FROM ma_table WHERE
       ...>        strftime('%Y%m',pdate) = strftime('%Y%m',NEW.pdate)) IS NOT NULL;
     
       ...> END;
    sqlite>
    sqlite> INSERT INTO ma_table VALUES ( '2008-01-02','a');
    sqlite> INSERT INTO ma_table VALUES ( '2008-05-15','b');
    sqlite> INSERT INTO ma_table VALUES ( '2008-06-25','c');
    sqlite> INSERT INTO ma_table VALUES ( '2008-06-05','d');
    SQL error: pdate doit etre unique

    Au passage, voici la page wiki sur les dates :

    http://www.sqlite.org/cvstrac/wiki?p...dTimeFunctions

    a+

  3. #3
    Membre régulier
    Inscrit en
    Décembre 2007
    Messages
    239
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 239
    Points : 92
    Points
    92
    Par défaut
    Ça me parait très bien!

    Etant donné que je veux stocker ma date entière tout de même je verrais deux champs dates dans ma table
    le premier, comme tu l'as dis en YYYYMM et le second qui subira les insert ou update de l'utilisateur.

    Afin de ne pas gérer le champ YYYYMM dans mon programme, y a t'il un moyen de faire en sorte que YYYYMM soit implémenter automatiquement par YYYYMMDD lors d'une insertion / update ?

    EDIT:
    Time Strings

    A time string can be in any of the following formats:

    1. YYYY-MM-DD
    2. YYYY-MM-DD HH:MM
    3. YYYY-MM-DD HH:MM:SS
    4. YYYY-MM-DD HH:MM:SS.SSS
    5. YYYY-MM-DDTHH:MM
    6. YYYY-MM-DDTHH:MM:SS
    7. YYYY-MM-DDTHH:MM:SS.SSS
    8. HH:MM
    9. HH:MM:SS
    10. HH:MM:SS.SSS
    11. now
    12. DDDD.DDDD
    Je ne vois pas le format YYYYMM , j'ai zappé quelque chose?

  4. #4
    Membre actif

    Inscrit en
    Décembre 2004
    Messages
    169
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 169
    Points : 225
    Points
    225
    Par défaut
    Oui, tu as raté quelque chose : ta as mal regardé mon exemple. La réponse y est...


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    SELECT 1 FROM ma_table WHERE
       ...>        strftime('%Y%m',pdate) = strftime('%Y%m',NEW.pdate)) IS NOT NULL;
    C'est donc la fonction strftime() qui va te sauver. Elle permet de formater un champ date (en fait une chaîne de caractères qui ressemble à une date) dans le format de ton choix.

    Ainsi strftime('%Y%m',pdate) génère un texte de la forme YYYYMM. Ce texte peut être déposé dans une colonne de type Integer ou text ou date... et il subira les transformations nécessaires sans que tu ne sois obligé de le typer.

    Donc, je résume :
    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
    DROP TABLE IF EXISTS ma_table;
    CREATE TABLE ma_table (idate integer PRIMARY KEY NOT NULL, sdate date, value text);
     
    CREATE TRIGGER tg1 BEFORE INSERT ON ma_table
    FOR EACH ROW BEGIN
      SELECT RAISE(ROLLBACK, 'Ce mois existe deja.')
      WHERE (SELECT 1 FROM ma_table WHERE 
           strftime('%Y%m',sdate) = strftime('%Y%m',NEW.sdate)) IS NOT NULL;
    END;
     
    CREATE TRIGGER tg2 AFTER INSERT ON ma_table
    FOR EACH ROW BEGIN
      UPDATE ma_table SET idate = strftime('%Y%m',NEW.sdate) WHERE idate=NEW.idate;
    END;
     
     
    INSERT INTO ma_table (sdate,value) VALUES ( '2008-01-02','a');
    INSERT INTO ma_table (sdate,value) VALUES ( '2008-05-15','b');
    INSERT INTO ma_table (sdate,value) VALUES ( '2008-06-25','c');
    INSERT INTO ma_table (sdate,value) VALUES ( '2008-06-05','d');
    SELECT * FROM ma_table;
    Ca fonctionne comme tu le demandes, cependant, méfiance pour l'update après l'insert : on change la clé primaire de type INTEGER avec un update ! C'est typiquement ce type de manipulation qui entraine un bug dans SQLite. Regardes bien : avant l'exécution du trigger TG2, SQLite crée un identifiant unique supérieur au dernier identifiant connu pour cette colonne. Par exemple, ce serait 200807 pour la prochaine valeur. Ensuite, TG2 change cet identifiant, et dans notre cas, pas de problème : ce sera soit cette valeur, soit un mois n'existant pas déjà car le test est fait en TG1. Il peut arriver dans d'autres exemples plus complexes qu'on se mélange les pinceaux et que l'on déclenche une erreur.
    Bref, il faut se méfier des updates de clés primaires et bien comprendre les implications des changements effectués.

    Si tu as des doutes, intègres les nouveaux enregistrements avec un id de ton choix, par exemple '1'. Cet id est temporaire, il changera dans TG2, il n'y aura donc jamais de refus d'intégration.

    voilà,
    a+

  5. #5
    Membre régulier
    Inscrit en
    Décembre 2007
    Messages
    239
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 239
    Points : 92
    Points
    92
    Par défaut
    Impeccable alors !

    En te remerciant encore !

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

Discussions similaires

  1. [AC-2003] Augmenter le jour, le mois, l'année d'une date
    Par jmde dans le forum VBA Access
    Réponses: 2
    Dernier message: 17/05/2014, 14h30
  2. Mois et Année d'une date dans Oracle
    Par minooo dans le forum SQL
    Réponses: 1
    Dernier message: 27/05/2013, 13h20
  3. [BO ??] récupérer le mois et année d'une date
    Par tinah16 dans le forum Designer
    Réponses: 2
    Dernier message: 07/06/2008, 11h03
  4. Grouper sur mois et année (seulement) d'une date
    Par Claythest dans le forum Langage SQL
    Réponses: 4
    Dernier message: 22/03/2007, 12h28
  5. Extraire mois et année d'une date
    Par cnguyen dans le forum SQL
    Réponses: 6
    Dernier message: 13/07/2006, 09h24

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