假设我有一张这样的桌子:
主题 | 旗帜 |
---|---|
这是一个测试 | 2 |
subject
属于 text
类型,flag
属于 int
类型。我想在 Postgres 中将此表转换为类似的内容:
代币 | 旗帜 |
---|---|
这个 | 2 |
是 | 2 |
a | 2 |
测试 | 2 |
有没有简单的方法可以做到这一点?
在
Postgres 14+中使用
LATERAL
连接 - 与
string_to_table()
。SELECT token, flag
FROM tbl, string_to_table(subject, ' ') token
WHERE flag = 2;
FROM
列表中的逗号(几乎)相当于CROSS JOIN
,LATERAL
自动假定为FROM
列表中的集合返回函数(SRF)。为什么是“几乎”?参见:
派生表的别名“令牌”也被假定为单个匿名列的列别名,并且我们在整个查询中假定不同的列名称。等效,更详细且不易出错:
SELECT s.token, t.flag
FROM tbl t
CROSS JOIN LATERAL string_to_table(subject, ' ') AS s(token)
WHERE t.flag = 2;
或者将 SRF 移至
SELECT
列表,这在 Postgres 中是允许的(但在标准 SQL 中不允许),以达到(几乎)相同的效果:
SELECT string_to_table(subject, ' ') AS token, flag
FROM tbl
WHERE flag = 2;
最后一个似乎可以接受,因为
SELECT
列表中的 SRF 已在 Postgres 10 中进行清理。请参阅:
如果
string_to_table()
不返回任何行(空或 null subject
),(隐式)连接会从结果中消除该行。使用 LEFT JOIN ... ON true
保留 tbl
中的合格行。参见:
regexp_split_to_table()
,但速度较慢。正则表达式功能强大但昂贵。参见:
在 Postgres 13 或更早版本中使用
unnest(string_to_array(subject, ' '))
而不是 string_to_table(subject, ' ')
。
我认为没有必要使用连接,只需将
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
使用正则表达式拆分到表功能,包括横向连接,
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 功能详情