SQL LEFT 外连接仅包含右侧的一些行?

发布于 2024-08-03 04:45:21 字数 610 浏览 5 评论 0原文

我有两个表 TABLE_ATABLE_B,其连接列作为员工编号 EMPNO

我想做一个正常的左外连接。但是,TABLE_B 具有某些被软删除的记录 (status='D'),我希望将这些记录包括在内。只是为了澄清,TABLE_B 可能有活动记录(状态 = null/a/anything)以及已删除的记录,在这种情况下,我不希望该员工出现在我的结果中。但是,如果 TABLE_B 中只有已删除的员工记录,我希望该员工包含在结果中。我希望我能明确我的要求。 (我可以做一个冗长的 qrslt 之类的事情并得到我想要的东西,但我认为必须有一种更优化的方法来使用连接语法来做到这一点)。将不胜感激任何建议(即使没有加入)。他的新手正在尝试以下查询,但没有得到所需的结果:

SELECT TABLE_A.EMPNO
FROM   TABLE_A
LEFT OUTER JOIN TABLE_B ON TABLE_A.EMPNO = TABLE_B.EMPNO AND TABLE_B.STATUS<>'D' 

非常感谢任何帮助。

I have two tables TABLE_A and TABLE_B having the joined column as the employee number EMPNO.

I want to do a normal left outer join. However, TABLE_B has certain records that are soft-deleted (status='D'), I want these to be included. Just to clarify, TABLE_B could have active records (status= null/a/anything) as well as deleted records, in this case i don't want that employee in my result. If however there are only deleted records of the employee in TABLE_B i want the employee to be included in the result.I hope i'm making my requirement clear. (I could do a lengthy qrslt kind of thingy and get what I want, but I figure there has to be a more optimized way of doing this using the join syntax). Would appreciate any suggestions(even without the join). His newbness is trying the following query without the desired result:

SELECT TABLE_A.EMPNO
FROM   TABLE_A
LEFT OUTER JOIN TABLE_B ON TABLE_A.EMPNO = TABLE_B.EMPNO AND TABLE_B.STATUS<>'D' 

Much appreciate any help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

空气里的味道 2024-08-10 04:45:21

只是为了澄清 - TABLE_A 中的所有记录都应该出现,除非表 B 中的行的雕像除了而不是“D”?

您将需要 B 上至少一个非空列(我将使用“B.ID”作为示例,这种方法应该有效):

SELECT TABLE_A.EMPNO
FROM TABLE_A
LEFT OUTER JOIN TABLE_B ON
  (TABLE_A.EMPNO = TABLE_B.EMPNO)
  AND (TABLE_B.STATUS <> 'D' OR TABLE_B.STATUS IS NULL)
WHERE
  TABLE_B.ID IS NULL

也就是说,反转您可能想到的逻辑 - 仅在以下位置加入到 TABLE_B:您有一些行排除 TABLE_A 条目,然后在末尾使用 IS NULL 来排除这些行。这意味着仅包含那些不匹配的内容(TABLE_B 中没有行或仅包含“D”行的内容)。

另一种选择可能是

SELECT TABLE_A.EMPNO
FROM TABLE_A
WHERE NOT EXISTS (
  SELECT * FROM TABLE_B 
  WHERE TABLE_B.EMPNO = TABLE_A.EMPNO
  AND (TABLE_B.STATUS <> 'D' OR TABLE_B.STATUS IS NULL)
)

Just to clarify -- all records from TABLE_A should appear, unless there are rows in table B with statues other than 'D'?

You'll need at least one non-null column on B (I'll use 'B.ID' as an example, and this approach should work):

SELECT TABLE_A.EMPNO
FROM TABLE_A
LEFT OUTER JOIN TABLE_B ON
  (TABLE_A.EMPNO = TABLE_B.EMPNO)
  AND (TABLE_B.STATUS <> 'D' OR TABLE_B.STATUS IS NULL)
WHERE
  TABLE_B.ID IS NULL

That is, reverse the logic you might think -- join onto TABLE_B only where you have rows that would exclude TABLE_A entries, and then use the IS NULL at the end to exclude those. This means that only those which didn't match (those with no row in TABLE_B, or with only 'D' rows) get included.

An alternative might be

SELECT TABLE_A.EMPNO
FROM TABLE_A
WHERE NOT EXISTS (
  SELECT * FROM TABLE_B 
  WHERE TABLE_B.EMPNO = TABLE_A.EMPNO
  AND (TABLE_B.STATUS <> 'D' OR TABLE_B.STATUS IS NULL)
)
哎呦我呸! 2024-08-10 04:45:21

以下查询将获取未删除的员工记录,或仅该员工已删除的记录。

select
    a.*
from
    table_a a
    left join table_b b on
        a.empno = b.empno
where
    b.status <> 'D'
    or (b.status = 'D' and 
        (select count(distinct status) from table_b where empno = a.empno) = 1)

这是用 ANSI SQL 编写的,但如果我知道你的 RDBMS,我可以给出一个更具体的解决方案,可能会更优雅一些。

The following query will get you the employee records that aren't deleted, or only the employ only has deleted records.

select
    a.*
from
    table_a a
    left join table_b b on
        a.empno = b.empno
where
    b.status <> 'D'
    or (b.status = 'D' and 
        (select count(distinct status) from table_b where empno = a.empno) = 1)

This is in ANSI SQL, but if I knew your RDBMS, I could give a more specific solution that may be a bit more elegant.

吻风 2024-08-10 04:45:21

啊粗鲁,这显然有效>><

