如何在不使用 SQL 中的多个连接条件的情况下获取同一行中的所有值?

Posted

技术标签:

【中文标题】如何在不使用 SQL 中的多个连接条件的情况下获取同一行中的所有值?【英文标题】:How get all value in same row without using multiple joins conditions in SQL? 【发布时间】:2020-11-26 20:16:03 【问题描述】:

我有下面的表结构

学生

Stud_ID | First_Name | Last_name | Contact
ID001   | AAA        | AAA       |     111
ID002   | BBB        | BBB       |     222

学生用户

Stud_ID | NUM | Value
ID001   |  10 | English
ID001   |  20 | Math
ID001   |  30 | Science
ID002   |  10 | English
ID002   |  20 | Math

预期输出

Stud_id | First_name | 10      | 20    | 30
ID001   | AAA        | English | Math  | Science
ID002   | BBB        | English | Math  |

我正在使用的当前查询

select 
        stud_id,
        First_name,
        EG.EGUV AS "10",
        LE.LEUV AS "20",
        FPS.FPSUV AS "30"
from 
        student,
        (SELECT STUD_ID AS EGS,USER_VALUE AS EGUV FROM STUD_USER WHERE COL_NUM='10') AS EG,
        (SELECT STUD_ID AS BUS,USER_VALUE AS BUUV FROM STUD_USER WHERE COL_NUM='20') AS BU,
        (SELECT STUD_ID AS AUS,USER_VALUE AS AUV FROM STUD_USER WHERE COL_NUM='30') AS A
where
        ST.STUD_ID=EG.EGS(+) and 
        ST.STUD_ID=BU.BUS(+) and    
        ST.STUD_ID=A.AUS(+)

如果有任何其他优化方式来获取所有用户价值,请告诉我。 注意:此表结构不能更改,只有读取权限可用

【问题讨论】:

【参考方案1】:

您可以为此使用 Oracle PIVOT 子句。 它将(排序)根据所选列的值动态创建附加列。

这是我使用的查询(使用 WITH 子句来模拟您的输入数据):

WITH
Student
AS
    (SELECT 'ID001' AS Stud_ID, 'AAA' AS First_Name, 'AAA' AS Last_name, 111 AS Contact FROM DUAL
     UNION ALL
     SELECT 'ID002', 'BBB', 'BBB', 222 FROM DUAL),
StudUser
AS
    (SELECT 'ID001' AS Stud_ID, 10 AS NUM, 'English' AS VALUE FROM DUAL
     UNION ALL
     SELECT 'ID001', 20, 'Math' FROM DUAL
     UNION ALL
     SELECT 'ID001', 30, 'Science' FROM DUAL
     UNION ALL
     SELECT 'ID002', 10, 'English' FROM DUAL
     UNION ALL
     SELECT 'ID002', 20, 'Math' FROM DUAL),
Prepare
AS
    (SELECT ST.STUD_ID,
            ST.FIRST_NAME,
            SU.NUM,
            SU.VALUE
       FROM STUDENT ST LEFT JOIN STUDUSER SU ON ST.STUD_ID = SU.STUD_ID)
SELECT *
FROM Prepare PIVOT (MIN (VALUE) FOR NUM IN (10, 20, 30))

PIVOT 函数需要一个聚合函数,因为它将遍历所有结果,例如STUD_ID = ID001 and NUM = 10 并将根据使用的聚合函数返回一个值。您的示例暗示 STUD_ID and NUM 的组合对于 StudUser 表是唯一的,因此大多数 Oracle 的聚合函数都可以,因为它们只需要遍历一个值。如果组合不是唯一的,您将不得不花一点时间考虑您希望聚合它们的方式。

pivot 子句的FOR 部分可让您指定要将哪些值转换为列。不幸的是,这不能动态生成,例如:

SELECT *
FROM Prepare PIVOT (MIN (VALUE) FOR NUM IN ( SELECT DISTINCT NUM FROM StudUser ))

那将是无效的并且不会编译。

您还可以为透视列指定所需的列名,如下所示:

SELECT *
FROM Prepare PIVOT (MIN (VALUE) FOR NUM IN (10 Subject1, 20 Subject2, 30 Subject3))

我只是通过搜索找到了 PIVOT 子句:oracle turn values into columns,所以我猜你没有找到它,因为你不知道如何打电话给这个。不能怪你。

【讨论】:

以上是关于如何在不使用 SQL 中的多个连接条件的情况下获取同一行中的所有值?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用左连接的情况下根据“OR”条件对数据框进行子集化? [复制]

在不知道 SQL 中的列的情况下创建表

如何在不使用循环的情况下更新 SQL Server 中两组不同条件之间的行

如何在不破坏SQL逻辑的情况下将JOINS转换为子查询

我可以在不返回条件列的情况下进行左连接吗?

我可以在不创建实体类的情况下对大型 sql 使用休眠命名查询吗?