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

  1. #1
    Expert confirmé
    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 : 41
    Localisation : Belgique

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 239
    Points
    4 239
    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 ?
    Kropernic

  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
    Points : 13 092
    Points
    13 092
    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
    Expert confirmé
    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 : 41
    Localisation : Belgique

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 239
    Points
    4 239
    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.
    Kropernic

  4. #4
    Expert confirmé
    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 : 41
    Localisation : Belgique

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 239
    Points
    4 239
    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 ?
    Kropernic

  5. #5
    Expert confirmé
    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 : 41
    Localisation : Belgique

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 239
    Points
    4 239
    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à...
    Kropernic

  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
    Points : 13 092
    Points
    13 092
    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.

  7. #7
    Expert confirmé
    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 : 41
    Localisation : Belgique

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 239
    Points
    4 239
    Par défaut
    J'aurais peut-être dû commencer par là. Sorry,

    Ce que je cherche à faire. Cela entre dans le cadre d'une DB modélisant des futures promotions (actions commerciales).
    Je vais essayer de ne pas trop détailler pour ne pas tout compliqué mais ce n'est pas évident :-/

    Voici déjà le DDL des tables dont je vais parler, ça aidera p-e à suivre :
    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
     
    CREATE TABLE [dbo].[T_SEASON_SEA](
        [SEA_ID] [smallint] IDENTITY(-32768,1) NOT NULL,
        [SEA_CODE] [smallint] NOT NULL,
        [SEA_NAME] [varchar](50) NOT NULL,
        [SEA_YEAR] [smallint] NOT NULL,
     CONSTRAINT [PK_T_SEASON_SEA] PRIMARY KEY CLUSTERED 
    (
        [SEA_ID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY],
     CONSTRAINT [AK_SEA_CODE_SEA_YEAR] UNIQUE NONCLUSTERED 
    (
        [SEA_CODE] ASC,
        [SEA_YEAR] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
     
    GO
     
    SET ANSI_PADDING OFF
    GO
     
    /****** Object:  Table [S_PROMO].[T_PERCENTAGE_OWN_PEO]    Script Date: 5/08/2014 12:09:45 ******/
    SET ANSI_NULLS ON
    GO
     
    SET QUOTED_IDENTIFIER ON
    GO
     
    CREATE TABLE [S_PROMO].[T_PERCENTAGE_OWN_PEO](
        [PEO_ID] [int] IDENTITY(-2147483648,1) NOT NULL,
        [PEO_PERCENTAGE] [decimal](4, 2) NOT NULL,
        [DTO_ID] [int] NOT NULL,
     CONSTRAINT [PK_T_PERCENTAGE_OWN_PEO] PRIMARY KEY CLUSTERED 
    (
        [PEO_ID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
     
    GO
     
    /****** Object:  Table [S_PROMO].[T_SEASON_GROUP_SGP]    Script Date: 5/08/2014 12:09:45 ******/
    SET ANSI_NULLS ON
    GO
     
    SET QUOTED_IDENTIFIER ON
    GO
     
    CREATE TABLE [S_PROMO].[T_SEASON_GROUP_SGP](
        [SGP_ID] [int] IDENTITY(-2147483648,1) NOT NULL,
        [PEO_ID] [int] NOT NULL,
     CONSTRAINT [PK_T_SEASON_GROUP_SGP] PRIMARY KEY CLUSTERED 
    (
        [SGP_ID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
     
    GO
     
    /****** Object:  Table [S_PROMO].[TJ_SGP_SEA_JSS]    Script Date: 5/08/2014 12:09:45 ******/
    SET ANSI_NULLS ON
    GO
     
    SET QUOTED_IDENTIFIER ON
    GO
     
    CREATE TABLE [S_PROMO].[TJ_SGP_SEA_JSS](
        [SGP_ID] [int] NOT NULL,
        [SEA_ID] [smallint] NOT NULL,
     CONSTRAINT [PK_TJ_SGP_SEA_JSS] PRIMARY KEY CLUSTERED 
    (
        [SGP_ID] ASC,
        [SEA_ID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
     
    GO
     
    ALTER TABLE [S_PROMO].[T_PERCENTAGE_OWN_PEO]  WITH CHECK ADD  CONSTRAINT [FK_T_PERCENTAGE_OWN_PEO_T_DETAIL_OWN_DTO] FOREIGN KEY([DTO_ID])
    REFERENCES [S_PROMO].[T_DETAIL_OWN_DTO] ([DTO_ID])
    GO
     
    ALTER TABLE [S_PROMO].[T_PERCENTAGE_OWN_PEO] CHECK CONSTRAINT [FK_T_PERCENTAGE_OWN_PEO_T_DETAIL_OWN_DTO]
    GO
     
    ALTER TABLE [S_PROMO].[T_SEASON_GROUP_SGP]  WITH CHECK ADD  CONSTRAINT [FK_T_SEASON_GROUP_SGP_T_PERCENTAGE_OWN_PEO] FOREIGN KEY([PEO_ID])
    REFERENCES [S_PROMO].[T_PERCENTAGE_OWN_PEO] ([PEO_ID])
    GO
     
    ALTER TABLE [S_PROMO].[T_SEASON_GROUP_SGP] CHECK CONSTRAINT [FK_T_SEASON_GROUP_SGP_T_PERCENTAGE_OWN_PEO]
    GO
     
    ALTER TABLE [S_PROMO].[TJ_SGP_SEA_JSS]  WITH CHECK ADD  CONSTRAINT [FK_TJ_SGP_SEA_JSS_T_SEASON_GROUP_SGP] FOREIGN KEY([SGP_ID])
    REFERENCES [S_PROMO].[T_SEASON_GROUP_SGP] ([SGP_ID])
    GO
     
    ALTER TABLE [S_PROMO].[TJ_SGP_SEA_JSS] CHECK CONSTRAINT [FK_TJ_SGP_SEA_JSS_T_SEASON_GROUP_SGP]
    GO
     
    ALTER TABLE [S_PROMO].[TJ_SGP_SEA_JSS]  WITH CHECK ADD  CONSTRAINT [FK_TJ_SGP_SEA_JSS_T_SEASON_SEA] FOREIGN KEY([SEA_ID])
    REFERENCES [dbo].[T_SEASON_SEA] ([SEA_ID])
    GO
     
    ALTER TABLE [S_PROMO].[TJ_SGP_SEA_JSS] CHECK CONSTRAINT [FK_TJ_SGP_SEA_JSS_T_SEASON_SEA]
    GO
     
    ALTER TABLE [dbo].[T_SEASON_SEA]  WITH CHECK ADD  CONSTRAINT [CK_YEAR_EXISTS] CHECK  (([DBO].[UF_CHECK_IF_YEAR_EXISTS]([SEA_YEAR])=(1)))
    GO
     
    ALTER TABLE [dbo].[T_SEASON_SEA] CHECK CONSTRAINT [CK_YEAR_EXISTS]
    GO
    Une promo portera sur une ou plusieurs marques et chaque marque pourra (faire) bénéfier (au client) d'un ou plusieurs pourcentages sur base de la saison à laquelle appartient l'article vendu.

    J'ai donc une table reprenant les pourcentages (T_PERCENTAGE_OWN_PEO) avec DTO_ID qui permet de retrouver la marque en question via la table dont il est la clef primaire.

    J'ai également une table des groupes de saisons (T_SEASON_GROUP_SGP) qui permet d'attribuer le même pourcentage à un groupe de saisons. Et bien évidemment, pour savoir de quelles saisons il s'agit, il y a une table de jointure (TJ_SGP_SEA_JSS) entre la table des saisons (T_SEASON_SEA) et celles des groupes de saisons.

    Dans ma requête merge, j'en suis à la mise à jour de la table des groupes de saisons en fonction de ce que je vais recevoir via l'application. Des instructions ultérieures viendront mettre à jour la table de jointre entre celle des saisons et celles des groupes.

    Je vais recevoir la liste des saisons via un TVP contenant l'Id du group, l'id de la saison, la valeur du pourcentage et un flag pour dire si c'est un nouveau groupe ou non).
    Si dans ce tvp, plusieurs saisons (donc plusieurs lignes) appartiennent au même groupe de saisons, la valeur de SGP_ID sera identique pour ces lignes (heureusemnt) et ISNEW est là pour m'indiquer si un groupe existe déjà avec cet ID. Je fais donc un update de la colonne PEO_ID (car le pourcentage pourrait avoir été modifié). Si ISNEW est false, SGP_ID n'est là que pour assurer le bon regroupement des saisons et je crée donc un nouveau groupe avec la bonne valeur pour PEO_ID) et je récupère l'id inséré (il manque la clause OUTPUT de l'instruction INSERT) pour pouvoir insérer correctement après dans la table de jointure.

    Voilà... J'espère avoir été clair... Je me rends bien compte que ce n'est pas évident.

    Je vais regarder en décalant le isnew comme critère des clauses matched.
    Kropernic

  8. #8
    Expert confirmé
    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 : 41
    Localisation : Belgique

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 239
    Points
    4 239
    Par défaut Je continue mon monologue ^^
    J'ai de nouveau relu la MSDN et il apparait qu'une instruction MERGE ne peut avoir qu'une seule clause WHEN NOT MATCHED. Donc c'est raté pour faire un action différente suivant que c'est par la source ou la cible...

    J'en suis arrivé à 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
    16
    17
    18
    19
    20
    21
    22
    23
     
        --déclaration de la table pour faire la relation entre les id provisoires des nouveaux groupes et leur id réel
        DECLARE @INSERTED TABLE (
            SOURCE_ID INT,
            TARGET_ID INT);
     
        --MAJ DES GROUPES DE SAISONS
        MERGE    S_PROMO.T_SEASON_GROUP_SGP AS TARGET
        USING    (SELECT DISTINCT LS.SGP_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, PEO_VALUE, ISNEW, PEO_ID)
            ON    (TARGET.SGP_ID = SOURCE.SGP_ID AND SOURCE.ISNEW = 0) --on ne prend donc que les groupes qui ne sont pas nouveau et dont on retrouve l'id dans la table des groupes (si on ne retrouve pas, c'est qu'il y a un problème quelque part car on aurait un groupe fantôme...)
        WHEN MATCHED THEN --si on trouve, on met à jour PEO_ID pour être sûr d'avoir la bonne valeur
            UPDATE SET PEO_ID = SOURCE.PEO_ID
        WHEN NOT MATCHED THEN --si on ne trouve pas, on crée le nouveau groupe et ajoute son id en regard de l'id provisoire dans la variable table nommée @INSERTED
            INSERT (PEO_ID) VALUES(SOURCE.PEO_ID) OUTPUT INSERTED.SGP_ID, SOURCE.SGP_ID INTO @INSERTED;
     
        --finalement (car on ne peut pas rajouter une clause WHEN NOT MATCHED BY SOURCE), on supprime les groupes qui ne trouve plus dans le TVP (car supprimé via la GUI de l'application)
        DELETE 
        FROM    S_PROMO.T_SEASON_GROUP_SGP
        WHERE    SGP_ID NOT IN (SELECT DISTINCT SGP_ID FROM @LIST_SEASONS WHERE ISNEW = 0);
    J'ai commenté le code pour décrire ce que chaque partie doit faire selon moi. Me suis-je fourvoyé quelque part ?
    Kropernic

  9. #9
    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
    Points : 13 092
    Points
    13 092
    Par défaut
    Citation Envoyé par Kropernic Voir le message
    J'ai de nouveau relu la MSDN et il apparait qu'une instruction MERGE ne peut avoir qu'une seule clause WHEN NOT MATCHED.
    Vous ne pouvez avoir qu'une seule clause WHEN NOT MATCHED [BY TARGET], mais vous pouvez en plus avoir une (et même plusieurs je crois) clause(s) WHEN NOT MATCHED BY SOURCE.

  10. #10
    Expert éminent
    Avatar de Lyche
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2007
    Messages
    2 523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Janvier 2007
    Messages : 2 523
    Points : 6 775
    Points
    6 775
    Billets dans le blog
    4
    Par défaut
    Oui, on peut même rajouter des conditions spécifiques en dehors du BY TARGET/SOURCE.

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    WHEN MATCHED AND Champ = 'x'

    Permettant aussi de faire des filtres spécifiques à une action précise.
    -> On peut alors faire des UPDATES de différentes colonnes sur différents types de MATCH

    Cordialement
    Rejoignez la communauté du chat et partagez vos connaissances ou vos questions avec nous

    Mon Tutoriel pour apprendre les Agregations
    Consultez mon Blog SQL destiné aux débutants

    Pensez à FAQ SQL Server Ainsi qu'aux Cours et Tuto SQL Server

  11. #11
    Expert confirmé
    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 : 41
    Localisation : Belgique

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 239
    Points
    4 239
    Par défaut
    Citation Envoyé par aieeeuuuuu Voir le message
    Vous ne pouvez avoir qu'une seule clause WHEN NOT MATCHED [BY TARGET], mais vous pouvez en plus avoir une (et même plusieurs je crois) clause(s) WHEN NOT MATCHED BY SOURCE.
    Je pensais aussi vu que c'est ce que dit MSDN mais quand je le fais, ssms me souligne en rouge ondulé la fin de la ligne juste avant when not matched by source en disant que l'instruction merge doit finir par un point-virgule...

    Voilà ce que donne mon instruction merge avec WHEN NOT MATCHED BY SOURCE.

    Le soulignement rouge que je m'entionne se trouve donc juste après @INSERTED (que je mets en gras)

    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 DISTINCT LS.SGP_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, 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 THEN
            INSERT (PEO_ID) VALUES(SOURCE.PEO_ID) OUTPUT INSERTED.SGP_ID, SOURCE.SGP_ID INTO @INSERTED
        WHEN NOT MATCHED BY SOURCE THEN
            DELETE;
    N.B. : je mets un mot en gras et plus rien n'est coloré automatiquement.. c'est génial '-_-
    Kropernic

  12. #12
    Expert éminent
    Avatar de Lyche
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2007
    Messages
    2 523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Janvier 2007
    Messages : 2 523
    Points : 6 775
    Points
    6 775
    Billets dans le blog
    4
    Par défaut
    pourquoi passer par le @INSERTED?

    la clause OUTPUT permet de gérer le résultat du MERGE

    Edit : My bad je n'avais pas vu que ça venait du OUTPUT.
    Rejoignez la communauté du chat et partagez vos connaissances ou vos questions avec nous

    Mon Tutoriel pour apprendre les Agregations
    Consultez mon Blog SQL destiné aux débutants

    Pensez à FAQ SQL Server Ainsi qu'aux Cours et Tuto SQL Server

  13. #13
    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
    Points : 13 092
    Points
    13 092
    Par défaut
    oui, c'est justement la clause OUTPUT qui pose problème : elle devrait se trouver à la fin du MERGE, c'est pourquoi SSMS indique qu'elle doit être suivie d'un point-virgule.
    Décalez votre clause OUTPUT après votre clause WHEN NOT MATCHED BY SOURCE

  14. #14
    Expert éminent
    Avatar de Lyche
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2007
    Messages
    2 523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Janvier 2007
    Messages : 2 523
    Points : 6 775
    Points
    6 775
    Billets dans le blog
    4
    Par défaut
    Exact, le OUTPUT d'un MERGE ne peut se retrouver dans chaque clause.

    Exemple :

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    MERGE INTO ...
    USING (... )
    WHEN MATCHED THEN
    UPDATE SET ...
    WHEN NOT MATCHED THEN
    INSERT (...)
    VALUES(...)
    OUTPUT inserted.champ, inserted.champ2, inserted.champ3, $Action;

    la fonction $Action permet en revanche, de connaître l'action appliquée par ligne. (INSERT/DELETE/UPDATE)
    Rejoignez la communauté du chat et partagez vos connaissances ou vos questions avec nous

    Mon Tutoriel pour apprendre les Agregations
    Consultez mon Blog SQL destiné aux débutants

    Pensez à FAQ SQL Server Ainsi qu'aux Cours et Tuto SQL Server

  15. #15
    Expert confirmé
    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 : 41
    Localisation : Belgique

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 239
    Points
    4 239
    Par défaut
    Citation Envoyé par aieeeuuuuu Voir le message
    oui, c'est justement la clause OUTPUT qui pose problème : elle devrait se trouver à la fin du MERGE, c'est pourquoi SSMS indique qu'elle doit être suivie d'un point-virgule.
    Décalez votre clause OUTPUT après votre clause WHEN NOT MATCHED BY SOURCE
    Mais alors je vais choper les SGP_ID des lignes qui ont été mises à jour... Bon ce n'est pas la fin du monde l'idée était de ne récupérer que les SGP_ID des lignes insérées. D'où le output après le insert (comme pour un insert normal quoi ^^).

    C'est vrai que maintenant que tu me fais remarquer cela, je me rends compte que le insert n'est pas un insert habituel mais un ordre propre à l'instruction merge. Du coup, logique que ssms prenne le output comme étant la dernière clause du merge...

    Vais adapter cela.
    Kropernic

  16. #16
    Expert confirmé
    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 : 41
    Localisation : Belgique

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 239
    Points
    4 239
    Par défaut
    Citation Envoyé par Lyche Voir le message
    Exact, le OUTPUT d'un MERGE ne peut se retrouver dans chaque clause.
    Je l'avais écrit comme étant le output de l'insert ^^. Autant pour moi.
    Kropernic

  17. #17
    Expert éminent
    Avatar de Lyche
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2007
    Messages
    2 523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Janvier 2007
    Messages : 2 523
    Points : 6 775
    Points
    6 775
    Billets dans le blog
    4
    Par défaut
    Alors il est possible d'encapsuler le MERGE dans un sous select, et de n'insérer dans la nouvelle table que les actions d'insertion.

    Exemple :
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    INSERT INTO @INSERTED
    SELECT champ, champ2, champ3, Actions
      FROM (
             MERGE INTO ...
             USING (... )
             WHEN MATCHED THEN
             UPDATE SET ...
             WHEN NOT MATCHED THEN
             INSERT (...)
             VALUES(...)
             OUTPUT inserted.champ, inserted.champ2, inserted.champ3, $Action ) AS RqMERGE(champ, champ2, champ3, Actions)
    WHERE  Actions = 'INSERTED';
    Rejoignez la communauté du chat et partagez vos connaissances ou vos questions avec nous

    Mon Tutoriel pour apprendre les Agregations
    Consultez mon Blog SQL destiné aux débutants

    Pensez à FAQ SQL Server Ainsi qu'aux Cours et Tuto SQL Server

  18. #18
    Expert confirmé
    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 : 41
    Localisation : Belgique

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 239
    Points
    4 239
    Par défaut
    Citation Envoyé par Lyche Voir le message
    Alors il est possible d'encapsuler le MERGE dans un sous select, et de n'insérer dans la nouvelle table que les actions d'insertion.

    Exemple :
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    INSERT INTO @INSERTED
    SELECT champ, champ2, champ3, Actions
      FROM (
             MERGE INTO ...
             USING (... )
             WHEN MATCHED THEN
             UPDATE SET ...
             WHEN NOT MATCHED THEN
             INSERT (...)
             VALUES(...)
             OUTPUT inserted.champ, inserted.champ2, inserted.champ3, $Action ) AS RqMERGE(champ, champ2, champ3, Actions)
    WHERE  Actions = 'INSERTED';
    C'est tellement élégant ! J'aime

    Par contre, le jour où je suis en congé/malade et qu'il faut bosser faire une adaptation (ça ne devrait pas arriver mais on ne sait jamais), ça va être le bordel car personne ici ne va y comprendre quelque chose à part moi
    Kropernic

  19. #19
    Expert éminent
    Avatar de Lyche
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2007
    Messages
    2 523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Janvier 2007
    Messages : 2 523
    Points : 6 775
    Points
    6 775
    Billets dans le blog
    4
    Par défaut
    Avec une bonne indentation et un peu de commentaire pour expliquer ce qui est fait. Je ne vois pas ce qui pourrait poser problème
    Rejoignez la communauté du chat et partagez vos connaissances ou vos questions avec nous

    Mon Tutoriel pour apprendre les Agregations
    Consultez mon Blog SQL destiné aux débutants

    Pensez à FAQ SQL Server Ainsi qu'aux Cours et Tuto SQL Server

  20. #20
    Expert confirmé
    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 : 41
    Localisation : Belgique

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 239
    Points
    4 239
    Par défaut
    Citation Envoyé par Lyche Voir le message
    Avec une bonne indentation et un peu de commentaire pour expliquer ce qui est fait. Je ne vois pas ce qui pourrait poser problème
    Avant, j'aurais réagi comme vous. Mais ça, c'était avant.

    Niveau commentaire, le code t-sql est suffisant auto-commenté pour que, si on n'utilise pas des variables avec des noms arbitraires, aucun commentaire supplémentaire n'est vraiment nécessaires.

    Je note au dessus d'un bloc d'instructions à quoi il sert mais dans le bloc, je ne note rien.
    Kropernic

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

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