none
Utilizar o segundo WHEN MATCHED THEN <merge_matched> RRS feed

  • Pergunta

  • Eu gostaria de saber como faço para utilizar o segundo merge matched then

    Eu preciso do seguinte caso:

    MERGE tabelaTarget AS target  
    USING 
       (SELECT id, codigo, flag_deletado from tabelaSource) AS source 
    ON (target.ID = source.ID and target.flag_deletado = '')  
    WHEN MATCHED AND (target.codigo <> source.codigo and source.flag_deletado = '') THEN
       UPDATE SET target.codigo= source.codigo
    WHEN MATCHED THEN
       UPDATE SET target.flag_deletado = '*'
    
    WHEN NOT MATCHED BY TARGET THEN  
    
            INSERT (codigo, flag_deletado)  
            VALUES (source.codigo, flag_deletado='')  
     OUTPUT deleted.*, $action, inserted.* INTO tabelaLog;  
    Na documentação diz o seguinte:

    "A instrução MERGE pode ter, no máximo, duas cláusulas WHEN MATCHED. Se duas cláusulas forem especificadas, a primeira deverá ser acompanhada de uma cláusula AND <search_condition>. Para qualquer linha especificada, a segunda cláusula WHEN MATCHED será aplicada somente se a primeira não for. Se houver duas cláusulas WHEN MATCHED, uma delas deverá especificar uma ação UPDATE e a outra, uma ação DELETE. Quando UPDATE for especificada na cláusula <merge_matched> e mais de uma linha de <table_source> corresponder a uma linha em target_table com base em <merge_search_condition>, SQL Server retornará um erro. A instrução MERGE não pode atualizar a mesma linha mais de uma vez, nem atualizar e excluir a mesma linha."

    Entendo que se a primeira tiver o AND a segundo caso deveria acontecer normalmente como escrevi no script. Porem na Doc também, existe a sintaxe que eu não consegui entender.

    [ WITH <common_table_expression> [,...n] ]  
    MERGE
        [ TOP ( expression ) [ PERCENT ] ]
        [ INTO ] <target_table> [ WITH ( <merge_hint> ) ] [ [ AS ] table_alias ]  
        USING <table_source>
        ON <merge_search_condition>  
        [ WHEN MATCHED [ AND <clause_search_condition> ]  
            THEN <merge_matched> ] [ ...n ]  
        [ WHEN NOT MATCHED [ BY TARGET ] [ AND <clause_search_condition> ]  
            THEN <merge_not_matched> ]  
        [ WHEN NOT MATCHED BY SOURCE [ AND <clause_search_condition> ]  
            THEN <merge_matched> ] [ ...n ]  
        [ <output_clause> ]  
        [ OPTION ( <query_hint> [ ,...n ] ) ]
    ;  

    <merge_matched>::=  
        { UPDATE SET <set_clause> | DELETE }  
    Como eu coloco esses blocos juntos, vejo que tem ; Como chamo o merge_matched, não entendi mesmo, eu não posso usar o deleted, pq o banco de dados que estou trazendo, não é normalizado, isso pode dar vários problemas no meu banco de dados a direita que é normalizado.

    segunda-feira, 8 de junho de 2020 11:58

