我有一个包含这样数据的表:
select * from data
id | col1 | col2 | col3
---+-------+-------+-------
1 | 1,2,3 | 4,5,6 | 7,8,9
我想得到这样的数据:
id | name | dd | fn | suf
---+------+----+----+-----
1 | col1 | 1 | 2 | 3
1 | col2 | 4 | 5 | 6
1 | col3 | 7 | 8 | 9
目前,我在这样的查询中使用split_part():
SELECT * from(
select id,
'col1' as name,
NULLIF(split_part(col1, ',', 1), '') AS dd,
NULLIF(split_part(col1, ',', 2), '') AS fn,
NULLIF(split_part(col1, ',', 3), '') AS suf
from data
UNION
select id,
'col2' as name,
NULLIF(split_part(col2, ',', 1), '') AS dd,
NULLIF(split_part(col2, ',', 2), '') AS fn,
NULLIF(split_part(col2, ',', 3), '') AS suf
from data
UNION
select id,
'col3' as name,
NULLIF(split_part(col3, ',', 1), '') AS dd,
NULLIF(split_part(col3, ',', 2), '') AS fn,
NULLIF(split_part(col3, ',', 3), '') AS suf
from data
);
有更优雅的方式吗? 我有20列。
答案 0 :(得分:1)
假设这个表:
CREATE TABLE tbl (id int, col1 text, col2 text, col3 text);
INSERT INTO tbl VALUES (1 ,'1,2,3', '4,5,6', '7,8,9');
VALUES
子查询中的LATERAL
表达式应该是一个优雅的解决方案
然后使用split_part()
。仅当源中存在实际空字符串时才添加NULLIF()
SELECT id, x.name
, split_part(x.col, ',', 1) AS dd
, split_part(x.col, ',', 2) AS fn
, split_part(x.col, ',', 3) AS suf
FROM tbl t, LATERAL (
VALUES (text 'col1', t.col1)
, ( 'col2', t.col2)
, ( 'col3', t.col3)
-- ... many more?
) x(name, col);
适用于PostgreSQL 9.3或更高版本 SQL Fiddle.
相关:
答案 1 :(得分:0)
我会先union all
和split_part()
秒:
select id, name,
coalesce(split_part(col, ',', 1), '') as dd,
coalesce(split_part(col, ',', 2), '') as fn,
coalesce(split_part(col, ',', 3), '') as suf
from ((select id, 'col1' as name, col1 as col from data
) union all
(select id, 'col2' as name, col2 as col from data
) union all
(select id, 'col3' as name, col3 as col from data
)
) t;