SELECT TABLE_A.EMPNO
FROM   TABLE_A
LEFT OUTER JOIN TABLE_B ON TABLE_A.EMPNO = TABLE_B.EMPNO 
where TABLE_B.STATUS<>'D'

如果你们有任何额外的信息可以补充,请随意。

更新:
一段时间后看到这个问题,我想我会添加更多有用的信息:此链接有关于 ANSI 语法的良好信息 - http://www.oracle-base.com/articles/9i/ANSIISOSQLSupport.php

特别是链接页面中的这一部分内容丰富:

可以将额外的过滤条件添加到连接中,以使用 AND 形成复杂的连接。当需要过滤条件来限制外部联接时,这些通常是必要的。如果这些过滤条件放置在 WHERE 子句中,并且外连接为过滤列返回 NULL 值,则该行将被丢弃。如果将过滤条件编码为连接的一部分,则可以避免这种情况。

ah crud, this apparently works ><

SELECT TABLE_A.EMPNO
FROM   TABLE_A
LEFT OUTER JOIN TABLE_B ON TABLE_A.EMPNO = TABLE_B.EMPNO 
where TABLE_B.STATUS<>'D'

If you guys have any extra info to chime in with though, please feel free.

UPDATE:
Saw this question after sometime and thought i'll add more helpful info: This link has good info regarding ANSI syntax - http://www.oracle-base.com/articles/9i/ANSIISOSQLSupport.php

In particular this part from the linked page is informative:

Extra filter conditions can be added to the join to using AND to form a complex join. These are often necessary when filter conditions are required to restrict an outer join. If these filter conditions are placed in the WHERE clause and the outer join returns a NULL value for the filter column the row would be thrown away. if the filter condition is coded as part of the join the situation can be avoided.

那小子欠揍 2024-08-10 04:45:21
SELECT A.*, B.*
FROM
   Table_A A
   INNER JOIN Table_B B
      ON A.EmpNo = B.EmpNo
WHERE
   NOT EXISTS (
      SELECT *
      FROM Table_B X
      WHERE
          A.EmpNo = X.EmpNo
          AND X.Status <> 'D'
    )

我认为这可以解决问题。不需要左联接,因为您只想包含所有(和至少一个)已删除行的员工。

SELECT A.*, B.*
FROM
   Table_A A
   INNER JOIN Table_B B
      ON A.EmpNo = B.EmpNo
WHERE
   NOT EXISTS (
      SELECT *
      FROM Table_B X
      WHERE
          A.EmpNo = X.EmpNo
          AND X.Status <> 'D'
    )

I think this does the trick. The left join is not needed because you only want to include employees with all (and at least one) deleted rows.

嘿咻 2024-08-10 04:45:21

我是这样理解这个问题的。您只需包含满足以下任一条件的员工:

  • 员工在 TABLE_B 中仅具有(软)删除的行;

  • 员工在 TABLE_B 中仅拥有未删除的行;

  • 员工在 TABLE_B 中根本没有行。

换句话说,如果某个员工在 TABLE_B 中同时拥有已删除和未删除的行,则忽略该员工,否则将其包括在内。

这就是我认为可以解决的方法:

SELECT DISTINCT a.EMPNO
FROM TABLE_A a
  LEFT JOIN TABLE_B b1 ON a.EMPNO = b1.EMPNO
  LEFT JOIN TABLE_B b2 ON b1.EMPNO = b2.EMPNO
    AND (b1.STATUS = 'D' AND (b2.STATUS <> 'D' OR b2 IS NULL) OR
         b2.STATUS = 'D' AND (b1.STATUS <> 'D' OR b1 IS NULL))
WHERE b2.EMPNO /* or whatever non-nullable column there is */ IS NULL

不过,或者,您可以使用分组:

SELECT a.EMPNO
FROM TABLE_A a
  LEFT JOIN TABLE_B b ON a.EMPNO = b1.EMPNO
GROUP BY a.EMPNO
HAVING 0 IN (COUNT(CASE b.STATUS WHEN 'D' THEN 1 ELSE NULL END),
             COUNT(CASE b.STATUS WHEN 'D' THEN NULL ELSE 1 END))

This is how I understand the question. You need to include only those employees for which either of the following is true:

  • an employee has only (soft-)deleted rows in TABLE_B;

  • an employee has only non-deleted rows in TABLE_B;

  • an employee has no rows in TABLE_B at all.

In other words, if an employee has both deleted and non-deleted rows in TABLE_B, omit that employee, otherwise include them.

This is how I think it could be solved:

SELECT DISTINCT a.EMPNO
FROM TABLE_A a
  LEFT JOIN TABLE_B b1 ON a.EMPNO = b1.EMPNO
  LEFT JOIN TABLE_B b2 ON b1.EMPNO = b2.EMPNO
    AND (b1.STATUS = 'D' AND (b2.STATUS <> 'D' OR b2 IS NULL) OR
         b2.STATUS = 'D' AND (b1.STATUS <> 'D' OR b1 IS NULL))
WHERE b2.EMPNO /* or whatever non-nullable column there is */ IS NULL

Alternatively, though, you could use grouping:

SELECT a.EMPNO
FROM TABLE_A a
  LEFT JOIN TABLE_B b ON a.EMPNO = b1.EMPNO
GROUP BY a.EMPNO
HAVING 0 IN (COUNT(CASE b.STATUS WHEN 'D' THEN 1 ELSE NULL END),
             COUNT(CASE b.STATUS WHEN 'D' THEN NULL ELSE 1 END))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文