【问题标题】:Left Join and conditional where not giving desired result?Left Join 和有条件的地方没有给出想要的结果?
【发布时间】:2016-02-09 08:49:32
【问题描述】:

我不知道如何提出这个问题。但请阅读说明。 我有两张表如下,

EntityProgress 表-

 EntityID       CurrentStateID
   101             1154
   201             1155
   301             1155

EnityApprovar 表

 EntityID        StateID        ActorID
   201             1154            8
   201             1154            9
   201             1155            8
   301             1154            8
   301             1154            9
   301             1155            9

现在我想要的是,如果我将ActorID=2 作为参数传递,那么它应该只返回一行,如下所示,因为我们在entityapprovar 表中没有任何匹配的enityID。

   EntityID      CurrentStateID     
    101              1154

但是如果我通过ActorID=9 那么它应该给我如下结果,

   EntityID      CurrentStateID
      301            1155

因为我们在 EntityApprover 表中有 entityID 匹配记录,并且对于该 entityID,我们有 currentstateID,并且我们有 actorid 为 9。

所以为了得到如下结果,

 SELECT
      E.EntityID,
      E.CurrentStateID
 FROM 
      EntityProgress E LEFT JOIN EntityApprover EP 
      ON E.EntityID = EP.EntityID AND E.CurrentStateID = EP.StateID
 WHERE
     -- some conditions
     AND ((ISNULL(EP.ActorID,0) )= 0 
           OR ((ISNULL(EP.ActorID,0))!= 0 AND EP.ActorID = @ActorID AND Ep.CurrentStateID = E.StateID))

但是当我通过 2 时,我得到了第一个结果,但是当我通过 9/8 时,我没有得到想要的结果。可能这很简单,但我坚持下去。我需要别人的观点给我不同的方式。 如果感到困惑,请随时发表评论。

【问题讨论】:

  • LEFT JOIN 时,将右侧表的条件放在 ON 子句中以获得真正的左连接行为。 (在 WHERE 中,您会得到内部连接结果。)
  • @jarlh 我没明白你的意思。你能解释一下或任何指针或链接吗?
  • 常规内连接意味着返回两个表中满足 ON 子句的行。左连接时,还会返回左侧表中不满足 ON 条件的行 - 此处为右侧表返回 NULL。如果您的 WHERE 子句在这些 NULL 值上包含“常规”条件,则 WHERE 将为 false 并且不返回任何内容,即您返回内部连接结果!但是,也许那些 ISNULL 会处理这个问题? (我不知道它们是如何工作的......)
  • @jarlh IT 返回我真正的左连接结果,它具有空值我正在使用该结果在有条件的地方得到我想要的东西。

标签: sql sql-server join where-clause


【解决方案1】:

这是我试图回答你的问题。

查询

DECLARE @ActorID int = 2

DECLARE @EntityProgress table
(
    EntityID int,
    CurrentStateID int
)

DECLARE @EnityApprovar table
(
    EntityID int,
    StateID int,
    ActorID int
)

INSERT into @EntityProgress
    values (101, 1154),
            (201, 1155),
            (301, 1155)


INSERT into @EnityApprovar
    VALUES (201, 1154, 8),
            (201, 1154, 9),
            (201, 1155, 8),
            (301, 1154, 8),
            (301, 1154, 9),
            (301, 1155, 9)

SELECT
    E.EntityID
    ,E.CurrentStateID
    ,EP.ActorID
FROM @EntityProgress E
LEFT JOIN @EnityApprovar EP
    ON E.EntityID = EP.EntityID
    AND E.CurrentStateID = EP.StateID
WHERE ((EP.ActorID IS NULL AND NOT EXISTS (SELECT 1 FROM @EnityApprovar WHERE ActorID = @ActorID))
        OR (EP.ActorID = @ActorID))

当您通过@ActorID = 2 时,它会给出以下输出。

EntityID    CurrentStateID  
101          1154         

当您通过@ActorID = 9 时,它会给出以下输出。

EntityID    CurrentStateID
301         1155    

这是您想要的。

【讨论】:

  • 只是一个小改动:请将 OP 的 ISNULL(EP.ActorID, 0) = 0 替换为简单的 EP.ActorID IS NULL :-)
【解决方案2】:

您必须在查询中包含 not exists,因为您在传入 9 时尝试排除的行没有信息来确定表中是否还有其他匹配的行。

SELECT
      E.EntityID,
      E.CurrentStateID
 FROM 
      EntityProgress E LEFT JOIN EnityApprovar EP 
      ON E.EntityID = EP.EntityID AND E.CurrentStateID = EP.StateID
 WHERE ((ISNULL(EP.ActorID,0) = 0 
   and   not exists(select 1 
                      from EnityApprovar ep2 
                     where ep2.ActorID = @ActorID ))
    OR  (ISNULL(EP.ActorID,0) != 0 
   AND   EP.ActorID = @ActorID  
   AND   E.CurrentStateID = Ep.StateID))

【讨论】:

  • 没有给出想要的结果。而且,如果第一个条件为真,那么该表中将没有该实体的记录,因此在这种情况下不存在可能不起作用
  • 实际上它确实给出了您在问题中所述的 2 和 9 作为输入的预期结果。
  • 接受的答案使用相同的逻辑,只是更简化了。没有理由投反对票。
【解决方案3】:

您的 ActorId 查找表应该是您查询的起点。如果您的架构中没有(我怀疑),您可以尝试将此作为起点。使用 T-SQL 语法:

    DECLARE @ActorID int
    SET @ActorID = 2

    SELECT * FROM
         (SELECT @ActorID AS EntityId) 
    Actor
    LEFT JOIN
    EntityApprover EA
    ON Actor.EntityId = EA.EntityId ...

您可以从那里提取其他列值。

【讨论】:

  • 这与所提出的问题有什么关系。
猜你喜欢
  • 2020-05-10
  • 1970-01-01
  • 2021-08-29
  • 1970-01-01
  • 2013-10-26
  • 2021-03-02
  • 2017-08-25
  • 2021-12-10
  • 2018-10-17
相关资源
最近更新 更多