如何根据变量有选择地应用 WHERE IN 子句?

How to optionally apply a WHERE IN clause based on a variable?

我有一个存储过程需要按作为逗号分隔列表(即 '1,2,3')传递的 ID 列表进行过滤。

我想应用一个匹配这些 ID 的 WHERE IN 子句,但前提是变量包含任何内容 (IS NOT NULL AND <> '')。

这里是问题的简化 fiddle:http://sqlfiddle.com/#!18/5f6be/1

它目前适用于单个和多个 ID。但是当传递 ''NULL 时,它应该 return 一切但它不是 returning 任何东西。

CTE 和分页的存在是有原因的,请提供不会改变它的解决方案。

使用 DelimitedSplit8k_lead 您可以通过以下方式实现:

CREATE PROC YourProc @List varchar(8000) = NULL AS
BEGIN

    SELECT {YourColumns}
    FROM YourTable YT
         OUTER APPLY dbo.DelimitedSplit8k_Lead(@List,',') DS
    WHERE DS.item = YT.YourColumn
       OR NULLIF(@List,'') IS NULL
    OPTION (RECOMPILE);
END

用的是OUTER APPLY,就好像传了NULL一样数据集不会被淘汰。 RECOMPILE 在那里,因为它变成了 "Catch-all query" 加上处理 NULL.

老派方法:

WHERE
(@userIds IS NULL OR @userIds = '' OR U.Id IN (SELECT * FROM STRING_SPLIT(@userIds, ',')))

在末尾添加 OPTION (RECOMPILE) 以使其生效并 trim 计划。


编辑: 根据评论,此生成两个 table 扫描。它对我的 LocalDb 设置没有影响,但无论如何不要依赖它。

WHERE U.Id IN
(
   SELECT * FROM STRING_SPLIT(@userIds, ',')
   UNION ALL
   SELECT U.Id WHERE NULLIF(@userIds, '') IS NULL
)

为什么不在 WHERE 子句中使用 JOIN 而不是子查询。

set @userIds = nullif(ltrim(@userIds),'')
select u.*
from Users u
left join string_split(@userIds,',') s on u.Id=s.value
where s.value is not null or @userIds is null