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

Langage SQL Discussion :

INSERT INTO seulement s'il n'existe pas dans la table.


Sujet :

Langage SQL

  1. #1
    Modérateur

    Avatar de kOrt3x
    Homme Profil pro
    Technicien Informatique/Webmaster
    Inscrit en
    Septembre 2006
    Messages
    3 650
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Technicien Informatique/Webmaster
    Secteur : Santé

    Informations forums :
    Inscription : Septembre 2006
    Messages : 3 650
    Points : 15 771
    Points
    15 771
    Par défaut INSERT INTO seulement s'il n'existe pas dans la table.
    Bonjour à tous,

    J'aimerai savoir comment faire pour insérer dans ma table une ligne dont la colonne "date" serait une sorte d'id unique.

    Voici ma commande INSERT :

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    INSERT INTO planning VALUES ('2014-09-16','','');

    Ce que je veux, c'est savoir comment éviter d'inserer une nouvelle ligne si la date (unique) est déjà dans la table.

    Sachant que ma colonne "date" est de type DATE (format YYYY-MM-DD).

    Par avance, merci pour votre aide.
    La rubrique Mac
    Les cours & tutoriels Mac
    Critiques de Livres Mac & iOS
    FAQ Mac & iOS

    ________________________________________________________________________
    QuickEvent : Prise de rendez-vous rapide pour iPhone/iPad et iPod Touch (AppStore)
    Mon Livre sur AppleScript : AppleScript: L'essentiel du langage et de ses applications

  2. #2
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Si la date doit être unique, pose une contrainte d'unicité sur la colonne de date.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  3. #3
    Modérateur

    Avatar de kOrt3x
    Homme Profil pro
    Technicien Informatique/Webmaster
    Inscrit en
    Septembre 2006
    Messages
    3 650
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Technicien Informatique/Webmaster
    Secteur : Santé

    Informations forums :
    Inscription : Septembre 2006
    Messages : 3 650
    Points : 15 771
    Points
    15 771
    Par défaut
    Citation Envoyé par CinePhil Voir le message
    Si la date doit être unique, pose une contrainte d'unicité sur la colonne de date.
    Merci pour ta réponse, mais comment fait-on cela ?
    La rubrique Mac
    Les cours & tutoriels Mac
    Critiques de Livres Mac & iOS
    FAQ Mac & iOS

    ________________________________________________________________________
    QuickEvent : Prise de rendez-vous rapide pour iPhone/iPad et iPod Touch (AppStore)
    Mon Livre sur AppleScript : AppleScript: L'essentiel du langage et de ses applications

  4. #4
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Voyez l'aide de votre SGBD l'ordre ALTER TABLE.

    Si vous avez un outil visuel de gestion de votre BDD, ça doit pouvoir se faire en deux clics.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  5. #5
    Modérateur

    Avatar de kOrt3x
    Homme Profil pro
    Technicien Informatique/Webmaster
    Inscrit en
    Septembre 2006
    Messages
    3 650
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Technicien Informatique/Webmaster
    Secteur : Santé

    Informations forums :
    Inscription : Septembre 2006
    Messages : 3 650
    Points : 15 771
    Points
    15 771
    Par défaut
    C'est bon, j'ai trouvé, j'ai recréer ma table avec les infos que tu m'as donné :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    CREATE TABLE `planning` (
      `date` date NOT NULL UNIQUE,
      `planning1` text NOT NULL,
      `planning2` text NOT NULL,
       UNIQUE (`date`)
    )
    Et là j'ai bien une erreur qui m'indique :
    error sqlDuplicate entry '2014-09-17' for key 'date'
    donc c'est bon, il le voit bien en doublon.
    La rubrique Mac
    Les cours & tutoriels Mac
    Critiques de Livres Mac & iOS
    FAQ Mac & iOS

    ________________________________________________________________________
    QuickEvent : Prise de rendez-vous rapide pour iPhone/iPad et iPod Touch (AppStore)
    Mon Livre sur AppleScript : AppleScript: L'essentiel du langage et de ses applications

  6. #6
    Membre émérite Avatar de Drizzt [Drone38]
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2004
    Messages
    1 001
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Directeur de projet

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 001
    Points : 2 453
    Points
    2 453
    Par défaut
    Tu as plusieurs possibilité pour répondre à ton problème initial.

    - Ajouter effectivement une contrainte unique. Dans ce cas, si tu essayes une seconde insertion sur la même date, une erreur de type violation de contrainte unique sera remontée, erreur que tu devras gérer par ton programme appelant.
    - Selon ton SGBD tu peux utiliser l'instruction MERGE INTO, qui te permet de faire une action de type INSERT si ta clef n'existe pas et UPDATE sinon. L'UPDATE pouvant être facultatif.
    - Sinon il faut faire en deux requêtes, une première pour tester l'existence, une seconde pour faire l'insertion.


    Pour ajouter une contrainte unique (à adapter en fonction du SGBD):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ALTER TABLE Persons
     ADD CONSTRAINT uc_PersonID UNIQUE (P_Id,LastName)
    Je ne réponds pas aux questions techniques par MP, le forum est là pour cela.

    La crypto c'est comme les flambys, une fois que tu as trouvé la languette tu as juste à tirer pour tout faire tomber.

    (\ _ /)
    (='.'=)
    Voici Lapinou. Aidez le à conquérir le monde
    (")-(") en le reproduisant

  7. #7
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 768
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 768
    Points : 52 565
    Points
    52 565
    Billets dans le blog
    5
    Par défaut
    Citation Envoyé par Drizzt [Drone38] Voir le message
    Tu as plusieurs possibilité pour répondre à ton problème initial.

    - Ajouter effectivement une contrainte unique. Dans ce cas, si tu essayes une seconde insertion sur la même date, une erreur de type violation de contrainte unique sera remontée, erreur que tu devras gérer par ton programme appelant.
    Oui, c'est la seule solution viable !
    - Selon ton SGBD tu peux utiliser l'instruction MERGE INTO, qui te permet de faire une action de type INSERT si ta clef n'existe pas et UPDATE sinon. L'UPDATE pouvant être facultatif.
    NON, voir ci après
    - Sinon il faut faire en deux requêtes, une première pour tester l'existence, une seconde pour faire l'insertion.
    NON. Vous oubliez une des principales composantes des SGBDR : la concurrence d'accès. Si deux utilisateurs lancent le même bout de code en même temps (et fatalement cela arrivera plus d'une fois) alors vous obtiendrez in fine des doublons.

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  8. #8
    Membre émérite Avatar de Drizzt [Drone38]
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2004
    Messages
    1 001
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Directeur de projet

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 001
    Points : 2 453
    Points
    2 453
    Par défaut
    Oui j'aurais du préciser que dans tous les cas il faut mettre la contrainte d'unicité.

    Par contre je suis surpris sur le MERGE INTO.
    Si je fais deux MERGE INTO en simultané j'aurais en résultat 2 INSERT ? Comment garantir l'intégrité d'un MERGE INTO dans ce cas ?
    N'y a-t-il pas des LOCK qui vont se positionner sur les tables pour éviter ce genre de problème de concurrence d'accès ?
    Je ne réponds pas aux questions techniques par MP, le forum est là pour cela.

    La crypto c'est comme les flambys, une fois que tu as trouvé la languette tu as juste à tirer pour tout faire tomber.

    (\ _ /)
    (='.'=)
    Voici Lapinou. Aidez le à conquérir le monde
    (")-(") en le reproduisant

  9. #9
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par SQLpro Voir le message
    NON, voir ci après
    Merge ne gère pas les accès concurrent ?
    On ne jouit bien que de ce qu’on partage.

  10. #10
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    Citation Envoyé par Drizzt [Drone38] Voir le message
    Si je fais deux MERGE INTO en simultané j'aurais en résultat 2 INSERT ?
    Non, la première transaction validée sera bien enregistrée, la seconde sera refusée car violation de la contrainte d'unicité.

  11. #11
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Waldar Voir le message
    Non, la première transaction validée sera bien enregistrée, la seconde sera refusée car violation de la contrainte d'unicité.
    Hmmm, ok, et y'a pas moyen de locker de façon exclusives les lignes en cours de mise à jour ?
    En effet, je trouve plus propre d'avoir N merge concurrents qui sont mis en file d'attente car non sérialisables, que de me prendre des exceptions d'unicité dans la tête, puis faire des update, sur une ligne qui a potentiellement été supprimée entre le moment où j'ai eu l'exception et le moment où j'ai lancé mon update.

    En gros, imaginons le cas suivant :

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    create table testmerge
    (
         jour date primary key, -- ou unique not null si on veut rester dans l'exemple initial
         donnee varchar(50) not null
    );

    Session 1 souhaite :
    - Dire que le 01/01/1900, on avait la donnée 'A'
    - Dire que le 02/01/1900, on avait la donnée 'B'
    - Supprimer le 02/01/1900 si la donnée est 'B'
    - Dire que le 01/01/1900, on avait finalement la donnée 'C'

    Session 2 souhaite :
    - Dire que le 01/01/1900, on avait la donnée 'D'
    - Un traitement un peu long mais pas trop
    - Dire que le 02/01/1900, on avait la donnée 'E'

    Les deux sessions tournent en //, et les conflits sont résolus de la façon "le dernier qui parle à gagné".

    Lorsque la session 2 tente de faire un INSERT pour le 02/01/1900, on se prend une erreur dans la tête, car la ligne existe.
    Quelques cycles CPU plus tard, la session 1 supprimer la donnée du 02/01/1900 qui n'a pas été modifiée.
    La session 2 tente la mise à jour de la donnée du 02/01/1900... qui n'existe cette fois plus !

    Du coup moi je trouve ça très moyen comme approche.
    Avec des merge (avec un niveau de lock suffisant) on aurait bien la valeur 'E' dans la table, car soit la ligne aurait été supprimée par la première session, et on aurait donc inséré une nouvelle ligne, soit on l'aurait mise à jour dans la session 2 avant que la session 1 ne tente de la supprimer, et vu que data n'était plus égale à 'B', alors session 1 ne l'aurait pas supprimée.

    Comment faire du coup ?
    On ne jouit bien que de ce qu’on partage.

  12. #12
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 768
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 768
    Points : 52 565
    Points
    52 565
    Billets dans le blog
    5
    Par défaut
    Citation Envoyé par Waldar Voir le message
    Non, la première transaction validée sera bien enregistrée, la seconde sera refusée car violation de la contrainte d'unicité.
    Non, mais sans contrainte d'unicité ça génère des doublons. En fait il faut savoir que les requêtes ensemblistes (UNION, INSTERSECT et EXCEPT), tout comme le MERGE sont des requêtes assemblées par partie (SELECTs indépendants...) et ne sont pas intégralement transactionnelles (norme SQL). Du coup il est possible de se retrouver dans des problématiques de doublons...

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  13. #13
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Aucune idée si c'est vraiment une bonne solution, mais en tout cas ça marche :

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    begin transaction
     
    merge into testmerge with (xlock rowlock) as target
    using (select '1900-01-01' jour, 'A' data union select '1900-01-02' jour, 'B' data) as source (jour, donnee)
    on (target.jour = source.jour)
    when matched then
    	update set donnee = source.donnee
    when not matched then
    	insert (jour, donnee) values (source.jour, source.donnee);

    Si je lance dans la foulée, sans commit, dans une autre sessions :
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    begin transaction
     
    merge into testmerge with (xlock rowlock) as target
    using (select '1900-01-01' jour, 'C' data union select '1900-01-02' jour, 'D' data) as source (jour, donnee)
    on (target.jour = source.jour)
    when matched then
    	update set donnee = source.donnee
    when not matched then
    	insert (jour, donnee) values (source.jour, source.donnee);

    Alors la seconde reste en attente.
    Si je commit ou rollback la première, la seconde se lance normalement.

    Et du coup j'ai pas de souci.

    SQL Server 2014 Express
    On ne jouit bien que de ce qu’on partage.

  14. #14
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 768
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 768
    Points : 52 565
    Points
    52 565
    Billets dans le blog
    5
    Par défaut
    Le blocage va dépendre de ton niveau d'isolation et de tes index.

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

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

Discussions similaires

  1. [MySQL] PDO insert into depuis un formulaire n'ecrit pas dans ma bdd
    Par petinico83 dans le forum PHP & Base de données
    Réponses: 13
    Dernier message: 30/12/2013, 17h51
  2. Ajouter une ligne si elle n'existe pas dans la table
    Par daimadoshi dans le forum Requêtes et SQL.
    Réponses: 5
    Dernier message: 19/11/2010, 15h52
  3. [MySQL] extraire des données d'1 table t1 qui n'existent pas dans la table t2
    Par z_ahlam dans le forum PHP & Base de données
    Réponses: 6
    Dernier message: 07/11/2010, 18h07
  4. la selection d'un champ qui n'existe pas dans la table
    Par belaggoun2000 dans le forum Requêtes
    Réponses: 2
    Dernier message: 19/07/2010, 12h41
  5. Réponses: 3
    Dernier message: 12/10/2009, 12h51

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