【问题标题】:SQL query - link to lookup with two fields at onceSQL 查询 - 一次链接到两个字段的查找
【发布时间】:2014-03-28 17:04:34
【问题描述】:

我想组合一个查询,将 THERAPY 表中的两个字段链接到我的查找表 REF_CODE;字段 PROT(可以为空)和字段 THER_TYPE(非空)。 REF_CODE 包含多个查找类别,由 CAT_ID 区分。我目前的查询如下所示:

SELECT THER_ID, r1.CODE_NAME, r2.CODE_NAME
FROM THER t
LEFT JOIN REF_CODE r1 ON t.PROT = r1.CODE
JOIN REF_CODE r2 ON t.THER_TYPE = r2.CODE
WHERE EVENT_ID = 1234
AND r1.CAT_ID = '1'
AND r2.CAT_ID = '2';

有两条 THERAPY 记录,其中 EVENT_ID = 1234。此查询仅返回 PROT 不为空的记录。根本不返回 PROT = null 的记录。

这是为什么?无论 PROT 是否为空,如何返回所有值?

【问题讨论】:

标签: sql oracle11g


【解决方案1】:

试试这个..

SELECT THER_ID, r1.CODE_NAME, r2.CODE_NAME
FROM THER t
LEFT JOIN REF_CODE r1 ON t.PROT = r1.CODE
and r1.CAT_ID = '1'
LEFT JOIN REF_CODE r2 ON t.THER_TYPE = r2.CODE
AND r2.CAT_ID = '2'
WHERE EVENT_ID = 1234;

以下是我对您的代码所做的更改:

  1. 您在 2nd JOIN 中使用REF_CODE 执行INNER JOIN,因此NULL 值会丢失结果。我把它改成了LEFT JOIN

  2. 您的第二个问题归结为将您的filter criteria 放置在ONWHERE 子句中。

第二点的解释:

INNER JOIN 中,您可以交替使用ONWHERE。底层逻辑不会改变,也不会影响执行计划。

OUTER JOINs 完全不同。正如您在您的案例中看到的那样,错误放置的过滤器可能会完全扭曲逻辑。

一个。 Filter Criteria in the WHERE Clause

SELECT * FROM A left join B
ON A.id=B.id
WHERE B.id=1

上面的查询将像INNER JOIN 一样运行,并将整个结果限制在B.id=1 所在的行(注意过滤器应用于LEFT JOIN 运算符右侧的表)

b. Filter Criteria in the ON Clause

SELECT * FROM A left join B
ON A.id=B.id
AND B.id=1

上述查询只会限制table B 的行,因为它们在LEFT JOIN 运算符中映射到table A。因此结果将包含table A所有行table B 列中的值,仅适用于符合条件B.id=1 的行

【讨论】:

  • 感谢 SoulTrain...但恐怕这仍然无法恢复 PROT = null 的记录。不知道我在这里错过了什么......!
  • 我想我知道是什么导致了您的情况。您可以尝试更新的代码,看看它是否有效。如果可行,我将解释这些更改。
  • 您的 Where 子句限制了结果集。检查更新的代码。
  • SoulTrain,太棒了!该查询似乎与我非常相似……只是 WHERE 子句位于不同的位置。您能否详细解释一下为什么会这样?
  • 当然...我会尽快解释。
【解决方案2】:

我创建了一个SQL Fiddle 查询来测试您的问题。请检查以验证它是否符合您的方案。

where 子句胜过左连接。将 Cat_ID 上的两个过滤器移动到连接子句中,如下所示:

SELECT THER_ID, r1.CODE_NAME, r2.CODE_NAME as Name2
FROM THER t
LEFT JOIN REF_CODE r1 ON t.PROT = r1.CODE AND r1.CAT_ID = '1'
JOIN REF_CODE r2 ON t.THER_TYPE = r2.CODE AND r2.CAT_ID = '2'
WHERE EVENT_ID = 1234;

另一种不太干净的方法是用isnull()包围与左连接相关的where子句部分,如下所示:

SELECT THER_ID, r1.CODE_NAME, r2.CODE_NAME as Name2
FROM THER t
LEFT JOIN REF_CODE r1 ON t.PROT = r1.CODE
JOIN REF_CODE r2 ON t.THER_TYPE = r2.CODE AND r2.CAT_ID = '2'
WHERE EVENT_ID = 1234
AND Coalesce(RTRIM(r1.CAT_ID),'1') = '1'

查看Left Outer Join Not Working 的类似答案。

补充:

如果@SoulTrain 的查询有效,那么Ther 中的行也必须与Ref_Code 中的行不匹配。在这种情况下,您确实需要使用两个左连接,但连接的顺序无关紧要。请参阅updated SQL Fiddle Example 以查看此查询的实际效果。这是最后一个查询。

SELECT THER_ID, r1.CODE_NAME, r2.CODE_NAME
FROM THER t
LEFT JOIN REF_CODE r1 ON t.PROT = r1.CODE and r1.Cat_ID = 1
LEFT JOIN REF_CODE r2 ON t.THER_TYPE = r2.CODE AND r2.CAT_ID = '2'
WHERE EVENT_ID = 1234;

【讨论】:

  • 嗨,亚伯拉罕。不幸的是,第一个示例不起作用 - 仍然排除了 PROT = null 的记录。我错过了什么?
  • 这个答案对stackoverflow.com/a/11096237/269123有帮助吗?他似乎唯一不同的是,他在连接子句上使用了括号。让我知道这是否有帮助,我会更新答案。
  • 我看不出为什么这个语句不应该得到想要的记录。将标准移到 on 子句可以解决问题。加入顺序在这里无关紧要。从 r1 到 r2 没有关系。 davemere,您的问题出在其他地方。从查询中删除 r2 时是否获得记录?还是在删除 r1 时得到它们?检查并考虑您的查询。
  • @davemere - 我添加了一个 SQL Fiddle 示例来模仿您描述的场景。请看链接。此外,我更正了第二个查询的语法以使用 Coalesce 而不是 ISNULL。这有帮助吗?
  • @ThorstenKettner 感谢您支持我。数据中一定有其他事情发生。
猜你喜欢
  • 2014-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-25
  • 2021-11-01
  • 2016-07-27
  • 2013-02-01
  • 1970-01-01
相关资源
最近更新 更多