SQL 如何将组内多字段同时行转列 *
有数据库表FACTTABLE,数据如下所示:
ID
TYPE
VALUE
CURRENCY
ABC
TOT_AMT
3
5.7702
ABC
AMT_AVAL
1
1.9234
ABC
DRWN_AMT
2
3.8468
ABC
MTD_DRWN
2
3.8468
DEF
TOT_AMT
3
5.7702
DEF
AMT_AVAL
1
1.9234
DEF
DRWN_AMT
2
3.8468
DEF
MTD_DRWN
2
3.8468
需要按ID分组,组内多字段同时行转列,结果如下所示:
ID
AMT_AVAL
AMT_AVAL1
DRWN_AMT
DRWN_AMT1
MTD_DRWN
MTD_DRWN1
TOT_AMT
TOT_AMT1
ABC
1
1.9234
2
3.8468
2
3.8468
3
5.7702
DEF
1
1.9234
2
3.8468
2
3.8468
3
5.7702
将VALUE与CURRENCY分别对应"TYPE"与"TYPE"1列,变成相应的行值
SQL Server的SQL:
WITH CTE AS
(
SELECT UP.ID,
UP.TYPE + '_' + LEFT(UP.VALUETYPE, 4) AS NEW_CODE,
UP.VALUE1
FROM FACTTABLE
UNPIVOT (VALUE1 FOR VALUETYPE IN (VALUE, CURRENCY)) UP
)
SELECT P.ID,
P.TOT_AMT_CURR AS TOT_AMT,
P.TOT_AMT_VALU AS TOT_AMT1,
P.AMT_AVAL_CURR AS AMT_AVAL,
P.AMT_AVAL_VALU AS AMT_AVAL1,
P.DRWN_AMT_CURR AS DRWN_AMT,
P.DRWN_AMT_VALU AS DRWN_AMT1,
P.MTD_DRWN_CURR AS MTD_DRWN,
P.MTD_DRWN_VALU AS MTD_DRWN1
FROM CTE
PIVOT (MAX(VALUE1) FOR NEW_CODE IN ([TOT_AMT_CURR], [TOT_AMT_VALU],
[AMT_AVAL_CURR], [AMT_AVAL_VALU],
[DRWN_AMT_CURR], [DRWN_AMT_VALU],
[MTD_DRWN_CURR], [MTD_DRWN_VALU])) P
用自然思维去解这道题并不难,只需要将VALUE与CURRENCY这两列先转成行,比如TYPE为TOT_AMT的VALUE对应TOT_AMT、CURRENCY对应TOT_AMT1依此类推,然后再直接行转列即可。SQL不支持动态行列转换,当列数较少且固定时,勉强可以应付。但是当列数较多时,因为转换过程中需要枚举出所有列,所以写起来很费劲,写出的SQL也非常臃肿。如果是动态列,那就需要更复杂的办法来解了。
用开源集算器的SPL就很容易写:
A |
|
1 |
=connect("mssql") |
2 |
=A1.query@x("SELECT * FROM FACTTABLE") |
3 |
=A2.news([VALUE,CURRENCY];ID,TYPE,~:VALUE).run(if(#%2==0,TYPE=TYPE/"1")) |
4 |
=A3.pivot(ID;TYPE,VALUE) |
SPL是专业的数据计算引擎,基于有序集合设计,提供了完善的集合运算,相当于Java和SQL优势的结合,很容易处理各种行列转换问题。
https://stackoverflow.com/questions/64132722/pivot-operator-on-two-columns
英文版