如何从具有多个条件的 WHERE 条件中排除 ISNULL?

How to exclude ISNULL from WHERE condition with multiple conditions?

我有以下数据:

DECLARE @tbl TABLE (
    Id INT,
    [Date_1] DATETIME2,
    [Date_2] DATETIME2
)

INSERT INTO @tbl ([Id], [Date_1], [Date_2]) VALUES
(1, '2018-08-15 16:05:20.000', NULL),
(2, '2018-08-15 16:05:20.000', NULL),
(3, '2018-08-15 16:05:20.000', NULL),
(4, '2018-08-20 00:00:00.000', NULL),
(5, NULL, NULL),
(6, '2018-08-30 14:02:08.000', '2018-09-05 12:31:30.530')

我有一个查询可以完美适用于各种条件:

SELECT *
FROM @tbl AS t
WHERE
    (ISNULL(t.[Date_1], '1900-1-1') BETWEEN @DateFrom AND @DateTo) OR
    (ISNULL(t.[Date_2], '1900-1-1') BETWEEN @DateFrom AND @DateTo)

第一种情况.

DECLARE @DateFrom DATE = '1900-01-01', @DateTo DATE = '9999-12-30' -- result one. The overall count is 6 rows

结果将是:

第二种情况。如果我更改 @DateFrom@DateTo:

DECLARE @DateFrom DATE = '2018-08-15', @DateTo DATE = '2018-08-16' -- result two. The overall count is 3 rows

那么结果将是:

第三种情况。如果我更改 @DateFrom@DateTo:

DECLARE @DateFrom DATE = '2018-09-05', @DateTo DATE = '2018-09-06' -- result three. The overall count is 1 row

那么结果将是:

我的问题是如何从 WHERE 语句中排除 ISNULL? 我尝试了不同的方法,但它们给了我不正确的结果:

SELECT *
FROM @tbl AS t
WHERE
((t.[Date_1] IS NOT NULL AND t.[Date_1]  BETWEEN @DateFrom
    AND @DateTo) OR t.[Date_1] IS NULL) OR
((t.[Date_2] IS NOT NULL AND t.[Date_2] BETWEEN @DateFrom
    AND @DateTo) OR t.[Date_2] IS NULL)

如有任何帮助,我们将不胜感激。我无法将 @DateFrom@DateTo 设置为 NULL

当 (@DateFrom, @DateTo) 是最小和最大日期文字时,您似乎只需要所有记录。

然后这个查询returns那个。

SELECT  * 
FROM @tbl AS t     
WHERE ( (t.[Date_1] >= @DateFrom AND t.[Date_1] < DATEADD(day,1,@DateTo)) 
     OR (t.[Date_2] >= @DateFrom AND t.[Date_2] < DATEADD(day,1,@DateTo))
     OR (@DateFrom <= '1900-01-01' AND @DateTo >= '9999-01-01')
);

BETWEEN 已被替换,因为 Date_1 和 Date_2 不是 DATE 类型。

演示

DECLARE @tbl TABLE 
(
    Id int,
    [Date_1] DateTime2,
    [Date_2] DateTime2
)
Insert Into @tbl ([Id],[Date_1],[Date_2])
Values 
  (1, '2018-08-15 16:05:20.000', NULL)
, (2, '2018-08-15 16:05:20.000', NULL)
, (3, '2018-08-15 16:05:20.000', NULL)
, (4, '2018-08-20 00:00:00.000', NULL)
, (5, NULL,NULL)
, (6, '2018-08-30 14:02:08.000', '2018-09-05 12:31:30.530');

DECLARE @DateFrom DATE, @DateTo DATE;

SELECT @DateFrom = '1900-01-01', @DateTo = '9999-12-30'; 
-- result 1.  The overall count is 6 rows
    
SELECT  * 
FROM @tbl AS t     
WHERE ( (t.[Date_1] >= @DateFrom AND t.[Date_1] < DATEADD(day,1,@DateTo)) 
     OR (t.[Date_2] >= @DateFrom AND t.[Date_2] < DATEADD(day,1,@DateTo))
     OR (@DateFrom <= '1900-01-01' AND @DateTo >= '9999-01-01')
);
       
SELECT @DateFrom = '2018-08-15', @DateTo = '2018-08-16';
-- result two. The overall count is 3 rows   

SELECT  * 
FROM @tbl AS t     
WHERE ( (t.[Date_1] >= @DateFrom AND t.[Date_1] < DATEADD(day,1,@DateTo)) 
     OR (t.[Date_2] >= @DateFrom AND t.[Date_2] < DATEADD(day,1,@DateTo))
     OR (@DateFrom <= '1900-01-01' AND @DateTo >= '9999-01-01')
);

SET @DateFrom = '2018-09-05'; SET @DateTo = '2018-09-06';
-- result three. The overall count is 1 row

SELECT  * 
FROM @tbl AS t     
WHERE ( (t.[Date_1] >= @DateFrom AND t.[Date_1] < DATEADD(day,1,@DateTo)) 
     OR (t.[Date_2] >= @DateFrom AND t.[Date_2] < DATEADD(day,1,@DateTo))
     OR (@DateFrom <= '1900-01-01' AND @DateTo >= '9999-01-01')
);
GO
Id | Date_1                      | Date_2                     
-: | :-------------------------- | :--------------------------
 1 | 2018-08-15 16:05:20.0000000 | null                       
 2 | 2018-08-15 16:05:20.0000000 | null                       
 3 | 2018-08-15 16:05:20.0000000 | null                       
 4 | 2018-08-20 00:00:00.0000000 | null                       
 5 | null                        | null                       
 6 | 2018-08-30 14:02:08.0000000 | 2018-09-05 12:31:30.5300000

Id | Date_1                      | Date_2
-: | :-------------------------- | :-----
 1 | 2018-08-15 16:05:20.0000000 | null  
 2 | 2018-08-15 16:05:20.0000000 | null  
 3 | 2018-08-15 16:05:20.0000000 | null  

Id | Date_1                      | Date_2                     
-: | :-------------------------- | :--------------------------
 6 | 2018-08-30 14:02:08.0000000 | 2018-09-05 12:31:30.5300000

db<>fiddle here

首先,使用BETWEEN 来比较日期时间数据类型是不正确的。例如,您的原始查询不允许您 select 所有 2018-08-15 日期但排除 2018-08-16 00:00:00.

的确切值

其次,您似乎想要一个“包罗万象”的查询。

我将使用以下 WHERE 子句:

WHERE Date_1 >= @DateFrom AND Date_1 < @DateTo
OR    Date_2 >= @DateFrom AND Date_2 < @DateTo
OR    @DateFrom IS NULL AND @DateTo IS NULL

然后设置值如下:

-- catch all
SET @DateFrom = NULL
SET @DateTo   = NULL

-- all dates between 2018-08-15 00:00 and 2018-08-15 23:59:59.9999999
SET @DateFrom = '2018-08-15'
SET @DateTo   = '2018-08-16'

-- all dates between 2018-09-05 00:00 and 2018-09-05 23:59:59.9999999
SET @DateFrom = '2018-09-05'
SET @DateTo   = '2018-09-06'