在 Postgres 中将列拆分为多行

Split column into multiple rows in Postgres

假设我有一个这样的table:

    subject     | flag
----------------+------
 this is a test |    2

subjecttext 类型,flagint 类型。我想在 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 JOINLATERAL 被自动假设用于 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 功能详情