SQL Server 2014 - MainTable 和 TempTable - 如果不存在则插入其他更新

Posted

技术标签:

【中文标题】SQL Server 2014 - MainTable 和 TempTable - 如果不存在则插入其他更新【英文标题】:SQL Server 2014 - MainTable & TempTable - IF Not Exists Insert Else Update 【发布时间】: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 中? 【参考方案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 别名的工作!正是我想要的。

以上是关于SQL Server 2014 - MainTable 和 TempTable - 如果不存在则插入其他更新的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SQL Server 2008 中恢复 SQL Server 2014 备份

可以在 SQL Server 2012 上恢复 SQL Server 2014 的备份吗?

如何在 SQL Server 2014 中从 SQL Server 2008 R2 恢复备份?

在 SQL Server 2005 中恢复 SQL Server 2014 数据库

TFS 2013 到 TFS 2017 / 单个 SQL Server 2012 到 SQL Server 2014 AAG

sql server 2014怎么装的过程中出错