【问题标题】:SQL Server 2014 - MainTable & TempTable - IF Not Exists Insert Else UpdateSQL Server 2014 - MainTable 和 TempTable - 如果不存在则插入其他更新
【发布时间】:2017-04-12 19:38:18
【问题描述】:

我在 Microsoft SQL Server 2014 上有两个具有相同列的表。

MainTable 和 TempTable。

我想将 TempTable 中的更新/新鲜数据输入到 MainTable 中,避免重复。

MainTable 如下所示:

TempTable 如下所示:

TempTable 中的数据会不断变化。它可能已更新数据或新行。

我想要实现的是,将数据从 TempTable 插入/更新到 MainTable。

TempTable: - 在此示例中,Numbr 101 和 104 的行包含更新的数据。它还有带有 Numbr 105 和 106 的新行。我想更新101和104的数据,同时插入105和106。

由于我是 SQL 新手,请提供建议。


更新1:

使用以下查询后:

--Insert New
INSERT INTO MAINTABLE
SELECT A.*
FROM 
TempTable as A 
LEFT JOIN MainTable as B
ON B.Number = A.Number
WHERE B.Number IS NULL

--Update Old
UPDATE A
SET A.Number = B.Number,
    A.Name = B.Name,
    A.LastActive = B.LastActive,
    A.Country = B.Country
FROM 
TempTable as A 
LEFT JOIN MainTable as B
ON B.Number = A.Number
WHERE B.Number IS NOT NULL

MainTable的输出:

它有效,但是当 TempTable 中的数据更新并添加新数据时:

运行查询后的结果:

分别是MainTable和TempTable

添加了新的第 108 行(来自 TempTable --> MainTable),但更新后的第 106 行无效,并且 TempTable 中的值是从 MainTable 复制的。

【问题讨论】:

  • 查看 MERGE 语句(阅读整个页面,但您可以浏览“使用 MERGE 插入和更新”以获得更快的答案):technet.microsoft.com/en-us/library/bb522522(v=sql.105).aspx
  • 102和103呢?
  • @BaconBits 他们可能会也可能不会改变。这只是一个示例,我有数百行。
  • @pmbAustin 合并并没有真正奏效。
  • @Tango 对,但是当 102 和 103 存在而 TempTable 没有 102 和 103 时,MainTable 会发生什么?记录是否从 MainTable 中删除?它们是否保留在 MainTable 中?

标签: sql sql-server database sql-server-2014


【解决方案1】:
INSERT INTO MAINTABLE
SELECT A.*
FROM 
TempTable as A 
LEFT JOIN MainTable as B
ON B.Number = A.Number
WHERE B.Number IS NULL

--Update Old
UPDATE A
SET A.Name = B.Name,
A.LastActive = B.LastActive,
A.Country = B.Country
FROM TempTable as B 
INNER JOIN MainTable as A
 ON B.Number = A.Number
WHERE A.Name <> B.Name,
 A.LastActive <> B.LastActive,
 A.Country <> B.Country

