条件加入 SQL 服务器存储过程

Conditional Join in SQL Server stored procedure

我有 3 个变量 filter1filter2filter3,它们基于用户输入。其值为 1 或 0。

表格是

现在我想编写一个查询:

现在如何有条件地将innerjoin conjunctively添加到上述场景中,或者对于上述问题陈述还有其他方法吗

我试过以下解决方案,

Select * 
from 
    users
left join 
    filtertable1 on users.filtercount1 = filtertable1.filtercount1 
                 and filter1 = 1
left join 
    filtertable2 on users.filtercount2 = filtertable3.filtercount2 
                 and filter2 = 1
left join 
    filtertable3 on users.filtercount3 = filtertable3.filtercount3 
                 and filter3 = 1

但我不想使用左连接。对于上述情况,如果数据大于(20000 行)左连接将比内连接花费更多时间。

left join没问题。但您也可以使用 exists:

Select u.*
from users u
where (u.filter1 = 1 and
       exists (select 1 from filtertable1 ft where u.filtercount1 = ft.filtercount1)
      ) or
      (u.filter2 = 1 and
       exists (select 1 from filtertable2 ft where u.filtercount2 = ft.filtercount1)
      ) or
      (u.filter3 = 1 and
       exists (select 1 from filtertable3 ft where u.filtercount3 = ft.filtercount1)
      ) ;

注意:我不确定您是想在条件之间选择 and 还是 or。使用 and 逻辑会略有不同。

不应在查询内部进行条件过滤,因为它会导致查询执行计划不理想。

  • 相反,对于每个“查询形状”使用不同的查询...尽管这现在意味着必须使用许多 IF 分支来保存每个不同的查询或者使用 Dynamic-SQL.

动态SQL

  • 而不是将 整个查询 (包括任何 GROUP BY 和聚合以及其他谓词)放在 Dynamic SQL 中,而是使用 Dynamic-SQL 构建 一个仅包含主键的 TABLE 变量,- 然后在最终的非动态输出查询中使用该 table 变量。
    • 这种方法意味着您还可以在同一过程中的其他查询中使用它,而无需重新运行 搜索。使用 sp_executesql 插入外部作用域中的 table 变量。

像这样:

DECLARE @filter1 bit = 0;
DECLARE @filter2 bit = 0;
DECLARE @filter3 bit = 0;

DECLARE @userIds TABLE ( userId int PRIMARY KEY );

DECLARE @q varchar(max) = 'SELECT UserId FROM dbo.Users AS u';
IF @filter1 = 1
BEGIN
    @q = @q + 'INNER JOIN filtertable1 AS f1 ON u.filtercount1 = f1.filtercount1 ';
END

IF @filter2 = 1
BEGIN
    @q = @q + 'INNER JOIN filtertable2 AS f2 ON u.filtercount2 = f2.filtercount2' ;
END

IF @filter2 = 1
BEGIN
    @q = @q + 'INNER JOIN filtertable3 AS f3 ON u.filtercount3 = f3.filtercount3 ';
END

@q = 'INSERT INTO @userIds ' + @q;

EXEC sp_executesql @q;

----

SELECT
    u.*
FROM
    users AS u
    INNER JOIN @userIds AS f ON f.UserId = u.UserId

就地过滤

在此特定情况下,您 不需要 动态 SQL,您可以就地减少 @userIds 列表,如下所示:

DECLARE @filter1 bit = 0;
DECLARE @filter2 bit = 0;
DECLARE @filter3 bit = 0;

DECLARE @userIdsSoFar TABLE ( userId int PRIMARY KEY );

INSERT INTO @userIdsSoFar ( userId )
SELECT
    u.userId
FROM
    users AS u;

IF @filter1 = 1
BEGIN
    DELETE FROM @userIdsSoFar
    WHERE userId NOT IN (
        SELECT
            u.userId
        FROM
            users AS u
            INNER JOIN filtertable1 AS f1 ON u.filtercount1 = f1.filtercount1
    )
END

IF @filter2 = 1
BEGIN
    DELETE FROM @userIdsSoFar
    WHERE userId NOT IN (
        SELECT
            u.userId
        FROM
            users AS u
            INNER JOIN filtertable2 AS f2 ON u.filtercount2 = f2.filtercount2
    )
END

IF @filter3 = 1
BEGIN
    DELETE FROM @userIdsSoFar
    WHERE userId NOT IN (
        SELECT
            u.userId
        FROM
            users AS u
            INNER JOIN filtertable3 AS f3 ON u.filtercount3 = f3.filtercount3
    )
END

----

SELECT
    u.*
FROM
    users AS u
    INNER JOIN @userIdsSoFar AS f ON f.UserId = u.UserId