情况
我正在进行 SQL 服务器查询以过滤项目表( tblProjecten
)中的数据。该表与其他表(如 region ( tblProjectenRegio
)、 organization ( tblProjectenOrganisatie
)等)有很多多对多的关系。
我声明的所有参数都是可选的。我发现用来coalesce
做这个。如果我不使用我的查询中的联接,它工作正常,你得到了我首先使用的查询:
declare @themaid int = 1 ; -- themeID
declare @trefwoord nvarchar(max) = '' ; -- search query
select distinct p.*
from tblProjecten p left join tblProjectenThema pt on p.projectId = pt.projectId
where pt.themaId = coalesce(@themaid, pt.themaId) and
p.naam like '%' + @trefwoord + '%' ;
在我对不同声明的结果下方(另请参阅下面的数据):
@themaid | @trefwood | 结果 | 正确的 |
---|---|---|---|
1 | 166 | 好的 | |
1 | 空调 | 166 | 好的 |
无效的 | 空调 | 166 | 好的 |
无效的 | 166、185、415 | 好的 |
这工作正常,但如果我添加其他条件参数,如下面的查询。我得到了完全不同的结果。
declare @themaid int = 1 ;
declare @studiegebiedid int = null ;
declare @opleidingdtypeid int = null ;
declare @doelgroepid int = null ;
declare @organisatorid int = null ;
declare @regioid int = null ;
declare @trefwoord nvarchar(max) = '' ;
select distinct p.*
from tblProjecten p left join tblProjectenThema pt on p.projectId = pt.projectId
left join tblProjectenStudiegebieden ps on p.projectId = ps.projectid
left join tblProjectenOpleidingsType pot on p.projectId = pot.projectID
left join tblProjectendoelgroep pd on p.projectId = pd.projectId
left join tblProjectenOrganisator po on p.projectId = po.projectId
left join tblProjectenRegio pr on p.projectId = pr.projectId
where pt.themaId = coalesce(@themaid, pt.themaId) and
ps.studiegebiedid = coalesce(@studiegebiedid, ps.studiegebiedid) and
pot.opleidingsID = coalesce(@opleidingdtypeid, pot.opleidingsID) and
pd.doelgroepId = coalesce(@doelgroepid, pd.doelgroepid) and
po.organisatorId = coalesce(@organisatorid, po.organisatorId) and
pr.regioId = coalesce(@regioid, pr.regioId) and
p.naam like '%' + @trefwoord + '%' ;
以下是结果(其他声明是null
):
@themaid | @trefwood | 结果 | 正确的 | 一定是 |
---|---|---|---|---|
1 | 不好 | 166 | ||
1 | 空调 | 不好 | 166 | |
无效的 | 空调 | 不好 | 166 | |
无效的 | 不好 | 166、185、415 |
这是因为其他表中没有任何数据。(见下面的数据)
问题
我现在的问题是我可以忽略没有任何结果的连接以使最后一个查询正常工作吗?
我也尝试使用内连接和右连接,但给出相同的结果。
数据
这里有一些数据:
tblProjecten
:
项目编号 | 纳姆 |
---|---|
166 | 证明 AIRCO 项目 |
185 | Autoweb 电子学习 |
415 | 布恩豪特 |
tblProjectenThema
:
主题 | 项目编号 |
---|---|
1 | 166 |
2 | 166 |
2 | 415 |
3 | 415 |
6 | 185 |
tblProjectendoelgroep
:
doelgroepId | 项目编号 |
---|
我一直在阅读并重新阅读原始问题。我得到的是这样的:
从 tblProjecten 返回记录,其中已提供的参数存在匹配项(不为空)。如果未提供参数(或为空),则假定该子表的所有匹配项
实际上,您正在根据参数是否具有提供的值来动态连接。
为此,您可以使用:
我已经改变了一些事情。我们不是在做连接,而是在做
EXISTS
一个相关的子查询。每个评价如下:
通过这样做,我们的连接实际上变成了可选的(取决于我们是否有参数值)。
如果我的初衷是正确的,那么一个简单的假设是您可能想要使用内部连接,例如:
您不能这样做的原因是 tblProjectenThema 可能为空,因此无法匹配任何行。你总是会得到一个空的结果。
替代方法
由于需要考虑更多表,因此上述查询将开始受到性能影响。您可以
OPTION(RECOMPILE)
针对查询使用。因为您需要可选的动态参数,所以也可以使用动态 SQL 来提供服务。我认为您使用的
LEFT
连接不正确。现在查询的方式是,子句中涉及每个表的列WHERE
,连接有效地充当INNER
连接,而不是LEFT
连接。正如@Kent 在评论中解释的那样:当条件在连接语句(
ON
部分)中时,限制在连接之前应用。当它在 中时WHERE
,它会在连接发生后应用(因此,如果您对正确的表设置条件,则连接有效地成为内部连接)。现在,我不确定到底想要什么。
案例 A(可能不是想要的)。如果您还想从其他表中获取信息,那么您应该:
WHERE
相应的ON
条件移动COALESCE()
功能DISTINCT
查询将类似于:
案例B(我认为是这样)。如果你想要“可选参数”,即当参数为空时不限制结果,那么你应该:
WHERE
条件转换为EXISTS
子查询COALESCE()
功能并使用OR @parameter IS NULL
)DISTINCT
查询将类似于: