具有多列的 Unpivot postgres table
Unpivot postgres table having multiple columns
我想旋转一个 table 具有如下所示的一些列。
ID
week1
week2
week3
week4
week5
week6
week7
1
8
9
10
11
12
13
14
2
15
16
17
18
19
20
21
3
22
23
24
25
26
27
28
期望的输出是-
ID
week_number
week_value
1
1
8
1
2
9
1
3
10
1
4
11
1
5
12
1
6
13
1
7
14
2
1
15
2
2
16
2
3
17
2
4
18
2
5
19
2
6
20
2
7
21
3
1
22
3
2
23
3
3
24
3
4
25
3
5
26
3
6
27
3
7
28
我尝试使用交叉表,但无法正常工作。以下是我尝试过的方法 -
select * from crosstab('select ID,week1, week2,week3,week4,week5,week6,week7 order by ID') as table_name(ID, week_number, week_value);
请有人帮忙,因为我在处理复杂 sql 查询方面经验不多。
这实际上与枢轴相反,也称为“反枢轴”,可以使用横向交叉连接来完成:
select t.id, x.*
from the_table t
cross join lateral (
values (1, week1), (2, week2), (3, week3),
(4, week4), (5, week5), (6, week6),
(7, week7)
) as x(week_number, week_value)
order by t.id, x.week_number
一种使用 JSONB 的快速替代方法,适用于任意数量的列,前提是其中一个列称为 id
。无关,但结果看起来与臭名昭著的 EAV antipattern.
惊人地相似
with t as (select to_jsonb(t) j from the_table t)
select j ->> 'id' id,
(jsonb_each_text(j - 'id')).*
from t;
id
key
value
1
week1
8
1
week2
9
1
week3
10
1
week4
11
1
week5
12
1
week6
13
1
week7
14
2
week1
15
2
week2
16
2
week3
17
2
week4
18
2
week5
19
2
week6
20
2
week7
21
3
week1
22
3
week2
23
3
week3
24
3
week4
25
3
week5
26
3
week6
27
3
week7
28
由于您使用 SparkSQL 标记了问题,这里有一个使用 stack
函数的解决方案。应用于您的示例:
df = spark.createDataFrame([
(1, 8, 9, 10, 11, 12, 13, 14),
(2, 15, 16, 17, 18, 19, 20, 21),
(3, 22, 23, 24, 25, 26, 27, 28)
], ["ID", "week1", "week2", "week3", "week4", "week5", "week6", "week7"])
df.createOrReplaceTempView("my_table")
spark.sql("""
SELECT ID,
stack(7, '1', week1, '2', week2, '3', week3, '4', week4, '5', week5, '6', week6, '7', week7) as (week_number, week_value)
FROM my_table
""").show()
#+---+-----------+----------+
#| ID|week_number|week_value|
#+---+-----------+----------+
#| 1| 1| 8|
#| 1| 2| 9|
#| 1| 3| 10|
#| 1| 4| 11|
#| 1| 5| 12|
#| 1| 6| 13|
#| 1| 7| 14|
#| 2| 1| 15|
#| 2| 2| 16|
#| 2| 3| 17|
#| 2| 4| 18|
#| 2| 5| 19|
#| 2| 6| 20|
#| 2| 7| 21|
#| 3| 1| 22|
#| 3| 2| 23|
#| 3| 3| 24|
#| 3| 4| 25|
#| 3| 5| 26|
#| 3| 6| 27|
#| 3| 7| 28|
#+---+-----------+----------+
我想旋转一个 table 具有如下所示的一些列。
ID | week1 | week2 | week3 | week4 | week5 | week6 | week7 |
---|---|---|---|---|---|---|---|
1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
2 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
3 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
期望的输出是-
ID | week_number | week_value |
---|---|---|
1 | 1 | 8 |
1 | 2 | 9 |
1 | 3 | 10 |
1 | 4 | 11 |
1 | 5 | 12 |
1 | 6 | 13 |
1 | 7 | 14 |
2 | 1 | 15 |
2 | 2 | 16 |
2 | 3 | 17 |
2 | 4 | 18 |
2 | 5 | 19 |
2 | 6 | 20 |
2 | 7 | 21 |
3 | 1 | 22 |
3 | 2 | 23 |
3 | 3 | 24 |
3 | 4 | 25 |
3 | 5 | 26 |
3 | 6 | 27 |
3 | 7 | 28 |
我尝试使用交叉表,但无法正常工作。以下是我尝试过的方法 -
select * from crosstab('select ID,week1, week2,week3,week4,week5,week6,week7 order by ID') as table_name(ID, week_number, week_value);
请有人帮忙,因为我在处理复杂 sql 查询方面经验不多。
这实际上与枢轴相反,也称为“反枢轴”,可以使用横向交叉连接来完成:
select t.id, x.*
from the_table t
cross join lateral (
values (1, week1), (2, week2), (3, week3),
(4, week4), (5, week5), (6, week6),
(7, week7)
) as x(week_number, week_value)
order by t.id, x.week_number
一种使用 JSONB 的快速替代方法,适用于任意数量的列,前提是其中一个列称为 id
。无关,但结果看起来与臭名昭著的 EAV antipattern.
with t as (select to_jsonb(t) j from the_table t)
select j ->> 'id' id,
(jsonb_each_text(j - 'id')).*
from t;
id | key | value |
---|---|---|
1 | week1 | 8 |
1 | week2 | 9 |
1 | week3 | 10 |
1 | week4 | 11 |
1 | week5 | 12 |
1 | week6 | 13 |
1 | week7 | 14 |
2 | week1 | 15 |
2 | week2 | 16 |
2 | week3 | 17 |
2 | week4 | 18 |
2 | week5 | 19 |
2 | week6 | 20 |
2 | week7 | 21 |
3 | week1 | 22 |
3 | week2 | 23 |
3 | week3 | 24 |
3 | week4 | 25 |
3 | week5 | 26 |
3 | week6 | 27 |
3 | week7 | 28 |
由于您使用 SparkSQL 标记了问题,这里有一个使用 stack
函数的解决方案。应用于您的示例:
df = spark.createDataFrame([
(1, 8, 9, 10, 11, 12, 13, 14),
(2, 15, 16, 17, 18, 19, 20, 21),
(3, 22, 23, 24, 25, 26, 27, 28)
], ["ID", "week1", "week2", "week3", "week4", "week5", "week6", "week7"])
df.createOrReplaceTempView("my_table")
spark.sql("""
SELECT ID,
stack(7, '1', week1, '2', week2, '3', week3, '4', week4, '5', week5, '6', week6, '7', week7) as (week_number, week_value)
FROM my_table
""").show()
#+---+-----------+----------+
#| ID|week_number|week_value|
#+---+-----------+----------+
#| 1| 1| 8|
#| 1| 2| 9|
#| 1| 3| 10|
#| 1| 4| 11|
#| 1| 5| 12|
#| 1| 6| 13|
#| 1| 7| 14|
#| 2| 1| 15|
#| 2| 2| 16|
#| 2| 3| 17|
#| 2| 4| 18|
#| 2| 5| 19|
#| 2| 6| 20|
#| 2| 7| 21|
#| 3| 1| 22|
#| 3| 2| 23|
#| 3| 3| 24|
#| 3| 4| 25|
#| 3| 5| 26|
#| 3| 6| 27|
#| 3| 7| 28|
#+---+-----------+----------+