空值和 MERGE 语句:我需要将值设置为无穷大。如何?

发布于 2024-10-08 16:28:02 字数 800 浏览 3 评论 0原文

在具有 MERGE 代码的 SQL Server 中,一切都很好,除非有 2 个可为空的列。

如果我传递一个空值并且目标不为空,则 MERGE 不会看到差异(针对 null = false 进行评估)。如果我在双方(源和目标)上使用 IsNull ,则可以工作,但存在可能错误评估值的问题。

最后一句话的意思是,如果我说:

WHEN MATCHED AND NOT (IsNull(tgt.C, 0) = IsNull(src.C, 0)) THEN

那么如果 tgt.C 为 null 并且 src.C = 0,则不会执行任何更新。无论我选择什么替代值,我都会遇到这个问题。

我还尝试了“AND NOT (...true...)”语法,因为 BOL 声明针对 null 的评估结果为 FALSE。然而,它们似乎实际上导致 NULL,并且不会导致我的多部分语句变为 false。

我认为一种解决方案是使用 NaN 或 -INF 或 +INF 因为这些在目标中无效。但我找不到在 SQL 中表达这一点的方法。

有什么想法如何解决这个问题吗?

编辑:

以下逻辑解决了问题,但它很冗长并且不会进行快速评估:

declare @i int, @j int

set @j = 0
set @i = 0

if ISNULL(@i, 0) != ISNULL(@j, 0) OR 
    ((@i is null or @j is null) and not (@i is null and @j is null))
    print 'update';

In SQL Server with a MERGE code, everything is fine except when there are 2 nullable columns.

If I pass a null value and the target isn't null, MERGE doesn't see a difference (evals against null = false). If I use IsNull on both sides (source & target) that works, but has the issue of potentially mis-evaluating a value.

What I mean by the last statement is, if I say:

WHEN MATCHED AND NOT (IsNull(tgt.C, 0) = IsNull(src.C, 0)) THEN

then if tgt.C is null and src.C = 0, no update will be performed. No matter what substitute value I choose, I'll have this problem.

I also tried the "AND NOT (...true...)" syntax since BOL states that evaluations against null result in FALSE. However, it seems they actually result in NULL and do not result in my multi-part statement becoming false.

I thought one solution is to use NaN or -INF or +INF since these are not valid in target. But I can't find a way to express this in the SQL.

Any ideas how to solve this?

EDIT:

The following logic solves the problem, but it's verbose and won't make for fast evals:

declare @i int, @j int

set @j = 0
set @i = 0

if ISNULL(@i, 0) != ISNULL(@j, 0) OR 
    ((@i is null or @j is null) and not (@i is null and @j is null))
    print 'update';

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

乱了心跳 2024-10-15 16:28:02

在 SQL Server 2022 中,您可以使用

WHEN MATCHED AND tgt.C IS DISTINCT FROM src.C

在以前的版本中,您可以使用

WHEN MATCHED AND EXISTS (SELECT tgt.C EXCEPT SELECT src.C)

如果您需要跨多个列执行此检查,第二个版本仍然可以更紧凑。

WHEN MATCHED AND EXISTS (SELECT tgt.A, tgt.B, tgt.C 
                         EXCEPT 
                         SELECT src.A, src.B, src.C)

有关此问题的更多信息,请参阅本文

In SQL Server 2022 you can use

WHEN MATCHED AND tgt.C IS DISTINCT FROM src.C

In previous versions you can use

WHEN MATCHED AND EXISTS (SELECT tgt.C EXCEPT SELECT src.C)

The second version can still be more compact if you need to do this check across multiple columns.

WHEN MATCHED AND EXISTS (SELECT tgt.A, tgt.B, tgt.C 
                         EXCEPT 
                         SELECT src.A, src.B, src.C)

See this article for more on this issue.

野鹿林 2024-10-15 16:28:02

您可以更改合并语句的 ON 部分,检查源和目标何时为空。

MERGE tgt
USING src
ON ( -- enter non-nullable columns to match on ...
    tgt.A = src.A
    AND (tgt.C = src.C OR (tgt.C IS NULL AND src.C IS NULL))
)
WHEN MATCHED -- ...

