SQL 如何将每组多列数据转到同一行 *

有数据库表STAKEHOLDER,数据如下所示:

CLASS

NAME

SID

1

name1

001

1

name2

002

2

name3

003

2

name4

004

2

name5

005

需要按CLASS 分组,并将其余列转到同一行,结果如下所示:

CLASS

NAME1

SID1

NAME2

SID2

NAME3

SID3

1

name1

001

name2

002



2

name3

003

name4

004

name5

005

OracleSQL:

WITH CTE AS(

SELECT

            UP.CLASS,

            UP.NS || UP.RN AS NSR,

            UP.VAL

FROM

            (

            SELECT

                        ROW_NUMBER ()

         OVER (

           PARTITION BY S.CLASS

            ORDER BY

                        S.CLASS) RN,

                        S.*

            FROM

                        STAKEHOLDER S

            ORDER BY

                        CLASS,

                        SID) SS

UNPIVOT (VAL FOR NS IN (NAME, SID)) UP

)

SELECT

            *

FROM

            CTE

PIVOT(MAX(VAL) FOR NSR IN ('NAME1' AS NAME1,

            'SID1' AS SID1,

            'NAME2' AS NAME2,

            'SID2' AS SID2,

            'NAME3' AS NAME3,

            'SID3' AS SID3))

用自然思维去解这道题并不难,按CLASS 分组后,只需要将 NAME 与 SID 这两列先转成行,同时建立需要转列的值所在列名,这里利用原列名 + 组内序号,例如 NAME1,SID1,NAME2,SID2,…,下一个组内又是NAME1,SID1,…,再合并各组数据后,行转列即可。SQL 不支持动态行列转换,当列数较少且固定时,勉强可以应付。但是当列数较多时,因为转换过程中需要枚举出所有列,所以写起来很费劲,写出的 SQL 也非常臃肿。如果是动态列,那就需要更复杂的办法来解了。

用开源集算器的SPL 就很容易写:


A

1

=connect("ORACLE")

2

=A1.query@x("SELECT * FROM STAKEHOLDER ORDER BY CLASS,SID")

3

=A2.fname().m(2:)

4

=A2.group@o(CLASS)

5

=A4.conj(~.news(A3;CLASS,A3(#)/A4.~.#:COL,eval(~):VAL))

6

=A5.pivot(CLASS;COL,VAL)

SPL 是专业的数据计算引擎,基于有序集合设计,提供了完善的集合运算,支持分步计算,更切合自然思维。相比 SQL 需要枚举列名,SPL 可以直接自动扩展,很容易处理各种行列转换问题。

问答搜集

https://stackoverflow.com/questions/64138971/how-to-merge-2-tables-into-1-row-with-multiple-entries-from-second-table-in-ora