WITH ORDINALITY
在Postgres 9.4或更高版本中
新功能简化了此类问题。上面的查询现在可以简单地是:
SELECT *
FROM regexp_split_to_table('I think Postgres is nifty', ' ') WITH ORDINALITY x(word, rn);
或者,应用于表:
SELECT *
FROM tbl t, regexp_split_to_table(t.my_column, ' ') WITH ORDINALITY x(word, rn);
细节:
关于隐式LATERAL
联接:
Postgres 9.3或更早版本-以及更一般的解释
对于单个字符串
您可以应用窗口函数row_number()
来记住元素的顺序。但是,通常row_number() OVER (ORDER BY col)
您会根据排序顺序获得数字,而不是字符串中的原始位置。
您可以简单地省略ORDER BY
“按原样”的位置:
SELECT *, row_number() OVER () AS rn
FROM regexp_split_to_table('I think Postgres is nifty', ' ') AS x(word);
regexp_split_to_table()
长字符串会降低性能。 unnest(string_to_array(...))
扩展性更好:
SELECT *, row_number() OVER () AS rn
FROM unnest(string_to_array('I think Postgres is nifty', ' ')) AS x(word);
但是,尽管这通常可以正常工作,而且我从未见过它会在简单查询中中断,但Postgres无需断言就没有显式的行顺序ORDER BY
。
为了保证原始字符串中元素的序数,请使用generate_subscript()
(@deszo的注释进行了改进):
SELECT arr[rn] AS word, rn
FROM (
SELECT *, generate_subscripts(arr, 1) AS rn
FROM string_to_array('I think Postgres is nifty', ' ') AS x(arr)
) y;
对于字符串表
添加PARTITION BY id
到OVER
条款...
演示表:
CREATE TEMP TABLE strings(string text);
INSERT INTO strings VALUES
('I think Postgres is nifty')
,('And it keeps getting better');
我用作主键ctid
的临时替代品。如果您有一个(或任何唯一的列),请改用它。
SELECT *, row_number() OVER (PARTITION BY ctid) AS rn
FROM (
SELECT ctid, unnest(string_to_array(string, ' ')) AS word
FROM strings
) x;
此方法无需任何独特的ID:
SELECT arr[rn] AS word, rn
FROM (
SELECT *, generate_subscripts(arr, 1) AS rn
FROM (
SELECT string_to_array(string, ' ') AS arr
FROM strings
) x
) y;
SQL提琴。
回答问题
SELECT z.arr, z.rn, z.word, d.meaning -- , partofspeech -- ?
FROM (
SELECT *, arr[rn] AS word
FROM (
SELECT *, generate_subscripts(arr, 1) AS rn
FROM (
SELECT string_to_array(string, ' ') AS arr
FROM strings
) x
) y
) z
JOIN dictionary d ON d.wordname = z.word
ORDER BY z.arr, z.rn;