我在 SQL Server 中有这个 SQL 查询作为上下文。
SELECT
O.OrderID, SUM(P.Quantity) AS SprayGlueCans
FROM
FCMDB.dbo.FcoOrders O
JOIN
FCMDB.dbo.FcoStyleGroups SG ON SG.OrderID = O.OrderID
JOIN
FCMDB.dbo.FcoProducts P ON P.StyleGroupID = SG.StyleGroupID
WHERE
P.CatalogProductID = 12715
AND O.Shipped = 1
AND MONTH(O.ShipDate) = 8
AND YEAR(O.ShipDate) = 2023
AND O.InstallerID <> 3
AND InstallerID <> 29
GROUP BY
O.OrderID
当我运行它时,除了
InstallerID
可以为 NULL 之外,一切都运行良好。我预计这并不重要,因为。我假设由于 NULL 不是 3 或 29,那么它将包含在结果中。但这个查询似乎遗漏了所有带有 NULL InstallerID
的内容。我想知道为什么会这样。
这就是它的工作原理吗?如果是这样,我是否应该小心不要编写再次出现此错误的查询?如果这是真的,是否有实践或设计选择可以最好地处理或避免这种情况?
正如我在评论中提到的,
NULL
值不适用于相等运算符。当 SomeColumn != 3
的值为 SomeColumn
时,3
将返回 UNKNOWN,重要的是 isn't TRUE,因此该行会从结果集中省略。
与
NULL
进行比较时,您需要使用 IS NULL
或 IS DISTINCT FROM
(后者仅在 Azure 或 SQL Server 2022+ 上受支持)。例如 (SomeColumn != 3 OR SomeColumn IS NULL)
和 SomeColumn IS DISTINCT FROM 3
。
对于您的查询,结果如下((取消)评论适合您的解决方案):
USE FCMDB; --Connect to the correct DB, there's no need for 3 part naming here
GO
SELECT O.OrderID,
SUM(P.Quantity) AS SprayGlueCans
FROM dbo.FcoOrders O
JOIN dbo.FcoStyleGroups SG ON SG.OrderID = O.OrderID
JOIN dbo.FcoProducts P ON P.StyleGroupID = SG.StyleGroupID
WHERE P.CatalogProductID = 12715
AND O.Shipped = 1
AND O.ShipDate >= '20230801'
AND O.ShipDate < '20230901'
AND (O.InstallerID NOT IN (3,29) OR O.InstallerID IS NULL)
--AND O.InstallerID IS DISTINCT FROM 3 AND O.InstallerID IS DISTINCT FROM 29
GROUP BY O.OrderID;
您会注意到,当使用
NOT IN
时,我切换到 IS NULL
,并且我还将您针对 ShipDate
的条款更改为 SARGable。再次强调,正如评论中提到的,不要在 YEAR(O.ShipDate) = 2023
中使用像 WHERE
这样的子句,因为索引不能用于此类查询,这将导致性能不佳。