在 Postgres 中将列拆分为多行
Split column into multiple rows in Postgres
假设我有一个这样的table:
subject | flag
----------------+------
this is a test | 2
subject
是 text
类型,flag
是 int
类型。我想在 Postgres 中将此 table 转换为类似这样的内容:
token | flag
----------------+------
this | 2
is | 2
a | 2
test | 2
有没有简单的方法来做到这一点?
在 Postgres 9.3+ 中使用 LATERAL
连接。最小形式:
SELECT token, flag
FROM tbl, unnest(string_to_array(subject, ' ')) token
WHERE flag = 2;
FROM
列表中的逗号(几乎)等同于 CROSS JOIN
,LATERAL
被自动假设用于 set-returning 函数(SRF) FROM
列表。为什么是“差不多”?参见:
派生的 table 的别名“token”也被假定为单个匿名列的列别名,并且我们在整个查询中假定了不同的列名。等效,更冗长且更不容易出错:
SELECT s.token, t.flag
FROM tbl t
CROSS JOIN LATERAL unnest(string_to_array(subject, ' ')) AS s(token)
WHERE t.flag = 2;
或者将 SRF 移动到 SELECT
列表中,这在 Postgres 中是允许的(但在标准 SQL 中是不允许的),以达到相同的效果:
SELECT unnest(string_to_array(subject, ' ')) AS token, flag
FROM tbl
WHERE flag = 2;
最后一个似乎可以接受table,因为 SELECT
列表中的 SRF 已在 Postgres 10 中被清除。参见:
如果 unnest()
没有 return 任何行(空行或 NULL subject
),(隐式)连接会从结果中删除该行。使用 LEFT JOIN ... ON true
保留来自 tbl
的符合条件的行。参见:
我们也可以使用 regexp_split_to_table()
,但这通常会更慢,因为正则表达式的成本更高一些。参见:
- SQL select rows containing substring in text field
- PostgreSQL unnest() with element number
我认为没有必要使用连接,只需将 unnest()
函数与 string_to_array()
结合使用即可:
SELECT unnest(string_to_array(subject, ' ')) as "token", flag FROM test;
token | flag
-------+-------
this | 2
is | 2
a | 2
test | 2
使用正则表达式拆分为 table 函数,包括横向连接,
SELECT s.token, flag
FROM tbl t, regexp_split_to_table(t.subject, ' ') s(token)
WHERE flag = 2;
参考https://www.postgresql.org/docs/9.3/functions-string.html
功能详情
假设我有一个这样的table:
subject | flag
----------------+------
this is a test | 2
subject
是 text
类型,flag
是 int
类型。我想在 Postgres 中将此 table 转换为类似这样的内容:
token | flag
----------------+------
this | 2
is | 2
a | 2
test | 2
有没有简单的方法来做到这一点?
在 Postgres 9.3+ 中使用 LATERAL
连接。最小形式:
SELECT token, flag
FROM tbl, unnest(string_to_array(subject, ' ')) token
WHERE flag = 2;
FROM
列表中的逗号(几乎)等同于 CROSS JOIN
,LATERAL
被自动假设用于 set-returning 函数(SRF) FROM
列表。为什么是“差不多”?参见:
派生的 table 的别名“token”也被假定为单个匿名列的列别名,并且我们在整个查询中假定了不同的列名。等效,更冗长且更不容易出错:
SELECT s.token, t.flag
FROM tbl t
CROSS JOIN LATERAL unnest(string_to_array(subject, ' ')) AS s(token)
WHERE t.flag = 2;
或者将 SRF 移动到 SELECT
列表中,这在 Postgres 中是允许的(但在标准 SQL 中是不允许的),以达到相同的效果:
SELECT unnest(string_to_array(subject, ' ')) AS token, flag
FROM tbl
WHERE flag = 2;
最后一个似乎可以接受table,因为 SELECT
列表中的 SRF 已在 Postgres 10 中被清除。参见:
如果 unnest()
没有 return 任何行(空行或 NULL subject
),(隐式)连接会从结果中删除该行。使用 LEFT JOIN ... ON true
保留来自 tbl
的符合条件的行。参见:
我们也可以使用 regexp_split_to_table()
,但这通常会更慢,因为正则表达式的成本更高一些。参见:
- SQL select rows containing substring in text field
- PostgreSQL unnest() with element number
我认为没有必要使用连接,只需将 unnest()
函数与 string_to_array()
结合使用即可:
SELECT unnest(string_to_array(subject, ' ')) as "token", flag FROM test;
token | flag
-------+-------
this | 2
is | 2
a | 2
test | 2
使用正则表达式拆分为 table 函数,包括横向连接,
SELECT s.token, flag
FROM tbl t, regexp_split_to_table(t.subject, ' ') s(token)
WHERE flag = 2;
参考https://www.postgresql.org/docs/9.3/functions-string.html 功能详情