SQL WHERE 中的服务器 CASE 具有单一条件但多个 returns
SQL Server CASE in WHERE with single condition but multiple returns
用户故事
我需要 select 列来检查空值,并且我的 selection 中的关系是 OR(例如,Cost 为 NULL 或 PurchaseType 为 NULL,或两者均为 NULL)。
开发问题
我的应用程序有几个查询,这些查询以用户进行 selection 为条件。例如,如果 selection 字段被命名为 @selection1 和 @selection2 那么我的 where 子句如下所示:
select...
from...
where isActive=1
and (@selection1=column or @selection1='')
and (@selection2=column or @selection2='')
这个特定的用例要求我建立 OR 关系而不是 AND,这在我的逻辑中增加了一个问题:
select..
from...
where isActive=1
and ((@selection1=column or @selection1='')
or (@selection2=column or @selection2=''))
如果 selection 中的任何一个为空(每行后半部分为“=”),则整个子句 returns 为真并被跳过,返回所有行并忽略用户的有效 selection.
代码示例
DECLARE @filter AS VARCHAR(100)=''
/**Options are empty
, Cost to show only where Cost IS NULL
, PurchaseType to show only where PurchaseType IS NULL
, PurchaseQuantity to show only where PurchaseQuantity IS NULL
, or any combination of these 3 values to show where ANY COLUMN in the combination IS NULL
so if the user selects 'Cost,PurchaseQuantity', then they want columns 1,2,3,4,7
and if the user selects 'PurchaseType,PurchaseQuantity', then they want columns 1,2,3,4,6.
**/
-- Create Sample Table
IF OBJECT_ID('tempdb..#Product') IS NOT NULL
Truncate TABLE #Product
ELSE
CREATE TABLE #Product (id INT, Cost DEC(8,2), PurchaseType VARCHAR(20), PurchaseQuantity INT, isActive bit);
INSERT INTO #Product
VALUES
(1, NULL, NULL, NULL,1),
(2, 10.00, NULL, NULL,0),
(3, NULL, 'Each',NULL,1),
(4, NULL, NULL, 100,1),
(5, 5.50, 'Box',1,0),
(6, 142.00, NULL, 12,1),
(7, NULL, 'Pkg',50,1)
-- Select values from Sample Table
-- Works great for single @filter values, but fails for multiple
--SELECT id,Cost,PurchaseType,PurchaseQuantity FROM #Product
--WHERE
-- CASE WHEN @filter = 'Cost' THEN Cost
-- ELSE
-- CASE WHEN @filter='PurchaseType' THEN PurchaseType
-- ELSE
-- CASE WHEN @filter='PurchaseQuantity' THEN PurchaseQuantity
-- ELSE
-- CASE WHEN @filter='Cost,PurchaseType' THEN COALESCE(Cost,PurchaseType)
-- --CASE WHEN @filter='Cost,PurchaseType' THEN Cost or PurchaseType
-- --The above line expresses what I'm trying to do in pseudo, but doesn't work for resulting when Cost IS NULL or PurchaseType IS NULL
-- ELSE
-- CASE WHEN @filter='Cost,PurchaseQuantity' THEN COALESCE(Cost,PurchaseQuantity)
-- ELSE
-- CASE WHEN @filter='PurchaseQuantity,PurchaseType' THEN COALESCE(PurchaseQuantity,PurchaseType)
-- ELSE
-- CASE WHEN @filter='Cost,PurchaseQuantity,PurchaseType' THEN COALESCE(Cost,PurchaseQuantity,PurchaseType)
-- END END END END END END END
-- IS NULL
select id,Cost,PurchaseType,PurchaseQuantity,isActive
from #Product
where isActive=1
and (@filter !='' and
(
(Cost is null and @filter like '%Cost%')
or
(PurchaseType is null and @filter like '%PurchaseType%')
or
(PurchaseQuantity is null and @filter like '%PurchaseQuantity%')
))
我已经添加了@Stu 的逻辑,但是“isActive=1 和”以及我的生产架构中的其他逻辑意味着如果用户将过滤器留空而不是忽略@Filter 部分(这是我想看到的事情发生了)。
如我的代码示例中所述,我最终想设置 where 子句,以便
- 如果用户select没有@filter,则跳过 WHERE
- 如果用户 select 为 @filter 设置了单个值,则 WHERE returns 其中该单个列为 NULL
- 如果用户 select 为 @filter 设置多个值,则 WHERE returns 其中任何 @filter 列为 NULL
我已经在这上面花了一天半的时间,但我一无所获...希望我错过了一些简单的事情,互联网上的人有办法解决这个问题。提前致谢!!
我不明白你是怎么想出这个安排的,但这对你有用吗?很难确定!
select id,Cost,PurchaseType,PurchaseQuantity,isActive
from #Product
where isActive=1 and
(@Filter ='' or
(
(Cost is null and @filter like '%cost%')
or
(PurchaseType is null and @filter like '%PurchaseType%')
or
(PurchaseQuantity is null and @filter like '%PurchaseQuantity%')
))
请注意,这几乎肯定会导致查询性能不佳,特别是如果 table 很大 - 1000 行。
最好做 3 个单独的查询并 union
结果 - 这样优化器就可以在每个查询上使用 suitable 索引。
用户故事
我需要 select 列来检查空值,并且我的 selection 中的关系是 OR(例如,Cost 为 NULL 或 PurchaseType 为 NULL,或两者均为 NULL)。
开发问题
我的应用程序有几个查询,这些查询以用户进行 selection 为条件。例如,如果 selection 字段被命名为 @selection1 和 @selection2 那么我的 where 子句如下所示:
select...
from...
where isActive=1
and (@selection1=column or @selection1='')
and (@selection2=column or @selection2='')
这个特定的用例要求我建立 OR 关系而不是 AND,这在我的逻辑中增加了一个问题:
select..
from...
where isActive=1
and ((@selection1=column or @selection1='')
or (@selection2=column or @selection2=''))
如果 selection 中的任何一个为空(每行后半部分为“=”),则整个子句 returns 为真并被跳过,返回所有行并忽略用户的有效 selection.
代码示例
DECLARE @filter AS VARCHAR(100)=''
/**Options are empty
, Cost to show only where Cost IS NULL
, PurchaseType to show only where PurchaseType IS NULL
, PurchaseQuantity to show only where PurchaseQuantity IS NULL
, or any combination of these 3 values to show where ANY COLUMN in the combination IS NULL
so if the user selects 'Cost,PurchaseQuantity', then they want columns 1,2,3,4,7
and if the user selects 'PurchaseType,PurchaseQuantity', then they want columns 1,2,3,4,6.
**/
-- Create Sample Table
IF OBJECT_ID('tempdb..#Product') IS NOT NULL
Truncate TABLE #Product
ELSE
CREATE TABLE #Product (id INT, Cost DEC(8,2), PurchaseType VARCHAR(20), PurchaseQuantity INT, isActive bit);
INSERT INTO #Product
VALUES
(1, NULL, NULL, NULL,1),
(2, 10.00, NULL, NULL,0),
(3, NULL, 'Each',NULL,1),
(4, NULL, NULL, 100,1),
(5, 5.50, 'Box',1,0),
(6, 142.00, NULL, 12,1),
(7, NULL, 'Pkg',50,1)
-- Select values from Sample Table
-- Works great for single @filter values, but fails for multiple
--SELECT id,Cost,PurchaseType,PurchaseQuantity FROM #Product
--WHERE
-- CASE WHEN @filter = 'Cost' THEN Cost
-- ELSE
-- CASE WHEN @filter='PurchaseType' THEN PurchaseType
-- ELSE
-- CASE WHEN @filter='PurchaseQuantity' THEN PurchaseQuantity
-- ELSE
-- CASE WHEN @filter='Cost,PurchaseType' THEN COALESCE(Cost,PurchaseType)
-- --CASE WHEN @filter='Cost,PurchaseType' THEN Cost or PurchaseType
-- --The above line expresses what I'm trying to do in pseudo, but doesn't work for resulting when Cost IS NULL or PurchaseType IS NULL
-- ELSE
-- CASE WHEN @filter='Cost,PurchaseQuantity' THEN COALESCE(Cost,PurchaseQuantity)
-- ELSE
-- CASE WHEN @filter='PurchaseQuantity,PurchaseType' THEN COALESCE(PurchaseQuantity,PurchaseType)
-- ELSE
-- CASE WHEN @filter='Cost,PurchaseQuantity,PurchaseType' THEN COALESCE(Cost,PurchaseQuantity,PurchaseType)
-- END END END END END END END
-- IS NULL
select id,Cost,PurchaseType,PurchaseQuantity,isActive
from #Product
where isActive=1
and (@filter !='' and
(
(Cost is null and @filter like '%Cost%')
or
(PurchaseType is null and @filter like '%PurchaseType%')
or
(PurchaseQuantity is null and @filter like '%PurchaseQuantity%')
))
我已经添加了@Stu 的逻辑,但是“isActive=1 和”以及我的生产架构中的其他逻辑意味着如果用户将过滤器留空而不是忽略@Filter 部分(这是我想看到的事情发生了)。
如我的代码示例中所述,我最终想设置 where 子句,以便
- 如果用户select没有@filter,则跳过 WHERE
- 如果用户 select 为 @filter 设置了单个值,则 WHERE returns 其中该单个列为 NULL
- 如果用户 select 为 @filter 设置多个值,则 WHERE returns 其中任何 @filter 列为 NULL
我已经在这上面花了一天半的时间,但我一无所获...希望我错过了一些简单的事情,互联网上的人有办法解决这个问题。提前致谢!!
我不明白你是怎么想出这个安排的,但这对你有用吗?很难确定!
select id,Cost,PurchaseType,PurchaseQuantity,isActive
from #Product
where isActive=1 and
(@Filter ='' or
(
(Cost is null and @filter like '%cost%')
or
(PurchaseType is null and @filter like '%PurchaseType%')
or
(PurchaseQuantity is null and @filter like '%PurchaseQuantity%')
))
请注意,这几乎肯定会导致查询性能不佳,特别是如果 table 很大 - 1000 行。
最好做 3 个单独的查询并 union
结果 - 这样优化器就可以在每个查询上使用 suitable 索引。