【讨论】:

    【解决方案2】:

    我假设Numbr 是两个表中的键或唯一字段。如果不是这种情况,那么您不应该使用这些查询。此外,如果性能存在问题,则应在两个表中都对该字段进行索引。

    这是最简单的方法:

    BEGIN TRANSACTION;
    INSERT INTO MainTable (Numbr, Name, LastActive, Country)
    SELECT t.Numbr, t.Name, t.LastActive, t.Country
    FROM TempTable t
    WHERE NOT EXISTS (SELECT 1 FROM MainTable m WHERE m.Numbr = t.Numbr);
    
    UPDATE m
        SET Name = t.Name,
            LastActive = t.LastActive,
            Country = t.Country
    FROM MainTable m
    INNER JOIN TempTable t
        ON m.Numbr = t.Numbr
    WHERE m.Name <> t.Name
        OR m.LastActive <> t.LastActive
        OR m.Country <> t.Country;
    COMMIT;
    

    请注意,如果 Name、LastActive 或 Country 是可为空的字段,则语法会变得更加冗长。例如,如果所有三个字段都可以为空,那么您应该使用以下语法:

    BEGIN TRANSACTION;
    INSERT INTO MainTable (Numbr, Name, LastActive, Country)
    SELECT t.Numbr, t.Name, t.LastActive, t.Country
    FROM TempTable t
    WHERE NOT EXISTS (SELECT 1 FROM MainTable m WHERE m.Numbr = t.Numbr);
    
    UPDATE m
        SET Name = t.Name,
            LastActive = t.LastActive,
            Country = t.Country
    FROM MainTable m
    INNER JOIN TempTable t
        ON m.Numbr = t.Numbr
    WHERE m.Name <> t.Name
        OR (m.Name IS NULL AND t.Name IS NOT NULL)
        OR (m.Name IS NOT NULL AND t.Name IS NULL)
        OR m.LastActive <> t.LastActive
        OR (m.LastActive IS NULL AND t.LastActive IS NOT NULL)
        OR (m.LastActive IS NOT NULL AND t.LastActive IS NULL)
        OR m.Country <> t.Country
        OR (m.Country IS NULL AND t.Country IS NOT NULL)
        OR (m.Country IS NOT NULL AND t.Country IS NULL);
    COMMIT;
    

    如果您绝对需要最小化写入次数,那么您应该将UPDATE 语句分解为每个字段的一个查询。这可能运行得更快或可能运行得更慢,所以仅仅因为你写得更少并不意味着查询会执行得更快。同样,我假设您的系统中没有可为空的字段:

    BEGIN TRANSACTION;
    INSERT INTO MainTable (Numbr, Name, LastActive, Country)
    SELECT t.Numbr, t.Name, t.LastActive, t.Country
    FROM TempTable t
    WHERE NOT EXISTS (SELECT 1 FROM MainTable m WHERE m.Numbr = t.Numbr);
    
    UPDATE m
        SET Name = t.Name
    FROM MainTable m
    INNER JOIN TempTable t
        ON m.Numbr = t.Numbr
    WHERE m.Name <> t.Name;
    
    UPDATE m
        SET LastActive = t.LastActive
    FROM MainTable m
    INNER JOIN TempTable t
        ON m.Numbr = t.Numbr
    WHERE m.LastActive <> t.LastActive;
    
    UPDATE m
        SET Country = t.Country
    FROM MainTable m
    INNER JOIN TempTable t
        ON m.Numbr = t.Numbr
    WHERE m.Country <> t.Country;
    COMMIT;
    

    【讨论】:

      【解决方案3】:
      --Insert New
      INSERT INTO MAINTABLE
      SELECT A.*
      FROM 
      TempTable as A 
      LEFT JOIN MainTable as B
      ON B.Number = A.Number
      WHERE B.Number IS NULL
      
      --Update Old
      UPDATE A
      SET A.Number = B.Number,
          A.Name = B.Name,
          A.LastActive = B.LastActive,
          A.Country = B.Country
      FROM 
      TempTable as A 
      LEFT JOIN MainTable as B
      ON B.Number = A.Number
      WHERE B.Number IS NOT NULL
      

      【讨论】:

      • 如果那是您的连接谓词,请不要更新数字......在更新的情况下,您可以只执行 INNER JOIN 并省略 WEHRE 子句
      • @pmbAustin 和 LONG,请查看原帖中的更新。
      • 是的,这个答案的更新语句搞砸了很多。在连接中切换 A 和 B 别名(TempTable B LEFT JOIN MainTable A),它应该工作得更好一些......
      • @pmbAustin 感谢切换 a 和 b 别名的工作!正是我想要的。
      猜你喜欢
      • 2012-08-08
      • 2011-04-07
      • 2014-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多