Add/Skip WHERE CLAUSE 基于条件

Add/Skip WHERE CLAUSE based on Condition

我有以下查询,它从 table 变量和 returns 列表中获取 TagId 列表。

但只有当@Tags 有记录时,我才需要添加 CategoryId WHERE 条件。

是否可以仅在我的 table 变量有记录时添加 WHERE 条件,否则 运行 使用 1=1(始终为真)的相同查询并跳过类别过滤器?

DECLARE @TagIdList NVARCHAR(100) = '22,25,47'
DECLARE @Tags TABLE (TagId INT);

WITH CSVtoTable
AS (
    SELECT CAST('<XMLRoot><RowData>' + REPLACE(t.val, ',', '</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x
    FROM (
        SELECT @TagIdList
        ) AS t(val)
    )
INSERT INTO @Tags (TagId)
SELECT m.n.value('.[1]', 'varchar(8000)') AS TagId
FROM CSVtoTable
CROSS APPLY x.nodes('/XMLRoot/RowData') m(n)

SELECT BookingId
    ,C.CategoryName
FROM Booking B
INNER JOIN Category C ON C.CategoryId = B.CategoryId
WHERE (
        b.IsDeleted = 0
        OR b.IsDeleted IS NULL
        )
 -- Add the below where condition only if @Tags has records, else use 1=1
    AND C.CategoryId IN (
        SELECT DISTINCT CategoryId
        FROM CategoryXTag con
        WHERE TagId IN (
                SELECT TagId
                FROM @Tags
                )
        )
declare int @tagcount = (select count(*) from @Tags); 

SELECT BookingId, C.CategoryName
FROM Booking B
INNER JOIN Category C 
        ON C.CategoryId = B.CategoryId 
       AND isnull(b.IsDeleted, 0) = 0 
INNER JOIN CategoryXTag con 
        ON C.CategoryId = con.CategoryId 
INNER JOIN @Tags tags 
        ON tags.TagID = con.TagID
        OR @tagcount = 0;

如果@tags 为空,您可能需要在其中放入一条记录,其中包含一个永远不会被使用的值,然后或该值

if(@tagcount = 0) insert into @tags values (-100); 
or tags.TagID = -100;

最终您只需要更改查询的结尾即可。如果性能是一个问题,您可能需要考虑为这两种情况中的每一种使用 if 块的两个分支,即使从技术上讲可以将逻辑压缩到通常也不会优化的单个查询中。

AND
(
    C.CategoryId IN (
        SELECT CategoryId
        FROM CategotryXTag
        WHERE TagId IN (
            SELECT TagId
            FROM @Tags
        )
    )
    OR
    (SELECT COUNT(*) FROM @Tags) = 0
)

您无需修改​​ where 子句。相反,如果 @Tags 在初始插入后为空,则在 运行 之前用 CategoryXTag 中的每个 TagId 填充 @Tags 来实现相同的逻辑:

if ((select count(*) from @Tags) = 0)
  insert into @Tags
  select distinct TagId
  from CategoryXTag;

我会为 @Tags 声明一个变量 table:

declare @needTagsFilter bit
set @needTagsFilter = case when exists(select 1 from @Tags) then 1 else 0 end

并像

这样更改 where 子句
AND (
     (@needTagsFilter = 0) OR 
     (C.CategoryId IN (
      SELECT DISTINCT CategoryId
      FROM CategoryXTag con
      WHERE TagId IN (
            SELECT TagId
            FROM @Tags
            )
     )
    )

COUNT(*) 比 exists 慢。将 count/exists 直接添加到原始查询的缺点是 SQL 服务器可能会对所有行执行它。