【发布时间】:2021-04-01 18:40:11
【问题描述】:
用户故事
我需要选择列来检查空值,并且我的选择中的关系是 OR(例如 Cost IS NULL 或 PurchaseType IS NULL,或两者都是 NULL)。
发展问题
我的应用程序有几个以用户进行选择为条件的查询。例如,如果选择字段被命名为 @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=''))
如果任何一个选择为空(每行后半部分为''=''),则整个子句返回 true 并被跳过,返回所有行并忽略用户的有效选择。
代码示例
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 and”和其他逻辑意味着如果用户将过滤器留空而不是忽略@Filter 部分(这就是我想看到发生)。
如我的代码示例中所述,我最终希望设置 where 子句,以便
- 如果用户没有为 @filter 选择任何内容,则跳过 WHERE
- 如果用户为 @filter 选择单个值,则 WHERE 返回该单个列为 NULL 的位置
- 如果用户为 @filter 选择多个值,则 WHERE 将返回任何 @filter 列为 NULL 的位置
我已经花了一天半的时间来解决这个问题......希望我错过了一些简单的事情,并且互联网上的某个人有办法解决这个问题。提前致谢!!
【问题讨论】:
-
恐怕这只是一个糟糕的设计。不要走这条路。为您可能要过滤的每个列传递参数,并设计一个“catch&all”/“kitchen sink”查询。
-
这是一个设计的母马,如果你有 5 列或 10 列呢?!
-
我的 2 美分 - 不要给用户太多的灵活性。随着时间的推移,提供这种服务的成本很高,而且用户实际上很少使用它。我发现用户通常只需要几个搜索选项,并且通常使用更小的集合。
标签: sql-server case where-clause sql-null