Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在SQL Server中插入而不是更新合并语句_Sql_Sql Server_Sql Server 2008 - Fatal编程技术网

在SQL Server中插入而不是更新合并语句

在SQL Server中插入而不是更新合并语句,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我正在使用SQLServer2008,我正在尝试从一个暂存(源)表加载一个新的(目标)表。目标表为空 我认为,由于我的目标表是空的,MERGE语句跳过了WHEN MATCHED部分,即内部连接的结果为NULL,因此没有任何内容更新,它只是继续执行WHEN NOT MATCHED BY target部分(左外部连接),插入staging表中的所有记录 我的目标表看起来与暂存表(第1行和第4行)完全相似。目标表中应该只有3行(3次插入,第4行更新一次)。所以,我不知道发生了什么 FileID cl

我正在使用SQLServer2008,我正在尝试从一个暂存(源)表加载一个新的(目标)表。目标表为空

我认为,由于我的目标表是空的,MERGE语句跳过了WHEN MATCHED部分,即内部连接的结果为NULL,因此没有任何内容更新,它只是继续执行WHEN NOT MATCHED BY target部分(左外部连接),插入staging表中的所有记录

我的目标表看起来与暂存表(第1行和第4行)完全相似。目标表中应该只有3行(3次插入,第4行更新一次)。所以,我不知道发生了什么

FileID client_id account_name account_currency creation_date last_modified 210 12345 Cars USD 2013-11-21 2013-11-27 211 23498 Truck USD 2013-09-22 2013-11-27 212 97652 Cars - 1 USD 2013-09-17 2013-11-27 210 12345 Cars JPY 2013-11-21 2013-11-29 我认为,因为我的目标表是空的,所以MERGE语句跳过了WHEN MATCHED部分

好吧,这是正确的,但这是出于设计——
MERGE
不是“渐进式”合并。它不会逐行查看作为
合并的一部分插入的记录现在是否应该更新。它根据是否在目标中找到匹配项来“批量”处理源

在尝试
合并之前,您需要在源位置处理“重复”记录

我认为,因为我的目标表是空的,所以MERGE语句跳过了WHEN MATCHED部分

好吧,这是正确的,但这是出于设计——
MERGE
不是“渐进式”合并。它不会逐行查看作为
合并的一部分插入的记录现在是否应该更新。它根据是否在目标中找到匹配项来“批量”处理源


在尝试
合并之前,您需要在源位置处理“重复”记录,因为目标表是空的,所以在我看来,使用
合并
就像雇佣水管工给您倒一杯水一样。而
MERGE
对于表的每一行只独立地操作一个分支-它看不到键是重复的,因此执行插入然后执行更新-这表明您认为SQL总是按行操作,而实际上大多数操作都是同时对整个集合执行的

为什么不只插入最近的行:

;WITH cte AS 
(
  SELECT FileID, ... other columns ..., 
    rn = ROW_NUMBER() OVER (PARTITION BY FileID ORDER BY last_modified DESC)
  FROM dbo.AccountSettings_Staging
)
INSERT dbo.AccountSettings(FileID, ... other columns ...)
  SELECT FileID, ... other columns ...
  FROM cte WHERE rn = 1;
如果您有可能在最近的
上次修改的
上出现平局,您需要找到另一个平局破坏者(从您的示例数据中不明显)

对于未来的版本,我会说首先运行
更新

UPDATE a SET client_id = s.client_id /* , other columns that can change */
  FROM dbo.AccountSettings AS a
  INNER JOIN dbo.AccountSettings_Staging AS s
  ON a.FileID = s.FileID;
(当然,如果源包含多个具有相同
FileID
的行,这将选择任意行-您可能也希望在此处使用CTE以使选择可预测。)

然后将此条款添加到上面的
INSERT
CTE中:

FROM dbo.AccountSettings_Staging AS s
WHERE NOT EXISTS (SELECT 1 FROM dbo.AccountSettings 
  WHERE FileID = s.FileID);

以适当的隔离级别将其全部封装在事务中,您仍然可以避免大量复杂的
MERGE
语法、潜在的bug等。

由于目标表是空的,在我看来,使用
MERGE
就像雇佣一个水管工给您倒一杯水。而
MERGE
对于表的每一行只独立地操作一个分支-它看不到键是重复的,因此执行插入然后执行更新-这表明您认为SQL总是按行操作,而实际上大多数操作都是同时对整个集合执行的

为什么不只插入最近的行:

;WITH cte AS 
(
  SELECT FileID, ... other columns ..., 
    rn = ROW_NUMBER() OVER (PARTITION BY FileID ORDER BY last_modified DESC)
  FROM dbo.AccountSettings_Staging
)
INSERT dbo.AccountSettings(FileID, ... other columns ...)
  SELECT FileID, ... other columns ...
  FROM cte WHERE rn = 1;
如果您有可能在最近的
上次修改的
上出现平局,您需要找到另一个平局破坏者(从您的示例数据中不明显)

对于未来的版本,我会说首先运行
更新

UPDATE a SET client_id = s.client_id /* , other columns that can change */
  FROM dbo.AccountSettings AS a
  INNER JOIN dbo.AccountSettings_Staging AS s
  ON a.FileID = s.FileID;
(当然,如果源包含多个具有相同
FileID
的行,这将选择任意行-您可能也希望在此处使用CTE以使选择可预测。)

然后将此条款添加到上面的
INSERT
CTE中:

FROM dbo.AccountSettings_Staging AS s
WHERE NOT EXISTS (SELECT 1 FROM dbo.AccountSettings 
  WHERE FileID = s.FileID);

以适当的隔离级别将其封装在事务中,您仍然可以避免大量复杂的
MERGE
语法、潜在错误等。

相关:。@AaronBertrand谢谢。您建议在它的位置使用什么(如果存在的话除外)?它现在是空的,但不会用于将来的作业运行。如果MERGE语句继续为任何帐户插入重复项,则会导致问题。您应该在问题中这样说。问题中的所有内容都让我相信这是某种一次性的事情,或者目标表总是先被清除。相关:。@AaronBertrand谢谢。您建议在它的位置使用什么(如果存在的话除外)?它现在是空的,但不会用于将来的作业运行。如果MERGE语句继续为任何帐户插入重复项,则会导致问题。您应该在问题中这样说。问题中的所有内容都让我相信这是某种一次性的事情,或者目标表总是先被清除。它现在是空的,但不会用于以后的作业运行。如果MERGE语句继续为任何帐户插入重复项,则会导致问题。可能我需要将CTE用作合并中的源,然后在目标表中更新或删除。@仅当源中包含不在目标中的重复时,才会插入重复。我也不相信SQL会按照记录在CTE中出现的顺序更新记录。您需要以任何方式(或使用光标,这将是最后的手段)在源代码中解决复制-Aaron,
更新
/
插入
在幕后做什么?不反驳你的答案,只是重申
MERGE
@DStanley确实没有什么“魔力”,那么为什么要使用完全繁琐和不直观的语法呢?或者去努力验证你没有受到十几个错误结果和其他严重错误的影响,而这些错误还没有被修复?是吗?@AaronBertrand我确实这么做了,我完全同意——我只是重申,
MERGE
UPDATE
/
INSERT
b上买不到多少东西