AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 191568
Accepted
H. Pauwelyn
H. Pauwelyn
Asked: 2017-11-24 01:00:47 +0800 CST2017-11-24 01:00:47 +0800 CST 2017-11-24 01:00:47 +0800 CST

在 SQL Server 中忽略没有任何结果的连接

  • 772

情况

我正在进行 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 项目编号
sql-server join
  • 2 2 个回答
  • 1774 Views

2 个回答

  • Voted
  1. Best Answer
    Kent Chenery
    2017-11-24T02:20:38+08:002017-11-24T02:20:38+08:00

    我一直在阅读并重新阅读原始问题。我得到的是这样的:

    从 tblProjecten 返回记录,其中已提供的参数存在匹配项(不为空)。如果未提供参数(或为空),则假定该子表的所有匹配项

    实际上,您正在根据参数是否具有提供的值来动态连接。

    为此,您可以使用:

    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 p.* 
    from tblProjecten p 
    where p.naam like '%' + @trefwoord + '%'
    and ( 
            @themaid is null
        or exists(select 1 from tblProjectenThema pt where p.projectId = pt.projectId and pt.themaId = @themaid)
    )
    and (
            @studiegebiedid is null
        or exists(select 1 from tblProjectenStudiegebieden ps where p.projectId = ps.projectid and ps.studiegebiedid = @studiegebiedid
    )
    and (
            @studiegebiedid is null
        or exists(select 1 from tblProjectenOpleidingsType pot where p.projectId = pot.projectID and ps.studiegebiedid = @studiegebiedid
    )
    and (
            @opleidingdtypeid is null
        or exists(select 1 from tblProjectendoelgroep pd where p.projectId = pd.projectId and pd.doelgroepId = @doelgroepid
    )
    and (
            @organisatorid is null
        or exists(select 1 from tblProjectenOrganisator po where p.projectId = po.projectId and po.organisatorId  = @organisatorid
    )
    and (
            @regioid is null
        or exists(select 1 from tblProjectenRegio pr where p.projectId = pr.projectId and pr.regioId = @regioid
    )
    

    我已经改变了一些事情。我们不是在做连接,而是在做EXISTS一个相关的子查询。

    每个评价如下:

    • 如果 @parameter 为 null 返回 true
    • 或者...如果@parameter 不为空,则检查子表上是否存在该@parameter 的匹配记录。如果有,返回true

    通过这样做,我们的连接实际上变成了可选的(取决于我们是否有参数值)。

    如果我的初衷是正确的,那么一个简单的假设是您可能想要使用内部连接,例如:

    select distinct p.* 
    from tblProjecten p
    inner join tblProjectenThema pt on p.projectId = pt.projectId
    ...etc...
    where p.naam like '%' + @trefwoord + '%'
    and (pt.themaId = coalesce(@themaid))
    

    您不能这样做的原因是 tblProjectenThema 可能为空,因此无法匹配任何行。你总是会得到一个空的结果。

    替代方法

    由于需要考虑更多表,因此上述查询将开始受到性能影响。您可以OPTION(RECOMPILE)针对查询使用。因为您需要可选的动态参数,所以也可以使用动态 SQL 来提供服务。

    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 @trefwoord = '%' + @trefwoord + '%';
    declare @sql nvarchar(max);
    
    select @sql = '
    select p.* 
    from tblProjecten p 
    where p.naam like @trefwoord
    '
    
    if @themaid is not null
    select @sql += 'and exists(select 1 from tblProjectenThema pt where p.projectId = pt.projectId and pt.themaId = @themaid)'
    
    if @studiegebiedid is not null 
    select @sql += 'and exists(select 1 from tblProjectenStudiegebieden ps where p.projectId = ps.projectid and ps.studiegebiedid = @studiegebiedid)'
    
    if @opleidingdtypeid is not null
    select @sql += 'and exists(select 1 from tblProjectendoelgroep pd where p.projectId = pd.projectId and pd.doelgroepId = @doelgroepid)'
    
    if @organisatorid is not null
    select @sql += 'and exists(select 1 from tblProjectenOrganisator po where p.projectId = po.projectId and po.organisatorId  = @organisatorid)'
    
    if @regioid is not null
    select @sql = +='and exists(select 1 from tblProjectenRegio pr where p.projectId = pr.projectId and pr.regioId = @regioid)'
    
    exec sp_executesql 
        @stmt = @sql
        ,@params = N'@trefwoord nvarchar(max), @themaid int, @studiegebiedid int, @opleidingdtypeid int, @doelgroepid int, @organisatorid int, @regioid int'
        ,@trefwoord = @trefwoord
        ,@themaid = @themaid
        ,@studiegebiedid = @studiegebiedid
        ,@opleidingdtypeid = @opleidingdtypeid
        ,@doelgroepid = @doelgroepid
        ,@organisatorid = @organisatorid
        ,@regioid = @regioid
        ;
    
    • 4
  2. ypercubeᵀᴹ
    2017-11-24T01:57:44+08:002017-11-24T01:57:44+08:00

    我认为您使用的LEFT连接不正确。现在查询的方式是,子句中涉及每个表的列WHERE,连接有效地充当INNER连接,而不是LEFT连接。正如@Kent 在评论中解释的那样:

    当条件在连接语句(ON部分)中时,限制在连接之前应用。当它在 中时WHERE,它会在连接发生后应用(因此,如果您对正确的表设置条件,则连接有效地成为内部连接)。

    现在,我不确定到底想要什么。


    案例 A(可能不是想要的)。如果您还想从其他表中获取信息,那么您应该:

    • 将条件从WHERE相应的ON条件移动
    • 摆脱COALESCE()功能
    • (奖金)摆脱DISTINCT

    查询将类似于:

    select p.*
        -- pt.*, ps.*, ... 
    from tblProjecten p 
        left join tblProjectenThema pt
            on  p.projectId = pt.projectId
            and pt.themaId = @themaid 
        left join tblProjectenStudiegebieden ps
            on  p.projectId = ps.projectid
            and ps.studiegebiedid = @studiegebiedid
        left join tblProjectenOpleidingsType pot
            on  p.projectId = pot.projectID
            and pot.opleidingsID = @opleidingdtypeid
        left join tblProjectendoelgroep pd
            on  p.projectId = pd.projectId
            and pd.doelgroepId = @doelgroepid
        left join tblProjectenOrganisator po
            on  p.projectId = po.projectId
            and po.organisatorId = @organisatorid
        left join tblProjectenRegio pr
            on  p.projectId = pr.projectId
            and pr.regioId = @regioid
    where  
          p.naam like '%' + @trefwoord + '%'
     ;
    

    案例B(我认为是这样)。如果你想要“可选参数”,即当参数为空时不限制结果,那么你应该:

    • 将连接和WHERE条件转换为EXISTS子查询
    • 摆脱COALESCE()功能并使用OR @parameter IS NULL)
    • (奖金)摆脱DISTINCT

    查询将类似于:

    select p.*
    from tblProjecten p 
    where 
          p.naam like '%' + @trefwoord + '%'
      and ( @themaid is null
          or exists
              ( select * from tblProjectenThema pt
                where p.projectId = pt.projectId
                  and pt.themaId = @themaid
              )
          ) 
      and ( @studiegebiedid is null
          or exists
              ( select * from tblProjectenStudiegebieden ps
                where p.projectId = ps.projectId
                  and ps.studiegebiedid = @studiegebiedid
              )
          ) 
      -- and ...
     ;
    
    • 1

相关问题

  • INNER JOIN 和 OUTER JOIN 有什么区别?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • JOIN 语句的输出是什么样的?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve