SQL 行转列时如何应对不同的数据类型 *
有数据库表FIRSTTBL,部分数据如下所示:
ID
PROPERTY
TYPE
STRING
INTEGER
DATETIME
BOLLEAN
XML
1
firstname
NVARCHAR
John
null
null
null
null
1
lastname
NVARCHAR
Doe
null
null
null
null
1
birthdate
DATETIME
null
null
1986-09-16
null
null
1
address
XML
null
null
null
null
eyJh…
1
flag
BIT
null
null
null
1
null
1
number
INT
null
20
null
null
null
2
…
…
…
…
…
…
…
表中的数据每6条可以转为以下的一条记录,部分结果如下:
ID
FIRSTNAME
LASTANME
BIRTHDAY
ADDRESS
FLAG
NUMBER
1
John
Doe
1986-09-16
eyJh…
1
20
2
…
…
…
…
…
…
行转列,将PROPERTY中的各字段值(每6条)作为新列,取STRING、INTEGER、DATETIME、BOLLEAN、XML这几列的非空数据对应新列的数据(转换的同时需要保留各字段的数据类型)
SQL:
SELECT
ID,
FIRSTNAME,
...,
FLAG = CAST (FLAG AS INT),
...
FROM
(
SELECT
*
FROM
(
SELECT
f.ID,
f.PROPERTY,
f.STRING + f."INTEGER" + f.DATETIME + f.BOLLEAN + f.XML AS COLS
FROM
FIRSTTBL f)
PIVOT(
min(COLS) FOR PROPERTY IN
(
'firstname' AS firstname,
'lastname' AS lastname,
'birthdate' AS birthdate,
'address' AS address,
'flag' AS flag,
'number' AS "NUMBER"
)
)
)
容易看出,任意行的STRING、INTEGER、DATETIME、BOLLEAN、XML中有且仅有一列非空,只需要取第一个非空值,然后按要求行转列即可。对于这题来说,用PIVOT函数行转列本身并不难,但是SQL 中的列需要有统一的数据类型。这题需要先把合并列后的数据转为串,行转列操作后再按实际类型转回来。当列数较多时,SQL写起来就很麻烦了,更难以实现动态需求。
用开源集算器的SPL就很容易写:
A |
|
1 |
=connect("MSSQL") |
2 |
=A1.query@x("SELECT * FROM FIRSTTBL") |
3 |
=A2.pivot(ID;PROPERTY,~.array().m(4:).ifn();"firstname":"FIRSTNAME","lastname":"LASTANME","birthdate":"BIRTHDAY","address":"ADDRESS","flag":"FLAG","number":"NUMBER") |
SPL中的同列数据不要求统一数据类型,很容易实现行转列的同时保留数据类型。
https://stackoverflow.com/questions/64101227/sql-server-pivot-values-with-different-data-types
英文版
已回答