19

我有一个更新查询,当值与另一个表中的字段不匹配时,它会更新一个表中的字段。

UPDATE  table1
SET     a.field1 = b.field3
FROM    table1 a ,
        table2 b
WHERE   a.field2 = b.field2
        AND a.field1 <> b.field3

我遇到的问题是,当 a.field1 为 null 且 b.field3 为值或 a.field1 为值且 b.field3 为 null 时,它不会启动。

我通过添加以下内容解决了这个问题......

UPDATE  table1
SET     a.field1 = b.field3
FROM    table1 a ,
        table2 b
WHERE   a.field2 = b.field2
        AND ( a.field1 <> b.field3
              OR (a.field1 IS NOT NULL
              AND b.field3 IS NULL)
              OR (a.field1 IS NULL
              AND b.field3 IS NOT NULL)
            )

我的问题更集中在为什么会发生这种情况以及如何最好地构建查询以防止这种情况发生?

4

8 回答 8

10

问题在于 NULL 比较。如果 a.field1 或 b.field3 为 NULL,则需要使用 IS NULL 或 IS NOT NULL 语句。您可以使用 ISNULL 函数为 a.field1 和 b.field3 使用默认值。

ISNULL(a.field1,0) <> ISNULL(b.field3,0)

在这种情况下,与值 0 进行比较。

SELECT IIF(NULL=NULL,'true','false')  -- The result is false.  Amazing!
于 2013-04-10T15:00:53.537 回答
8

将任何东西与 NULL 进行比较的结果,甚至它本身,总是 NULL(不是 TRUE 或 FALSE)。将选项与 EXISTS 和 EXCEPT 运算符一起使用。

UPDATE table1
SET a.field1 = b.field3
FROM table1 a JOIN table2 b ON a.field2 = b.field2
WHERE EXISTS (
              SELECT a.field1
              EXCEPT
              SELECT b.field3
              )
于 2013-04-10T15:07:30.507 回答
2

除了正确处理 NULL 逻辑之外,您还需要将要一起应用的多个条件括在括号中

像这样的东西(不确定我是否完全理解你的情况)。

UPDATE  table1
SET     a.field1 = b.field3
FROM    table1 a ,
        table2 b
WHERE   a.field2 = b.field2
        AND (
              ( a.field1 <> b.field3)
              OR (a.field1 IS NOT NULL AND b.field3 IS NULL)
              OR (a.field1 IS NULL AND b.field3 IS NOT NULL)
            )
于 2013-04-10T14:58:41.950 回答
1

Tim Shmelter 在他的评论中是对的,NULL不等于任何东西——甚至包括NULLNULL字面意思是值未知。

这意味着,即使a.field1and b.field3both are NULL,条件a.field1 <> b.field3以及a.field1 = b.field3both 也将始终返回 false。试试看,你会看到!

我认为这里的解决方案并不在于IFNULLSQL Server 的功能。它更多地在于您的加入逻辑。您已经有了解决方案,即问题中的第二个查询。我建议你多玩一点NULL价值观,这样你就可以理解它们的真正含义。

于 2013-04-10T15:00:30.790 回答
1

您可以coalesce在 SQL Server 中使用将列的值默认为非空值。Coalesce返回列表中的第一个非空值。

UPDATE  table1
SET     a.field1 = b.field3
FROM    table1 a ,
        table2 b
WHERE   a.field2 = b.field2
        AND (
           coalesce(a.field1,-1) <> coalesce(b.field3, -1)
        )

我假设您的类型是数字,尽管您可以使用其他数据类型。我还假设如果两个值都是 NULL,那么这两行是等价的。

于 2015-04-16T14:20:33.333 回答
0

当您在查询中编写时,您a.field1 = b.field3实际上做了两个假设:表 a 中的 field1 必须包含一个值,而 b 表中的 field3 也必须包含一个值。无法将“缺失信息和不适用信息”与某个值进行比较。这种比较的结果是未知的。您可以在Wikipedia上查看更多信息。

于 2013-04-10T15:04:20.367 回答
0

这将检查 Column1 和 Column2 是否相等,另外使用转换为 VARBINARY 来比较区分大小写,如果不需要,您可以将其删除。

--c1 = Length of Column1
--c2 = Length of Column2

ISNULL(NULLIF(CONVERT(VARBINARY(cl), LTRIM(RTRIM(Column1))), CONVERT(VARBINARY(c2),LTRIM(RTRIM(Column2)))), NULLIF(CONVERT(VARBINARY(c2),LTRIM(RTRIM(Column2))), CONVERT(VARBINARY(c1),LTRIM(RTRIM(Column1))))) IS NULL

您可以将表达式的结尾更改IS NOT NULL为检查不相等的条件。

希望这有帮助。

于 2014-12-01T23:00:24.833 回答
0

另一种方法是使用CHECKSUM函数

create table #temp
  (
    val1 varchar(255),
    val2 varchar(255)
  )

  insert into #temp values(NULL, NULL) 
  insert into #temp values(NULL, 'B') 
  insert into #temp values('A', NULL) 
  insert into #temp values('A', 'B') 
  insert into #temp values('A', 'A') 

  select *, 
  'Are Not Equal' = case 
   when val1 <> val2 or checksum(val1) <> checksum(val2) then 'true' 
   else 'false' end 
  from #temp
于 2016-03-17T18:56:23.857 回答