AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 212003
Accepted
user2676140
user2676140
Asked: 2018-07-13 03:25:37 +0800 CST2018-07-13 03:25:37 +0800 CST 2018-07-13 03:25:37 +0800 CST

Ajuda com a declaração de mesclagem

  • 772

Estou querendo comparar o Distinct snfrom HMI_Tempto snna minha tabela HMI-> se snexistir, quero atualizar os valores - consegui essa sintaxe CHECK! - se snNÃO existir , quero inserir os dados de HMI_TempTentei HMIesta sintaxe, mas recebo erros de:

Nome de coluna inválido 'cb'
Nome de coluna inválido 'lp' Nome de
coluna inválido cn Nome de
coluna inválido stn

E esta é a minha sintaxe - como devo reescrever isso para obter o resultado desejado?

MERGE INTO HMI AS Target
USING (SELECT DISTINCT sn FROM HMI_Temp) AS Source ON Target.sn = Source.sn
WHEN NOT MATCHED THEN
INSERT (lp, cb, cn, sn, stn) VALUES (Source.lp, Source.cb, Source.cn, Source.sn, Source.stn);

DDL:

CREATE TABLE [dbo].[HMI_Temp]
(
    [sID] [int] IDENTITY(1,1) NOT NULL,
    stn [float] NULL,
    [sn] [nvarchar](255) NULL,
    [cn] [nvarchar](max) NULL,
    [lp] [nvarchar](max) NULL,
    [cb] [nvarchar](max) NULL,
    PRIMARY KEY CLUSTERED 
    (
        [sID] ASC
    ) WITH 
      (
           PAD_INDEX = OFF
         , STATISTICS_NORECOMPUTE = OFF
         , IGNORE_DUP_KEY = OFF
         , ALLOW_ROW_LOCKS = ON
         , ALLOW_PAGE_LOCKS = ON
      ) ON [PRIMARY]
) ON [PRIMARY] 
TEXTIMAGE_ON [PRIMARY]  
GO

SET IDENTITY_INSERT [dbo].[HMI_Temp] ON 
GO

INSERT [dbo].[HMI_Temp] ([sID], stn, [sn], [cn], [lp], [cb]) 
VALUES (1, 8888, N'Test', N'Test', N'Test123', N'Test456')
VALUES (1, 8888, N'SecondTest', N'SecondTest', N'SecondTest123', N'SecondTest456')
GO