Respostas

  • Leandrotto,

    Acredito que mediante a sua necessidade o comando Merge talvez não seja a melhor solução.

    Análise a possibilidade de utilizar o operador lógico condicional IF ou até mesmo a função IIF().


    Pedro Antonio Galvão Junior [MVP | MCC | MSTC | MIE | MTAC | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados Relacional e Data Warehouse | Professor Universitário | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]

    Vou fazer o seguinte,

    Salvar as consultas dos dados de origem em uma tabela temporária, faço o merge apenas com as alterações e inclusões. Após o termino, faço um update com as linhas que devem ser flagadas como deletada.

    Obrigado pela disposição e tempo!
    Resolvido com iif

    MERGE tabelaTarget AS target  
    USING 
       (SELECT id, codigo, flag_deletado from tabelaSource) AS source 
    ON (target.ID = source.ID and target.flag_deletado = '')  
    WHEN MATCHED AND (target.codigo <> source.codigo 
       or source.flag_deletado = '*') THEN --colocado o or e flag_deletado = '*'
    
      UPDATE SET target.codigo = iif(source.flag_deletado = '*', target.codigo ,source.codigo,
       target.flag_deletado = iif(source.flag_deletado = '*', target.flag_deletado, )
    --foi utilizado o iif para resolver a duplicidade do matched
    WHEN NOT MATCHED BY TARGET THEN     
       INSERT (codigo, flag_deletado)  
       VALUES (source.codigo, flag_deletado='')  
     OUTPUT deleted.*, $action, inserted.* INTO tabelaLog

    segunda-feira, 8 de junho de 2020 23:43

Todas as Respostas

  • WHEN NOT MATCHED BY SOURCE THEN
       UPDATE SET target.flag_deletado = '*'
    acho que eh isso o segundo when
    segunda-feira, 8 de junho de 2020 12:23
  • WHEN NOT MATCHED BY SOURCE THEN
       UPDATE SET target.flag_deletado = '*'
    acho que eh isso o segundo when
    Desculpe, eu esqueci de falar, os dados serão atualizados de uma base log, ou seja, eu não vou conseguir ter o "when not matched by source then", pq se eu fizesse a leitura de todo o database de milhões de linha, demoraria demais. Foi ai que entrei no problema!
    segunda-feira, 8 de junho de 2020 12:34
  • "Se houver duas cláusulas WHEN MATCHED, uma delas deverá especificar uma ação UPDATE e a outra, uma ação DELETE."

    when match and bla bla bla then update bla bla bla
    when match then delete

    segunda-feira, 8 de junho de 2020 12:46
  • "Se houver duas cláusulas WHEN MATCHED, uma delas deverá especificar uma ação UPDATE e a outra, uma ação DELETE."

    when match and bla bla bla then update bla bla bla
    when match then delete

    Sim, mas como dito:
    "A instrução MERGE pode ter, no máximo, duas cláusulas WHEN MATCHED. Se duas cláusulas forem especificadas, a primeira deverá ser acompanhada de uma cláusula AND <search_condition>. Para qualquer linha especificada, a segunda cláusula WHEN MATCHED será aplicada somente se a primeira não for."

    Além disso, tem a sintaxe:

    [ WITH <common_table_expression> [,...n] ]  
    MERGE
        [ TOP ( expression ) [ PERCENT ] ]
        [ INTO ] <target_table> [ WITH ( <merge_hint> ) ] [ [ AS ] table_alias ]  
        USING <table_source>
        ON <merge_search_condition>  
        [ WHEN MATCHED [ AND <clause_search_condition> ]  
            THEN <merge_matched> ] [ ...n ]  
        [ WHEN NOT MATCHED [ BY TARGET ] [ AND <clause_search_condition> ]  
            THEN <merge_not_matched> ]  
        [ WHEN NOT MATCHED BY SOURCE [ AND <clause_search_condition> ]  
            THEN <merge_matched> ] [ ...n ]  
        [ <output_clause> ]  
        [ OPTION ( <query_hint> [ ,...n ] ) ]
    <merge_matched>::=  
        { UPDATE SET <set_clause> | DELETE }  



    segunda-feira, 8 de junho de 2020 12:51
  • Se não achar solução, vou ter que arriscar:
    WHEN MATCHED AND (sourge.flag_DELETADO<>'') THEN 
    DELETE
    ...

    segunda-feira, 8 de junho de 2020 12:53
  • Leandrotto,

    Acredito que mediante a sua necessidade o comando Merge talvez não seja a melhor solução.

    Análise a possibilidade de utilizar o operador lógico condicional IF ou até mesmo a função IIF().


    Pedro Antonio Galvão Junior [MVP | MCC | MSTC | MIE | MTAC | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados Relacional e Data Warehouse | Professor Universitário | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]

    segunda-feira, 8 de junho de 2020 15:41
  • Leandrotto,

    Acredito que mediante a sua necessidade o comando Merge talvez não seja a melhor solução.

    Análise a possibilidade de utilizar o operador lógico condicional IF ou até mesmo a função IIF().


    Pedro Antonio Galvão Junior [MVP | MCC | MSTC | MIE | MTAC | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados Relacional e Data Warehouse | Professor Universitário | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]

    Vou fazer o seguinte,

    Salvar as consultas dos dados de origem em uma tabela temporária, faço o merge apenas com as alterações e inclusões. Após o termino, faço um update com as linhas que devem ser flagadas como deletada.

    Obrigado pela disposição e tempo!
    segunda-feira, 8 de junho de 2020 19:07
  • MERGE tabelaTarget AS target  
    USING
       (SELECT id,codigo,flag_deletado from tabelaSource) AS source
    ON (target.ID = source.ID and target.flag_deletado = '')  
    WHEN MATCHED THEN
       UPDATE SET target.codigo=case when (target.codigo<>source.codigo and source.flag_deletado='') then source.codigo else target.codigo end, target.flag_deletado=case when not (target.codigo<>source.codigo and source.flag_deletado='') then '*' else '' end
    WHEN NOT MATCHED BY TARGET THEN  
            INSERT (id,codigo,flag_deletado)  
            VALUES (source.id, source.codigo, '')  
     OUTPUT deleted.*, $action, inserted.* INTO tabelaLog; 


    • Sugerido como Resposta Avatar SQL segunda-feira, 8 de junho de 2020 19:31
    • Editado Avatar SQL segunda-feira, 8 de junho de 2020 20:05
    segunda-feira, 8 de junho de 2020 19:27
  • Leandrotto,

    Acredito que mediante a sua necessidade o comando Merge talvez não seja a melhor solução.

    Análise a possibilidade de utilizar o operador lógico condicional IF ou até mesmo a função IIF().


    Pedro Antonio Galvão Junior [MVP | MCC | MSTC | MIE | MTAC | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados Relacional e Data Warehouse | Professor Universitário | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]

    Vou fazer o seguinte,

    Salvar as consultas dos dados de origem em uma tabela temporária, faço o merge apenas com as alterações e inclusões. Após o termino, faço um update com as linhas que devem ser flagadas como deletada.

    Obrigado pela disposição e tempo!

    LeandroOtto,

    Ok, obrigado, fico no aguardo.


    Pedro Antonio Galvão Junior [MVP | MCC | MSTC | MIE | MTAC | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados Relacional e Data Warehouse | Professor Universitário | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]

    segunda-feira, 8 de junho de 2020 20:28
  • Leandrotto,

    Acredito que mediante a sua necessidade o comando Merge talvez não seja a melhor solução.

    Análise a possibilidade de utilizar o operador lógico condicional IF ou até mesmo a função IIF().


    Pedro Antonio Galvão Junior [MVP | MCC | MSTC | MIE | MTAC | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados Relacional e Data Warehouse | Professor Universitário | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]

    Vou fazer o seguinte,

    Salvar as consultas dos dados de origem em uma tabela temporária, faço o merge apenas com as alterações e inclusões. Após o termino, faço um update com as linhas que devem ser flagadas como deletada.

    Obrigado pela disposição e tempo!
    Resolvido com iif

    MERGE tabelaTarget AS target  
    USING 
       (SELECT id, codigo, flag_deletado from tabelaSource) AS source 
    ON (target.ID = source.ID and target.flag_deletado = '')  
    WHEN MATCHED AND (target.codigo <> source.codigo 
       or source.flag_deletado = '*') THEN --colocado o or e flag_deletado = '*'
    
      UPDATE SET target.codigo = iif(source.flag_deletado = '*', target.codigo ,source.codigo,
       target.flag_deletado = iif(source.flag_deletado = '*', target.flag_deletado, )
    --foi utilizado o iif para resolver a duplicidade do matched
    WHEN NOT MATCHED BY TARGET THEN     
       INSERT (codigo, flag_deletado)  
       VALUES (source.codigo, flag_deletado='')  
     OUTPUT deleted.*, $action, inserted.* INTO tabelaLog

    segunda-feira, 8 de junho de 2020 23:43
  • Leandrotto,

    Acredito que mediante a sua necessidade o comando Merge talvez não seja a melhor solução.

    Análise a possibilidade de utilizar o operador lógico condicional IF ou até mesmo a função IIF().


    Pedro Antonio Galvão Junior [MVP | MCC | MSTC | MIE | MTAC | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados Relacional e Data Warehouse | Professor Universitário | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]

    Vou fazer o seguinte,

    Salvar as consultas dos dados de origem em uma tabela temporária, faço o merge apenas com as alterações e inclusões. Após o termino, faço um update com as linhas que devem ser flagadas como deletada.

    Obrigado pela disposição e tempo!

    Resolvido com iif

    MERGE tabelaTarget AS target  
    USING 
       (SELECT id, codigo, flag_deletado from tabelaSource) AS source 
    ON (target.ID = source.ID and target.flag_deletado = '')  
    WHEN MATCHED AND (target.codigo <> source.codigo 
       or source.flag_deletado = '*') THEN --colocado o or e flag_deletado = '*'
    
      UPDATE SET target.codigo = iif(source.flag_deletado = '*', target.codigo ,source.codigo,
       target.flag_deletado = iif(source.flag_deletado = '*', target.flag_deletado, )
    --foi utilizado o iif para resolver a duplicidade do matched
    WHEN NOT MATCHED BY TARGET THEN     
       INSERT (codigo, flag_deletado)  
       VALUES (source.codigo, flag_deletado='')  
     OUTPUT deleted.*, $action, inserted.* INTO tabelaLog

    Leandro,

    Ok, que bom que deu certo, imaginei mesmo que a função IIF() seria a possibilidade.


    Pedro Antonio Galvão Junior [MVP | MCC | MSTC | MIE | MTAC | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados Relacional e Data Warehouse | Professor Universitário | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]

    terça-feira, 9 de junho de 2020 01:41
  • leandro

    resolvido entao com somente um WHEN MATCHED e decidindo o que fazer com os campos no UPDATE.

    terça-feira, 9 de junho de 2020 06:40