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

MS SQL Server Discussion :

Vérifier doublons avant insertion (transaction, verrouillage et procédure stockée)


Sujet :

MS SQL Server

  1. #1
    Membre du Club
    Inscrit en
    Janvier 2008
    Messages
    70
    Détails du profil
    Informations forums :
    Inscription : Janvier 2008
    Messages : 70
    Points : 55
    Points
    55
    Par défaut Vérifier doublons avant insertion (transaction, verrouillage et procédure stockée)
    Bonjour,


    Je veux (par exemple) tester si une personne existe déjà dans la base de données avant de l'insérer. Admettons que l'on fasse ce test par rapport au nom de la personne. On est dans une application multi-utilisateur.

    Je fais une transaction SQL dans une procédure stockée.

    pseudo code :

    1) Début Transaction
    2) declaration de @nbDoublon
    3) SELECT @nbDoublon = COUNT(*) FROM t_personne WHERE personne_nom='quelquun';
    4) IF @nbDoublon = 0 INSERT etc...
    5) Fin transaction

    Voici ma question :

    Si j'utilise l'isolation par défaut de SQL-SERVER (read commited) est ce qu'il n'y a pas un risque qu'entre l'étape 3 et 4 une requête concurrente s'insère et que donc j'insère un doublon ?

    En effet, le mode read commited ne vérouille pas les SELECT

    Faut il passer par un verouillage serializable ?

    N'y a t'il pas une autre solution ?

    - par exemple faire la verif dans la même instruction INSERT..

    - executer le select, le if et le insert via un sp_executesql (les intructions d'un sp_executesql sont ils exécutés en une seule fois cad pas de risque de requêtes concurrentes qui s'insèrent entre ses instructions ?)

    Si je passe par une transaction serializable, y a pas de soucis ? (à priori non mais ça fait toujorus peur ce genre de transactions)

  2. #2
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 901
    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 901
    Points : 53 143
    Points
    53 143
    Billets dans le blog
    6
    Par défaut
    Il faut au moins le niveau SERIALIZABLE.

    Mais je ne voit pas l'intérêt de faire cela en 2 ordres SQL avec une transaction.? Le mieux étant de le faire sans transaction en un seul ordre SQL :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    INSERT INTO MaTable
    SELECT 'Dupont'
    WHERE NOT EXISTS (SELECT *
                        FROM MaTable
                        WHERE Nom = 'Dupont')
    A +

  3. #3
    Membre du Club
    Inscrit en
    Janvier 2008
    Messages
    70
    Détails du profil
    Informations forums :
    Inscription : Janvier 2008
    Messages : 70
    Points : 55
    Points
    55
    Par défaut
    Bonjour SqlPro,

    Merci pour votre réponse.

    Il me manquait cette notion de NOT EXISTS merci !!

    Par contre, le fait de le gérer en deux requêtes, me permettrai par exemple de faire un RAISEERROR afin de récupérer l'erreur dans l'application (asp.net) et avertir l'utilisateur..

    Je ne me trompe pas ?

    P.S. : Pour la transaction, c'est par ce que je récupére l'id auto généré et j'insére des valeurs dans des relations.



    merci

  4. #4
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 901
    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 901
    Points : 53 143
    Points
    53 143
    Billets dans le blog
    6
    Par défaut
    Pour l'erreur si pas d'insertion, interrogez le compteur de ligne dans votre L4G.

    Pour obtenir la clef autoincrémentée, utilisez la fonction SCOPE_IDENTITY() après l'insertion. Elle n'a pas à figurer dans la transaction.

    A +

  5. #5
    Membre du Club
    Inscrit en
    Janvier 2008
    Messages
    70
    Détails du profil
    Informations forums :
    Inscription : Janvier 2008
    Messages : 70
    Points : 55
    Points
    55
    Par défaut
    Merci !!

  6. #6
    Membre à l'essai
    Inscrit en
    Juin 2008
    Messages
    26
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 26
    Points : 13
    Points
    13
    Par défaut Doublons...
    Bonjour,

    Je suis un peu dans le même cas (application multi-utilisateurs sous SQL2000) avec une table permettant de gérer un "compteur" que je récupère dans le code de mon application C#.

    Voici un extrait du contenu de ma procédure stockée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    	
    	SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
    	BEGIN TRANSACTION;
    	IF 	((SELECT count(*) FROM [MaTable]) = 0)
    	BEGIN
    	/*(1)*/	SET @MaVariable = 1 ;
    	/*(2)*/	INSERT INTO [MaTable]([MonChamp]) VALUES(@MaVariable) ;
    	END
    	ELSE
    	BEGIN
    	/*(3)*/	SELECT @MaVariable = [MonChamp] + 1 FROM [MaTable]
    	/*(4)*/	UPDATE [MaTable] SET [MonChamp] = @MaVariable
    	END
    	COMMIT TRANSACTION;
    Apparemment, il arrive que cela me donne des doublons. Comment est-ce possible ?
    Imaginons que la procédure stockée soit appelée 2 fois quasi simultanément (donc 2 transactions X et Y), est-ce possible que la requête SELECT (N° 3) soit exécutée par X puis par Y et seulement ensuite que la requête UPDATE (N° 4) soit exécutée par X puis par Y ?

    Dans la clause "ELSE", j'avais pensé à passer la requête "UPDATE" avant le "SELECT".
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    UPDATE [MaTable] SET [MonChamp] = [MonChamp] + 1
    SELECT @MaVariable = [MonChamp] FROM [MaTable]
    Cela changerait-il quelque chose ?

  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 901
    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 901
    Points : 53 143
    Points
    53 143
    Billets dans le blog
    6
    Par défaut
    Inverser le SELECT et l'UPDATE.... Commencez par l'UPDATE...

    A +

  8. #8
    Membre à l'essai
    Inscrit en
    Juin 2008
    Messages
    26
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 26
    Points : 13
    Points
    13
    Par défaut
    C'est bien ce que je pensais ....
    Merci beaucoup de votre réponse !

  9. #9
    Candidat au Club
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 3
    Points : 3
    Points
    3
    Par défaut
    Bonjour,

    J'aimerais comprendre cette syntaxe (sorry je ne la connaissais pas).
    Supposons que je veuille faire une insertion du type :
    INSERT INTO MaTable (`champ1`,`champ2`) VALUES('value1','value2);

    Et que le test serait qu'il ne faut pas que value1 existe déjà dans champ1.

    Je ne comprends pas le SELECT entre le INSERT et le NOT EXISTS.

    On ne peut pas spécifier de valeurs directes et de noms de champs ?

  10. #10
    Modérateur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2005
    Messages
    5 826
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2005
    Messages : 5 826
    Points : 12 371
    Points
    12 371
    Par défaut
    Bonjour,

    Hé non, on ne peut pas.
    Ainsi l'écriture suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    INSERT INTO MaTable
    VALUES 'Dupont'
    WHERE NOT EXISTS (SELECT *
                        FROM MaTable
                        WHERE Nom = 'Dupont')
    est illégale.

    Dans une instruction INSERT:

    - soit vous utilisez la clause VALUES et vous passez les valeurs, mais à ce titre vous n'insèrerez jamais qu'une seule ligne et vous devrez effectuer les contrôles avant de réaliser l'insertion,

    - soit vous utilisez une requête SELECT spécifiant l'ensemble à insérer dans la table, et vous disposez de toute la sémantique du SELECT pour contrôler ce que vous allez insérer dans la table.

    le test serait qu'il ne faut pas que value1 existe déjà dans champ1.
    Pourquoi donc ne pas poser une contrainte d'unicité sur cette colonne ?

    A+

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

Discussions similaires

  1. Vérifier données avant insertion dans une base de données
    Par massbbc dans le forum PHP & Base de données
    Réponses: 1
    Dernier message: 05/09/2010, 11h08
  2. Les transactions dans les procédures stockées
    Par CharleLéo dans le forum Connexion aux bases de données
    Réponses: 2
    Dernier message: 04/12/2009, 16h04
  3. vérifier si une table est vide avant insertion
    Par cashmoney dans le forum JDBC
    Réponses: 7
    Dernier message: 21/04/2009, 17h54
  4. [MySQL] Vérifier l'existance d'une donnée dans la base avant insertion
    Par Him dans le forum PHP & Base de données
    Réponses: 26
    Dernier message: 16/07/2006, 15h47
  5. [MySQL] Vérification de doublons avant insertion
    Par Nicos77 dans le forum PHP & Base de données
    Réponses: 15
    Dernier message: 09/12/2005, 13h37

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