Esta é a instrução de atualização que eu estava usando que funcionou, mas agora jogando uma chave nela para a inserção, se não existir :(

UPDATE y
SET y.lp = x.lp
,y.cb = x.cb
,y.cn = x.cn
FROM HMI y
INNER JOIN HMI_Temp x
ON y.stn = x.stn
AND y.sn = x.sn
AND y.cn = x.cn
sql-server sql-server-2008-r2
  • 2 2 respostas
  • 1532 Views

2 respostas

  • Voted
  1. Aaron Bertrand
    2018-07-13T04:02:30+08:002018-07-13T04:02:30+08:00

    Aqui está pelo menos uma parte do problema: se você tiver duas linhas HMI_Tempcom o mesmo valor, snmas valores diferentes para cb(ou qualquer outra coluna), qual delas o SQL Server deve escolher?

    Aqui está um padrão melhor do que MERGE, IMHO, que tem todos os tipos de problemas :

    INSERT dbo.HMI(stn,sn,cn,lp,cb)
    SELECT stn,sn,cn,lp,cb
    FROM
    (
      SELECT stn,sn,cn,lp,cb,rn = ROW_NUMBER() OVER 
        (
          PARTITION BY sn,cn -- makes sn + cn distinct
          ORDER BY sID       -- picks which row to keep
        )
      FROM dbo.HMI_Temp
      WHERE NOT EXISTS 
      (
        SELECT 1 FROM dbo.HMI WHERE sn = hmi.sn
      )
    ) AS x
    WHERE rn = 1;
    

    Isso é pegar a linha com a menor sID, mas você pode querer classificar as linhas de uma maneira diferente ou usar MIN/ MAXem cada uma das outras quatro colunas para determinar qual linha você deseja manter. Difícil dizer pela sua pergunta.

    • 5
  2. Best Answer
    Hannah Vernon
    2018-07-13T05:37:01+08:002018-07-13T05:37:01+08:00

    Para evitar o erro de sintaxe, você precisa incluir todas as colunas da USINGcláusula que estão sendo inseridas na tabela de destino. Portanto, uma instrução de mesclagem sintaticamente válida seria:

    MERGE INTO HMI AS Target
    USING (SELECT DISTINCT sn, lp, cb, cn, stn FROM HMI_Temp) AS Source ON Target.sn = Source.sn
    WHEN NOT MATCHED THEN
    INSERT (lp, cb, cn, sn, stn) VALUES (Source.lp, Source.cb, Source.cn, Source.sn, Source.stn);
    

    Como a funcionalidade pretendida inclui a capacidade de atualizar linhas existentes, você também precisa de uma WHEN MATCHEDcláusula que defina as colunas desejadas na tabela de destino para esses valores da tabela de origem. Algo como:

    MERGE INTO HMI AS Target
    USING (
        SELECT DISTINCT sn
            , lp
            , cb
            , cn
            , stn 
        FROM HMI_Temp
        ) AS Source ON Target.sn = Source.sn
    WHEN MATCHED THEN
    UPDATE SET Target.lp = Source.lp
        , Target.cb = Source.cb
        , Target.cn = Source.cn
        , Target.stn = Source.stn
    WHEN NOT MATCHED THEN
    INSERT (lp, cb, cn, sn, stn) 
    VALUES (Source.lp, Source.cb, Source.cn, Source.sn, Source.stn);
    

    No entanto, como mencionado por Aaron em sua resposta, MERGEestá repleto de outros problemas em potencial.


    Eu usei o seguinte exemplo minimamente completo e verificável :

    USE tempdb;
    
    DROP TABLE IF EXISTS dbo.HMI;
    CREATE TABLE dbo.HMI
    (
        sID int IDENTITY(1,1) NOT NULL
        , stn float NULL
        , sn nvarchar(255) NULL
        , cn nvarchar(max) NULL
        , lp nvarchar(max) NULL
        , cb nvarchar(max) NULL
        , PRIMARY KEY CLUSTERED 
          (
              sID ASC
          ) WITH 
            (
                PAD_INDEX = OFF
                , STATISTICS_NORECOMPUTE = OFF
                , IGNORE_DUP_KEY = OFF
                , ALLOW_ROW_LOCKS = ON
                , ALLOW_PAGE_LOCKS = ON
            ) ON [PRIMARY]
    ) ON [PRIMARY] 
    TEXTIMAGE_ON [PRIMARY];
    GO
    
    INSERT dbo.HMI (stn, sn, cn, lp, cb) 
    VALUES (8888, N'Test', N'Test', N'Test123', N'Test456')
        , (8887, N'A', N'B', N'C', N'D');
    
    
    DROP TABLE IF EXISTS dbo.HMI_Temp;
    CREATE TABLE dbo.HMI_Temp
    (
        sID int IDENTITY(1,1) NOT NULL
        , stn float NULL
        , sn nvarchar(255) NULL
        , cn nvarchar(max) NULL
        , lp nvarchar(max) NULL
        , cb nvarchar(max) NULL
        , PRIMARY KEY CLUSTERED 
          (
              sID ASC
          ) WITH 
            (
                PAD_INDEX = OFF
                , STATISTICS_NORECOMPUTE = OFF
                , IGNORE_DUP_KEY = OFF
                , ALLOW_ROW_LOCKS = ON
                , ALLOW_PAGE_LOCKS = ON
            ) ON [PRIMARY]
    ) ON [PRIMARY] 
    TEXTIMAGE_ON [PRIMARY];
    GO
    
    INSERT dbo.HMI_Temp (stn, sn, cn, lp, cb) 
    VALUES (8888, N'Test', N'F', N'G', N'H')
    

    Os dados se parecem com:

    SELECT *
    FROM dbo.HMI;
    
    ╔═════╦══════╦══════╦══════╦═════════╦═══╗═════╦═══╗═════╦═══╗
    ║ sID ║ stn ║ sn ║ cn ║ lp ║ cb ║
    ╠═════╬══════╬══════╬══════╬═════════╬═══╣════╬═══╣
    ║ 1 ║ 8888 ║ Teste ║ Teste ║ Teste123 ║ Teste456 ║
    ║ 2 ║ 8887 ║ A ║ B ║ C ║ D ║
    ╚═════╩══════╩══════╩══════╩═════════╩════════╩════════╩═══╝
    SELECT *
    FROM dbo.HMI_Temp;
    
    ╔═════╦══════╦══════╦════╦════╦════╗
    ║ sID ║ stn ║ sn ║ cn ║ lp ║ cb ║
    ╠═════╬══════╬══════╬════╬════╬════╣
    ║ 1 ║ 8888 ║ Teste ║ F ║ G ║ H ║
    ╚═════╩══════╩══════╩════╩════╩════╝

    A instrução de mesclagem:

    MERGE INTO dbo.HMI AS Target
    USING (
        SELECT DISTINCT sn
            , lp
            , cb
            , cn
            , stn 
        FROM dbo.HMI_Temp
        ) AS Source ON Target.sn = Source.sn
    WHEN MATCHED THEN
        UPDATE SET Target.lp = Source.lp
            , Target.cb = Source.cb
            , Target.cn = Source.cn
            , Target.stn = Source.stn
    WHEN NOT MATCHED THEN
        INSERT (lp, cb, cn, sn, stn) 
        VALUES (Source.lp, Source.cb, Source.cn, Source.sn, Source.stn);
    

    Os resultados, poste MERGE:

    SELECT *
    FROM dbo.HMI;
    
    ╔═════╦══════╦══════╦════╦════╦════╗
    ║ sID ║ stn ║ sn ║ cn ║ lp ║ cb ║
    ╠═════╬══════╬══════╬════╬════╬════╣
    ║ 1 ║ 8888 ║ Teste ║ F ║ G ║ H ║
    ║ 2 ║ 8887 ║ A ║ B ║ C ║ D ║
    ╚═════╩══════╩══════╩════╩════╩════╝

    Se a dbo.HMI_Temptabela contiver linhas não exclusivas, como em:

    INSERT dbo.HMI_Temp (stn, sn, cn, lp, cb) 
    VALUES (8888, N'Test', N'F', N'G', N'H')
        , (8888, N'Test', N'I', N'J', N'K')
        , (8888, N'Test', N'L', N'M', N'N');
    

    Ao executar a MERGEinstrução, você verá este erro:

    Msg 8672, Level 16, State 1, Line 67
    A instrução MERGE tentou UPDATE ou DELETE a mesma linha mais de uma vez. Isso acontece quando uma linha de destino corresponde a mais de uma linha de origem. Uma instrução MERGE não pode atualizar/excluir a mesma linha da tabela de destino várias vezes. Refine a cláusula ON para garantir que uma linha de destino corresponda no máximo a uma linha de origem ou use a cláusula GROUP BY para agrupar as linhas de origem.

    Como agora você esclareceu que também precisa usar a cncoluna como unificador, talvez seja possível usar esta instrução de mesclagem:

    MERGE INTO dbo.HMI AS Target
    USING (
        SELECT sn
            , lp
            , cb
            , cn
            , stn 
        FROM dbo.HMI_Temp
        ) AS Source ON Target.sn = Source.sn
            AND Target.cn = Source.cn
    WHEN MATCHED THEN
        UPDATE SET Target.lp = Source.lp
            , Target.cb = Source.cb
            , Target.cn = Source.cn
            , Target.stn = Source.stn
    WHEN NOT MATCHED THEN
        INSERT (lp, cb, cn, sn, stn) 
        VALUES (Source.lp, Source.cb, Source.cn, Source.sn, Source.stn);
    

    Observe, eu adicionei AND Target.cn = Source.cnà WHEREcláusula.

    • 4

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve