如何从具有多个条件的 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'
我有以下数据:
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'