如果存在匹配值,则从另一个表中检索数据 - 否则基于第一个连接条件返回

Posted

技术标签:

【中文标题】如果存在匹配值,则从另一个表中检索数据 - 否则基于第一个连接条件返回【英文标题】:Retrieve data from another table if there is a matching value - else return based on first join condition 【发布时间】:2021-12-24 01:01:23 【问题描述】:

我正在尝试通过将两个表连接到主列来从它们中获取数据。但是,如果右表中有第二列和第三列,则考虑它们并返回其对应的列。

LEFT_TAB
USER  PRIMARY  SECONDARY  TERTIARY
1       A1       B1        (null)
2       X1     (null)      (null)

RIGHT_TAB
PRIMARY SECONDARY TERTIARY INDICATOR
  A1       B1      (null)    I1
  A1     (null)    (null)    I2
  X1     (null)    (null)    I3

Expected Output:
USER  PRIMARY  SECONDARY  TERTIARY INDICATOR
  1     A1         B1      (null)    I1
  2     X1       (null)    (null)    I3

我已经在 PRIMARY 上尝试了 INNER JOIN,因为这是主列,而 SECONDARY 和 TERTIARY 是可选的。如果它们可用,那么我们使用它们和相应的行(LEFT OUTER JOIN),但它返回重复。

select lft.user_id,lft.primary,lft.secondary,lft.tertiary,rit.indication
from left_tab lft
INNER JOIN right_tab rit ON left.primary = rit.primary
LEFT JOIN right_tab rite ON
(left.secondary = rite.secondary OR left.tertiary = rite.tertiary) ---(join that's bringing dups)
;

OUTPUT:
USER  PRIMARY  SECONDARY  TERTIARY INDICATOR
  1     A1         B1      (null)    I1
  1     A1         B1      (null)    I2 --duplicate
  2     X1       (null)    (null)    I3

【问题讨论】:

我会避免 left 作为表别名,因为 left inner join 看起来很奇怪。 (另外,似乎 Oracle 或多或少是单独没有保留它的,en.wikipedia.org/wiki/SQL_reserved_words.) 另外你不能(或者至少不应该)为同一张表的不同实例使用相同的别名——你已经使用了两次“rit” 根据上述cmets更新。 当然,只要您在RIGHT_TAB 中有两行带有A1 的行,它就会返回重复项。 Oracle 应该如何知道您的期望 或为什么 认为某一行优于另一行?更有趣的案例是A1 null C1 I3A1 B2 C2 I4 中的额外行 【参考方案1】:

从 Oracle 12 开始,您可以使用:

SELECT l.user_id,
       l.primary,
       l.secondary,
       l.tertiary,
       r.indicator
from   left_tab l
       CROSS JOIN LATERAL (
         SELECT r.*
         FROM   right_tab r
         WHERE  l.primary = r.primary
         AND    (l.secondary = r.secondary OR r.secondary IS NULL)
         AND    (l.tertiary = r.tertiary OR r.tertiary IS NULL)
         ORDER BY (CASE WHEN r.secondary IS NOT NULL THEN 1 ELSE 0 END
                  + CASE WHEN r.tertiary  IS NOT NULL THEN 1 ELSE 0 END) DESC
         FETCH FIRST ROW ONLY
       ) r;

其中,对于样本数据:

CREATE TABLE LEFT_TAB (USER_ID, PRIMARY, SECONDARY, TERTIARY) AS
SELECT 1, 'A1', 'B1', CAST(null AS VARCHAR2(2)) FROM DUAL UNION ALL
SELECT 2, 'X1', null, null FROM DUAL UNION ALL
SELECT 3, 'Y1', 'Y2', 'Y3' FROM DUAL;

CREATE TABLE RIGHT_TAB (PRIMARY, SECONDARY, TERTIARY, INDICATOR) AS
SELECT 'A1', 'B1', CAST(null AS VARCHAR2(2)), 'I1' FROM DUAL UNION ALL
SELECT 'A1', null, null, 'I2' FROM DUAL UNION ALL
SELECT 'X1', null, null, 'I3' FROM DUAL UNION ALL
SELECT 'Y1', null, 'Y3', 'I4' FROM DUAL UNION ALL
SELECT 'Y1', 'Y2', 'Y3', 'I5' FROM DUAL UNION ALL
SELECT 'Y1', 'Y2', null, 'I6' FROM DUAL;

输出:

USER_ID PRIMARY SECONDARY TERTIARY INDICATOR
1 A1 B1 I1
2 X1 I3
3 Y1 Y2 Y3 I5

db小提琴here

【讨论】:

以上是关于如果存在匹配值,则从另一个表中检索数据 - 否则基于第一个连接条件返回的主要内容,如果未能解决你的问题,请参考以下文章

如果存在则从表中选择,否则从oracle中的另一个表中选择

如果 Redshift 中存在表,则从表中删除行,否则忽略删除

Redshift:如果值存在,则从表 1 中获取值,否则从表 2 中提取

MYSQL从另一个表更新数据,如果存在,否则插入[重复]

如果值存在于多个表中,则从表中获取结果

WordPress 和 SQL - 如果列值不存在,则从另一个表更新和插入