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

Développement SQL Server Discussion :

Toujours des problèmes avec MERGE [2008R2]


Sujet :

Développement SQL Server

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre expérimenté
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Par défaut Toujours des problèmes avec MERGE
    Hello,

    Ce n'est pas la première fois que je poste à ce sujet mais pour éviter de remonter une vieille discussion (portant en plus sur d'autres tables), j'en ouvre une nouvelle.

    Il a fallu le temps mais j'appréhende à présent mieux le fonctionnement de l'instruction MERGE. On définit une table cible et une table source avec un critère de jointure entre les deux et suivant que le critère est vérifié ou non, on fait l'une ou l'autre action. Avec le recul, je me dis que c'était quand même vachement con à comprendre XD.

    Bref, je tente d'écrire une instruction merge et ssms me rale dessus en disant que mon critère n'est pas une expression booléenne. J'en perds mon latin...
    Voici l'instruction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        MERGE    S_PROMO.T_SEASON_GROUP_SGP AS TARGET
        USING    (SELECT SGP_ID, SEA_ID, PEO_VALUE, ISNEW FROM @LIST_SEASONS) AS SOURCE (SGP_ID, SEA_ID, PEO_VALUE, ISNEW)
            ON    (TARGET.SGP_ID = SOURCE.SGP_ID)
        WHEN MATCHED THEN
            SELECT 1
        WHEN NOT MATCHED THEN
            SELECT 2
    N.B. : inspiré du code de l'exemple A de cette page.

    SGP_ID est bien sûr de type INT des deux côtés. Je comprends vraiment pas le problème qu'y trouve ssms...

    Quelqu'un pourrait-il m'aiguiller ?

  2. #2
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Par défaut
    Bonjour,

    Deux choses qui sautent aux yeux (je n'ai pas tout lu en détail) :

    1/ TARGET et SOURCE sont justement des mots réservés pour l'instruction MERGE. C'est donc certainement SQL Server qui en perds son latin quand vous les utilisez comme alias.

    2/les instructions acceptées dans les clauses WHEN [NOT] MATCHED [BY TARGET|BY SOURCE] sont limitées en fonction des cas (INSERT et/ou UPDATE et/ou DELETE) Mais en aucun cas me semble-t-il vous ne pouvez y mettre de SELECT.


    Enfin, il me semble qu'une instruction MERGE doit obligatoirement se terminer par ";"

  3. #3
    Membre expérimenté
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Par défaut
    Citation Envoyé par aieeeuuuuu Voir le message
    Bonjour,

    Deux choses qui sautent aux yeux (je n'ai pas tout lu en détail) :

    1/ TARGET et SOURCE sont justement des mots réservés pour l'instruction MERGE. C'est donc certainement SQL Server qui en perds son latin quand vous les utilisez comme alias.

    2/les instructions acceptées dans les clauses WHEN [NOT] MATCHED [BY TARGET|BY SOURCE] sont limitées en fonction des cas (INSERT et/ou UPDATE et/ou DELETE) Mais en aucun cas me semble-t-il vous ne pouvez y mettre de SELECT.


    Enfin, il me semble qu'une instruction MERGE doit obligatoirement se terminer par ";"
    Les selects étaient là juste histoire d'avoir quelque chose... Je n'étais pas encore arrivé là.

    Pour les mots clefs target et source, c'est comme ça que c'est présenté dans l'exemple de la MSDN. Cependant, j'y avais pensé et j'ai testé en les mettant entre crochet mais cela ne changeait rien.

    Par acquis de conscience, je vais refaire le test une nouvelle fois et tenté également en donnant d'autres noms.

    Je reviens de suite avec le feed-back.

  4. #4
    Membre expérimenté
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Par défaut
    Me voilà avec le feedback.

    En fait, c'est SSMS qui raconte n'importe quoi !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        MERGE    S_PROMO.T_SEASON_GROUP_SGP AS TARGET
        USING    (SELECT SGP_ID, SEA_ID, PEO_VALUE, ISNEW FROM @LIST_SEASONS) AS SOURCE (SGP_ID, SEA_ID, PEO_VALUE, ISNEW)
            ON    ((TARGET.SGP_ID = SOURCE.SGP_ID) AND (SOURCE.ISNEW = 0))
        WHEN MATCHED THEN
            UPDATE SET PEO_ID = (SELECT PEO_ID FROM S_PROMO.T_PERCENTAGE_OWN_PEO WHERE DTO_ID = @DTO_ID AND PEO_PERCENTAGE = SOURCE.PEO_VALUE)
        WHEN NOT MATCHED BY TARGET THEN
            DELETE;
    En modifiant comme ceci avec des clauses matched/not matched valides, le critère devient valide... Et sans avoir mis de crochet autour de target et source !!!

    On paie des milliers d'euros pour avoir le droit d'utiliser sql server et on n'a même pas droit à un message d'erreur correct... C'est triste quand même !

    Sinon, concernant l'instruction en elle-même, histoire d'être sûr que je sois dans le bon, fait-elle bien ce que je crois qu'elle fait ?
    Si SGP_ID (INT) de target et de source sont égaux et que ISNEW (BIT) de source est faux
    Alors je mets à jour la valeur de PEO_ID dans target
    Sinon je supprime la ligne de target.

    N.B. : C'est la première fois que j'arrive enfin à écrire une instruction merge complète sans erreur lol.

    N.B.2 : Si j'ajoute une clause WHEN NOT MATCHED BY SOURCE, le fait que SOURCE.ISNEW soit égale à 1 suffit-il bien à entrer dans cette branche ?

  5. #5
    Membre expérimenté
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Par défaut
    Damned !
    An action of type 'DELETE' is not allowed in the 'WHEN NOT MATCHED' clause of a MERGE statement.
    Voici la dernière version du code... Une suggestion ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        MERGE    S_PROMO.T_SEASON_GROUP_SGP AS TARGET
        USING    (SELECT LS.SGP_ID, LS.SEA_ID, LS.PEO_VALUE, LS.ISNEW, PEO.PEO_ID
                FROM @LIST_SEASONS LS 
                        INNER JOIN S_PROMO.T_PERCENTAGE_OWN_PEO PEO
                            ON    PEO.DTO_ID = @DTO_ID
                            AND PEO.PEO_PERCENTAGE = LS.PEO_VALUE) AS SOURCE (SGP_ID, SEA_ID, PEO_VALUE, ISNEW, PEO_ID)
            ON    ((TARGET.SGP_ID = SOURCE.SGP_ID) AND (SOURCE.ISNEW = 0))
        WHEN MATCHED THEN
            UPDATE SET PEO_ID = SOURCE.PEO_ID
        WHEN NOT MATCHED BY TARGET THEN
            DELETE
        WHEN NOT MATCHED BY SOURCE THEN
            INSERT (PEO_ID) VALUES(PEO_ID);
    EDIT :
    Après lecture détaillé de la page MSDN sur l'instruction MERGE, je pense avoir compris que je dois échanger mes instructions INSERT et DELETE. En effet, cela compile. Mais cela va-t-il donner le résultat attendu ?

    Je vais essayer de générer des données de test. Le souci étant que cela s'intègre dans une procédure assez longue qui requiert pas mal d'autres données pour pouvoir arriver jusque là...

  6. #6
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Par défaut
    C'est normal, si la ligne n'existe pas (NOT MATCHED), elle ne peux pas être supprimée.

    Quelle ligne voulez-vous donc supprimer ?

    si le fait de mettre à jour ou de supprimer est conditionné par (SOURCE.ISNEW = 0), alors il ne faut pas le mettre dans la condition de jointure, mais dans les clauses WHEN MATCHED

    De la même façon, vous ne pouvez pas spécifier de clause INSERT dans la clause NOT MATCHED BY SOURCE : si la ligne n'existe pas dans la table source, vous ne pouvez l'inserer dans la cible.

    Ce que vous voulez faire est donc peut être ceci :

    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
     
     
        MERGE    S_PROMO.T_SEASON_GROUP_SGP AS TARGET
        USING    (SELECT LS.SGP_ID, LS.SEA_ID, LS.PEO_VALUE, LS.ISNEW, PEO.PEO_ID
                FROM @LIST_SEASONS LS 
                        INNER JOIN S_PROMO.T_PERCENTAGE_OWN_PEO PEO
                            ON    PEO.DTO_ID = @DTO_ID
                            AND PEO.PEO_PERCENTAGE = LS.PEO_VALUE) AS SOURCE (SGP_ID, SEA_ID, PEO_VALUE, ISNEW, PEO_ID)
            ON    TARGET.SGP_ID = SOURCE.SGP_ID
        WHEN MATCHED AND SOURCE.ISNEW = 0 THEN 
            UPDATE SET PEO_ID = SOURCE.PEO_ID
        WHEN MATCHED THEN
            DELETE
        WHEN NOT MATCHED BY TARGET THEN
            INSERT (PEO_ID) VALUES(PEO_ID);
    Mais je ne suis pas sûr de la logique, car je n'ai pas précisément compris ce que vous vouliez faire.

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

Discussions similaires

  1. Encore des problèmes avec le BDE
    Par Flint dans le forum C++Builder
    Réponses: 19
    Dernier message: 31/12/2007, 23h26
  2. j'ai des problèmes avec un virus
    Par beencss dans le forum Sécurité
    Réponses: 4
    Dernier message: 02/02/2007, 13h56
  3. Toujours un problème avec Timer
    Par adidas40 dans le forum VB 6 et antérieur
    Réponses: 5
    Dernier message: 10/10/2006, 11h04
  4. SQL server et toujours des problèmes de dates ...
    Par constantin dans le forum MS SQL Server
    Réponses: 10
    Dernier message: 28/10/2005, 12h19
  5. toujours des problemes avec ce DROP
    Par Missvan dans le forum PostgreSQL
    Réponses: 2
    Dernier message: 18/02/2004, 08h43

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