将具有多列值的表连接到具有多行值的表

Posted

技术标签:

【中文标题】将具有多列值的表连接到具有多行值的表【英文标题】:Join table with values in multiple columns to table with values in multiple rows 【发布时间】:2021-11-24 03:06:32 【问题描述】:

我有两张桌子。

REJECT_REASONS

Account_No Resn_Id1 Resn_Id2 Resn_Id3 Resn_Id4
100 0001 0005 0006 0104
101 0005 0006 0104
102 0001 0006
103
104 0001

REASON_DESC

Resn_Id Resn_Desc
0001 Bad Account
0005 Duplicate Account
0006 Invalid Data
0104 Invalid address

我想在 resn_id1、resn_id2、resn_id3 和 resn_id4 的每一列上将 REJECT_REASONS 和 REASON_DESC 与 resn_id 连接起来,并在结果中得到 resn_desc。

我尝试了以下查询:

select r.account_no,r.resn_id1,rd1.resn_desc,
r.resn_id2,rd2.resn_desc,
r.resn_id3,rd3.resn_desc,
r.resn_id4,rd4.resn_desc
from reject_reasons r, reason_desc rd1, reason_desc rd2, reason_desc rd3, reason_desc rd4
where r.resn_id1=rd1.resn_id(+)
and  r.resn_id2=rd2.resn_id(+)
and r.resn_id3=rd3.resn_id(+)
and r.resn_id4=rd4.resn_id(+)
;

期望的输出: |帐号_no | Resn_Id1 | Resn_desc1 | Resn_Id2 | Resn_desc2 | Resn_Id3 | Resn_desc3 | Resn_Id4 | Resn_desc4 |

如果有办法简化查询,请告诉我。

【问题讨论】:

使用标准 JOIN 语法使查询可读。无论如何,您需要 4 个连接。 显示理想的输出 and: 如果两个组件条件都是TRUE,则返回TRUE。如果其中一个是 FALSE,则返回 FALSE。否则返回UNKNOWN如果不是所有行中的值都相同,显然不会加入任何东西 您使用的连接语法已在 20 年前在 Oracle 中被标准连接 (LEFT OUTER JOIN) 所取代 - 而 Oracle 在这方面做得很晚;显式联接在 1992 年的 SQL 标准中引入。因此,当您说这是您现在尝试的查询时,感觉有点奇怪。您的查询是正确的,但您不应再使用这种古老的连接语法。用标准连接替换它。 @ThorstenKettner 感谢您告诉我。我一直在使用这些,因为它们在 19c 中仍然受支持。无论如何,我将其替换为 LEFT OUTER JOIN。我的主要问题是“如果有办法编写查询而不在同一个表上加入 4 次”。 【参考方案1】:

我猜你想要这样的东西

with reject_reasons ( Account_No , Resn_Id1 , Resn_Id2 , Resn_Id3 , Resn_Id4 ) 
as 
(
select 100, '0001' , '0005' , '0006' , '0104' from dual union all
select 101, '0005' , '0006' , '0104' ,  null  from dual union all
select 102, '0001' , '0006' ,  null  ,  null  from dual union all
select 103,  null  ,  null  ,  null  ,  null  from dual union all
select 104, '0001' ,  null  ,  null  ,  null  from dual 
), 
reason_desc ( Resn_Id , Resn_Desc ) 
as 
(
select  '0001' , 'Bad Account'        from dual union all 
select  '0005' , 'Duplicate Account'  from dual union all 
select  '0006' , 'Invalid Data'       from dual union all 
select  '0104' , 'Invalid address'    from dual 
) 
select r.account_no,r.resn_id1,rd1.resn_desc,
r.resn_id2,rd2.resn_desc,
r.resn_id3,rd3.resn_desc,
r.resn_id4,rd4.resn_desc
from reject_reasons r 
   left join reason_desc rd1 on r.resn_id1=rd1.resn_id 
   left join reason_desc rd2 on r.resn_id2=rd2.resn_id
   left join reason_desc rd3 on r.resn_id3=rd3.resn_id 
   left join reason_desc rd4 on r.resn_id4=rd4.resn_id
order by 1 ;

这里有一个演示

db<>fiddle

【讨论】:

【参考方案2】:

由于没有所需的输出,我认为另一种方法可以连接描述。

WITH REJECTION AS (SELECT DISTINCT *
    FROM(
    SELECT
    Account_No,
    Resn_Id1 AS Resn_Id
    FROM reject_reasons r
        UNION
    SELECT 
    Account_No,
    Resn_Id2 AS Resn_Id
    FROM reject_reasons r
        UNION
    SELECT 
    Account_No,
    Resn_Id3 AS Resn_Id
    FROM reject_reasons r
        UNION
    SELECT 
    Account_No,
    Resn_Id4 AS Resn_Id
    FROM reject_reasons r)) 

SELECT REJECTION.Account_No,
listagg(rdesc.Resn_Desc, ', ') WITHIN GROUP (ORDER BY rdesc.Resn_Desc)
FROM REJECTION  
LEFT JOIN reason_desc rdesc
ON rdesc.Resn_Id = REJECTION.Resn_Id
GROUP BY REJECTION.Account_No

【讨论】:

以上是关于将具有多列值的表连接到具有多行值的表的主要内容,如果未能解决你的问题,请参考以下文章

使用 LINQ 将具有相同值的多行列表连接成单行

如何在 LINQ sql 中将两个表与一个具有不同值的表连接起来?

具有多列值的 DataView 的 RowFilter

从每个 id 具有特定值的表中选择行

基于多列值的具有重复键的两个大型 Pandas DataFrame 的条件合并/连接 - Python

具有各自值的多列到行