首页 > 解决方案 > 如何在不使用 SQL 中的多个连接条件的情况下获取同一行中的所有值?

问题描述

我有下表结构

学生

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(+)

请让我知道是否有任何其他优化方式来获取所有用户值。 注意:此表结构不能更改,只有读取权限可用

标签: sqloraclejoinouter-join

解决方案


您可以为此使用 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,并将根据使用的聚合函数返回一个值。您的示例意味着StudUserSTUD_ID and NUM表的组合将是唯一的,因此大多数 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,所以我猜你没有找到它,因为你不知道如何调用它。不能怪你。


推荐阅读