You can change the ON part of the merge statement, putting in a check for when both source and target are null.

MERGE tgt
USING src
ON ( -- enter non-nullable columns to match on ...
    tgt.A = src.A
    AND (tgt.C = src.C OR (tgt.C IS NULL AND src.C IS NULL))
)
WHEN MATCHED -- ...
老子叫无熙 2024-10-15 16:28:02

事实上,这样效果更好。只需添加另一个替换值作为 OR :-

WHEN MATCHED AND 
    ( 
    NOT (IsNull(tgt.C, 0) = IsNull(src.C, 0)) OR NOT (IsNull(tgt.C, 1) = IsNull(src.C, 1)) 
    ) 
THEN ....

Actually, this works better. Just add another substitution value as an OR :-

WHEN MATCHED AND 
    ( 
    NOT (IsNull(tgt.C, 0) = IsNull(src.C, 0)) OR NOT (IsNull(tgt.C, 1) = IsNull(src.C, 1)) 
    ) 
THEN ....
美煞众生 2024-10-15 16:28:02

您是否尝试过SET ANSI_NULLS OFF,这将使NULL=NULL返回true? 这可能会产生其他问题,但它可能是脚本级解决方法(运行过程后将其关闭然后再打开)。

Have you tried SET ANSI_NULLS OFF, which will make NULL=NULL return true? This may create additional issues but it could be a script-level workaround (turn it off then on once you run your proc).

七分※倦醒 2024-10-15 16:28:02
WHEN MATCHED AND tgt.c <> src.c OR tgt.c IS NULL AND src.c IS NOT NULL OR tgt.c IS NOT NULL AND src.c IS NULL
WHEN MATCHED AND tgt.c <> src.c OR tgt.c IS NULL AND src.c IS NOT NULL OR tgt.c IS NOT NULL AND src.c IS NULL
镜花水月 2024-10-15 16:28:02

当您有多个列想要检查它们是否不同时,这也有效,并且可能会更好。

  MERGE @t2 a

  using @t1 b

  ON a.PK = b.PK

  WHEN MATCHED AND CHECKSUM(a.PK,a.VALUE)!= CHECKSUM(b.pk,b.VALUE)

  THEN UPDATE SET a.VALUE = b.VALUE;

This works as well and may be better when you have multiple columns that you want to check if they are different.

  MERGE @t2 a

  using @t1 b

  ON a.PK = b.PK

  WHEN MATCHED AND CHECKSUM(a.PK,a.VALUE)!= CHECKSUM(b.pk,b.VALUE)

  THEN UPDATE SET a.VALUE = b.VALUE;
胡渣熟男 2024-10-15 16:28:02

您可以在 ON 子句中检查 null:

MERGE TargetTable
USING (VALUES (0)) as s(x)
ON last_run is not null
WHEN not matched then
insert (last_run) values(getdate())
when matched then
update set last_run=getDate();

You can check for null in the ON Clause:

MERGE TargetTable
USING (VALUES (0)) as s(x)
ON last_run is not null
WHEN not matched then
insert (last_run) values(getdate())
when matched then
update set last_run=getDate();
彩虹直至黑白 2024-10-15 16:28:02

当值为 null 时,为什么不使用一个极不可能存在的值,而不是使用 0?
EG (IsNull(tgt.C, 2093128301)。

数据类型是 int,所以你有很多东西可以玩……

Instead of using 0 when the values are null, why not use a value that is highly unlikely to exist?
EG (IsNull(tgt.C, 2093128301).

The datatypes are int so you have a lot to play with......

夜光 2024-10-15 16:28:02
WHEN MATCHED AND
(
   NULLIF(tgt.C, src.C) IS NOT NULL OR NULLIF(src.C, tgt.C) IS NOT NULL
)
THEN
WHEN MATCHED AND
(
   NULLIF(tgt.C, src.C) IS NOT NULL OR NULLIF(src.C, tgt.C) IS NOT NULL
)
THEN
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文