能否根据Oracle SQL中的结果限制左联接的结果?

能否根据Oracle SQL中的结果限制左联接的结果?,sql,oracle11g,left-join,Sql,Oracle11g,Left Join,要将表A连接到表B,以获得表B中特定类型的行。 如果这些类型都不在表B中,则返回表A中的行,表B中的列为null。如果还返回了类型为的行,则不希望返回null行 我尝试使用秩推断方法: SELECT DISTINCT A.a_id, A.emp, B.b_id, B.id_for_c, C.type, C.rnk FROM A JOIN B on B.b_id = A.a_id Left JOIN ( SELECT b_id, C.type, id_for_c, C.c_id,

要将表A连接到表B,以获得表B中特定类型的行。 如果这些类型都不在表B中,则返回表A中的行,表B中的列为null。如果还返回了类型为的行,则不希望返回null行

我尝试使用秩推断方法:

SELECT DISTINCT
     A.a_id, A.emp, B.b_id, B.id_for_c, C.type, C.rnk
 FROM A
 JOIN B on B.b_id = A.a_id
 Left JOIN ( SELECT b_id, C.type, id_for_c, C.c_id, rnk
      FROM ( SELECT B.b_id, B.id_for_c, C.type, C.c_id,
            RANK() OVER (PARTITION BY B.b_id
            ORDER BY CASE WHEN C.type IS NOT NULL THEN 1 ELSE 2 END) AS rnk
            FROM B
            LEFT OUTER JOIN C
            ON C.c_id = B.id_for_c
            AND (C.type=1 or C.type=2)
          ) C

      ORDER BY b_id, C.type, rnk) C
on C.c_id = B.id_for_c;   


Data:

create table a (a_id number, emp number);
create table b (b_id number, id_for_c number);
create table c (c_id number, type number);

insert into a values (101, 1000);
insert into a values (102, 2000);
insert into a values (103, 3000);
insert into a values (104, 4000);

insert into b values (101, 25);
insert into b values (101, 75);
insert into b values (102, 50);
insert into b values (103, 75);
insert into b values (104, 25);
insert into b values (104, 75);

insert into c values (25, 1);
insert into c values (50, 2);
insert into c values (75, 3);
尝试:

说明:


(现有查询是with子句中的块)。我使用exists子查询来消除您不想要的内容。

您可以使用分析的
rank()
函数来支持空值的非空B值:

SELECT id, type
FROM (
  SELECT A.id, B.type,
    RANK() OVER (PARTITION BY A.id
      ORDER BY CASE WHEN B.type IS NOT NULL THEN 1 ELSE 2 END) AS rnk
  FROM A
  LEFT OUTER JOIN B
  ON B.id = A.id_for_b
  AND (B.type=1 or b.type=2)
)
WHERE rnk = 1
ORDER BY id, type;

内部查询添加一个排名列,该列为每个匹配结果提供一个1或2的排名(这两个值)。外部查询然后删除那些排名为2的结果;如果还存在非空值,则这些结果将仅为空值

正如Brian的回答一样,这只会击中你真正的桌子一次

如果任何A都有多个非空值,即类型1和类型2(或者没有非空值,但有多个空值),那么它们都会显示出来;我不确定这两种情况是否适用于您

对于您的三个表变体,我认为您不想加入子查询;当然不想回到您已经使用过的表。希望这能得到您想要的结果:

SELECT a_id, b_id, id_for_c, type, c_id
FROM (
  SELECT A.a_id, A.emp, B.b_id, B.id_for_c, C.type, C.c_id,
    RANK() OVER (PARTITION BY B.b_id
    ORDER BY CASE WHEN C.type IS NOT NULL THEN 1 ELSE 2 END) AS rnk
  FROM A
  LEFT OUTER JOIN B
  ON B.b_id = A.a_id
  LEFT OUTER JOIN C
  ON C.c_id = B.id_for_c
  AND (C.type=1 or C.type=2)
)
WHERE rnk = 1
ORDER BY a_id, b_id;

| A_ID | B_ID | ID_FOR_C |   TYPE |   C_ID |
|------|------|----------|--------|--------|
|  101 |  101 |       25 |      1 |     25 |
|  102 |  102 |       50 |      2 |     50 |
|  103 |  103 |       75 | (null) | (null) |
|  104 |  104 |       25 |      1 |     25 |

.

谢谢Brian。这也帮助了Alex谢谢你。Alex,我们确实有多个空值场景Alex,在试图在代码中实现这种方法时,所有空值都被列为1,即使存在非空值。@user3807647-,所以不确定有什么不同。你能显示一些数据,或者设置一个小提琴来显示问题吗?排名在inn中er查询,对我来说。问题在于如何将其连接回相同的基表。因此,现在有三个表要连接在一起。您希望从这些数据中看到什么结果?您嵌套的
C
没有任何作用,其中的
order by
对结果没有影响,因此不确定您要用它做什么。
SELECT a_id, b_id, id_for_c, type, c_id
FROM (
  SELECT A.a_id, A.emp, B.b_id, B.id_for_c, C.type, C.c_id,
    RANK() OVER (PARTITION BY B.b_id
    ORDER BY CASE WHEN C.type IS NOT NULL THEN 1 ELSE 2 END) AS rnk
  FROM A
  LEFT OUTER JOIN B
  ON B.b_id = A.a_id
  LEFT OUTER JOIN C
  ON C.c_id = B.id_for_c
  AND (C.type=1 or C.type=2)
)
WHERE rnk = 1
ORDER BY a_id, b_id;

| A_ID | B_ID | ID_FOR_C |   TYPE |   C_ID |
|------|------|----------|--------|--------|
|  101 |  101 |       25 |      1 |     25 |
|  102 |  102 |       50 |      2 |     50 |
|  103 |  103 |       75 | (null) | (null) |
|  104 |  104 |       25 |      1 |     25 |