usr*_*usr 7 sql-server sql-server-2014
作为MERGE
我想运行的查询的一部分,我想在运行时断言某个条件成立。当MERGE
找到 -match 时,我想更新某个列并执行以下逻辑:
NULL
,则写入源值NOT NULL
,则断言目标和源是相同的我希望这两个值在情况 2 中总是相同的,但我可能犯了一个错误(有一个错误)。发生这种情况时,我想使语句崩溃并让我的应用报告错误。这是一种非常罕见的错误情况,通常处理过程中不会发生这种情况。
所以我在想我可以滥用被零除的异常来触发崩溃:
MERGE
...
WHEN MATCHED BY TARGET THEN UPDATE SET
TargetCol = CASE
WHEN TargetCol IS NULL THEN SourceCol
WHEN TargetCol = SourceCol THEN SourceCol
ELSE 0/0 END --crash!
Run Code Online (Sandbox Code Playgroud)
这会可靠地工作吗?有理由不这样做吗?
这会可靠地工作吗?
这个问题的答案取决于您所需的保证的强度。过去围绕求值顺序存在一些错误CASE
,例如常量折叠生成错误的表达式。据我所知,SQL Server 2014 中当前没有任何错误会影响您的查询,但这并不意味着它们将来不会发生。
当然,任何代码都存在风险,但我的评估是,将此技术与MERGE
. 正如您所知,Merge 的实现很复杂,并且过去存在许多相关的错误。
有什么理由不应该这样做吗?
就我个人而言,我希望避免被零除作为解决方案的一部分。更好的选择可能是尝试写入一个违反CHECK
目标表上的显式(或其他)约束的值。这将导致执行计划中出现显式的 Assert 运算符,位于 Merge 运算符之后。添加这样的约束可能并不理想(如果允许列保存其类型域中的所有值,则甚至可能),但这是需要考虑的一件事。
另一项一般建议:避免在值匹配时更新目标列。这在逻辑上是一个空操作,但在物理上并不总是如此。
DECLARE @target AS TABLE (pk integer PRIMARY KEY, col2 integer NULL CHECK (col2 <> -1));
DECLARE @source AS TABLE (pk integer PRIMARY KEY, col2 integer NULL);
INSERT @target VALUES (1, 100), (2, NULL), (3, 300);
INSERT @source VALUES (1, 100), (2, 200), (3, 301);
MERGE @target AS T
USING @source AS S
ON S.pk = T.pk
WHEN MATCHED
AND
(
-- No update if values match
T.col2 IS NULL
OR T.col2 <> S.col2
)
THEN UPDATE SET col2 =
CASE
WHEN T.col2 IS NULL THEN S.col2
ELSE -1 -- violates CHECK constraint
END;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2679 次 |
最近记录: |