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