条件加入 SQL 服务器存储过程
Conditional Join in SQL Server stored procedure
我有 3 个变量 filter1
、filter2
、filter3
,它们基于用户输入。其值为 1 或 0。
表格是
userlist
(用户 ID、名称、filtercount1、filtercount2、filtercount3)`
filtertable1
(id, filtercount1)
filtertable2
(id, filtercount1)
filtertable3
(id, filtercount1)
现在我想编写一个查询:
- if filter1 = 1 then, inner join user to filtertable1
- if filter2 = 1 then, inner join user to filtertable2
- if filter3 = 1 then, innerjoin user to filtertable3.
现在如何有条件地将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
我有 3 个变量 filter1
、filter2
、filter3
,它们基于用户输入。其值为 1 或 0。
表格是
userlist
(用户 ID、名称、filtercount1、filtercount2、filtercount3)`filtertable1
(id, filtercount1)filtertable2
(id, filtercount1)filtertable3
(id, filtercount1)
现在我想编写一个查询:
- if filter1 = 1 then, inner join user to filtertable1
- if filter2 = 1 then, inner join user to filtertable2
- if filter3 = 1 then, innerjoin user to filtertable3.
现在如何有条件地将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