为啥某些 Where 子句被忽略?

Posted

技术标签:

【中文标题】为啥某些 Where 子句被忽略?【英文标题】:Why is some of the Where clause being ignored?为什么某些 Where 子句被忽略? 【发布时间】:2021-01-08 23:11:32 【问题描述】:

我有这张桌子:

CREATE TABLE [dbo].[Handshake]
(
    [Report Year] [varchar](100) NULL,
    [Status] [varchar](100) NULL,
    [Update Time] [datetime] NULL,
    [Process Time] [datetime] NULL
) ON [PRIMARY]
GO

一些样本数据:

Report Year Status       Update Time                Process Time
----------------------------------------------------------------
Test        Loading      2020-09-22 12:53:41.417    NULL
2020 1+7    Loaded       2020-09-22 12:46:41.417    NULL
2020 2+7    Loaded       2020-09-21 21:18:25.130    NULL

我有以下程序:

DECLARE
    @ReportYearCmd VARCHAR(1000),
    @CosCountCmd VARCHAR(1000),
    @FranchiseCountCmd AS VARCHAR(1000),
    @ProductCountCmd AS VARCHAR(1000);

WITH Validations AS 
(
    SELECT TOP 1 * 
    FROM [Handshake] 
    WHERE [Status] <> 'Loading' 
      AND [Update Time] = (SELECT MAX([Update Time]) FROM Handshake)
)
UPDATE Validations 
SET @ReportYearCmd = CASE 
                        WHEN Report_Year_Count = 0 
                           THEN NULL 
                           ELSE 'SELECT DISTINCT [Report Year] AS [Report Year] FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [Report Year] WHERE [Report Year].[Report Year] = [Fact].[Report Year] );'
                     END,
    @CosCountCmd = CASE 
                      WHEN COS_Count = 0 
                         THEN NULL 
                         ELSE 'SELECT DISTINCT [Country Code] AS [COS - Country Code] FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [COS] WHERE [COS].[Country Code] = [Fact].[Country Code] );' 
                   END,
    @FranchiseCountCmd = CASE WHEN  Franchise_Count = 0 THEN NULL 
        ELSE 'SELECT DISTINCT [Style Code] AS [Franchise - Style Code] FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [Franchise] WHERE [Franchise].[Style Code] = [Fact].[Style Code] );' 
    END,
    @ProductCountCmd = CASE WHEN Product_Count = 0 THEN NULL 
        ELSE 'SELECT DISTINCT [Style Code] AS [Product - Style Code] FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [Product] WHERE [Product].[Style Code] = [Fact].[Style Code] );' 
    END,
    [Status] = CASE
        WHEN ( Report_Year_Count = 0 AND COS_Count = 0 AND Franchise_Count = 0 AND Product_Count = 0 ) THEN 'Good'
        ELSE 'Rejects'
    END
FROM 
    [Validations] 
OUTER APPLY 
    (SELECT 
         ISNULL((SELECT COUNT(*) FROM [Fact] 
                 WHERE NOT EXISTS (SELECT * FROM [Report Year] WHERE [Report Year].[Report Year] = [Fact].[Report Year] ) ), 0 ) AS [Report_Year_Count],
        ISNULL( ( SELECT COUNT(*) FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [COS] WHERE [COS].[Country Code] = [Fact].[Country Code] ) ), 0 ) AS [COS_Count],
        ISNULL( ( SELECT COUNT(*) FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [Franchise] WHERE [Franchise].[Style Code] = [Fact].[Style Code] ) ), 0 ) AS [Franchise_Count],
        ISNULL( ( SELECT COUNT(*) FROM [Fact] WHERE NOT EXISTS ( SELECT * FROM [Product] WHERE [Product].[Style Code] = [Fact].[Style Code] ) ), 0 ) AS [Product_Count]

) AS [ValidationCounts];

只有当我在 Validations SELECT 语句中不包含此部分时,该过程才有效:...WHERE [Status] &lt;&gt; 'Loading'...,因此会选择最近的更新时间记录,例如

Test        Loading      2020-09-22 12:53:41.417    NULL

当我包含...WHERE [Status] &lt;&gt; 'Loading'... 时,什么都没有发生!

期望:查询应该获取这条记录:

2020 1+7    Loaded       2020-09-22 12:46:41.417    NULL

但它没有……为什么?

【问题讨论】:

试试这个...WHERE [Status] != N'Loading'......WHERE [Status] not in (N'Loading')... @Amirhossein nope 没用 【参考方案1】:

如果你想要最新的未加载状态,则不需要子查询。您可以在带有where 子句的非加载行上使用过滤器,然后order by 降序日期,并仅保留top (1) 行:

WITH validations AS (
    SELECT TOP (1) * 
    FROM [Handshake] 
    WHERE [Status] <> 'Loading' 
    ORDER BY [Update Time] DESC
)
UPDATE validations ...

【讨论】:

这个完全符合我的预期,并且不更新旧记录:)【参考方案2】:

SELECT MAX( [Update Time] ) FROM Handshake 的结果是 2020-09-22 12:53:41.417

现在您的查询是

SELECT TOP 1 * FROM [Handshake] WHERE [Status] <> 'Loading' AND [Update Time] = '2020-09-22 12:53:41.417'

当您评估上述查询时,您会看到在更新时间 2020-09-22 12:53:41.417 时没有状态加载的记录

正确的查询应该是

SELECT TOP 1 * FROM [Handshake] h 
WHERE [Status] <> 'Loading' AND 
  [Update Time] = ( 
    SELECT MAX( [Update Time] ) 
    FROM Handshake hi where hi.Status = h.Status)

【讨论】:

哦,等一下,如果我一遍又一遍地执行它,它现在也会更新旧记录......它应该只更新最新的非加载状态 但最新的非加载记录在您​​更新时会发生变化。你还有另一个顾虑。您正在更改状态,这实际上是预期的。这是一个设计问题。 是对“拒绝”或“不拒绝”的最新非加载更改。但不应该碰旧的记录。应该只更新最近的记录,因此为什么我要以SELECT MAX( [Update Time] ) 开头 那么您的查询就可以了。在给定时间没有处于非加载状态的记录。 但是当我再次运行查询时这条记录得到了更新,它不应该是....2020 2+7 Loaded 2020-09-21 21:18:25.130 NULL

以上是关于为啥某些 Where 子句被忽略?的主要内容,如果未能解决你的问题,请参考以下文章

Oracle [过程] - Sum 函数忽略 WHERE 子句

Redshift Cross join忽略where子句

SSIS 数据流,忽略 SQL 语句中的 where 子句

如何在 SQL Server 2008 的 where 子句中仅比较日期并忽略时间

为啥我不能在 INSERT 语句中使用 WHERE 子句进一步压缩我的查询?

SQL相关易忽略点