WITH ORDINALITY
no Postgres 9.4 ou posterior
O novo recurso simplifica essa classe de problemas. A consulta acima agora pode ser simplesmente:
SELECT *
FROM regexp_split_to_table('I think postgres is nifty', ' ') WITH ORDINALITY x(word, rn);
Ou, aplicado a uma tabela:
SELECT *
FROM tbl t, regexp_split_to_table(t.my_column, ' ') WITH ORDINALITY x(word, rn);
Detalhes:
Sobre a LATERAL
junção implícita :
Postgres 9.3 ou mais antigo - e explicação mais geral
Para uma única sequência
Você pode aplicar a função de janela row_number()
para lembrar a ordem dos elementos. No entanto, com o habitual, row_number() OVER (ORDER BY col)
você obtém números de acordo com a ordem de classificação , não a posição original na string.
Você pode tentar e simplesmente omitir o ORDER BY
para obter a posição "como está":
SELECT *, row_number() OVER () AS rn
FROM (
SELECT regexp_split_to_table('I think postgres is nifty', ' ') AS word
) x;
Desempenho de regexp_split_to_table()
degradas com cordas longas. unnest(string_to_array(...))
escala melhor:
SELECT *, row_number() OVER () AS rn
FROM (
SELECT unnest(string_to_array('I think postgres is nifty', ' ')) AS word
) x;
No entanto, enquanto isso normalmente funciona e eu nunca o vi quebrar em consultas simples, o PostgreSQL não afirma nada sobre a ordem das linhas sem um explícito ORDER BY
.
Para garantir números ordinais de elementos na string original, use generate_subscript()
(aprimorado com o comentário de @deszo):
SELECT arr[rn] AS word, rn
FROM (
SELECT *, generate_subscripts(arr, 1) AS rn
FROM (
SELECT string_to_array('I think postgres is nifty', ' ') AS arr
) x
) y;
Para uma tabela de cordas
Adicione PARTITION BY id
à OVER
cláusula ...
Tabela de demonstração:
CREATE TEMP TABLE strings(string text);
INSERT INTO strings VALUES
('I think postgres is nifty')
,('And it keeps getting better');
Eu uso ctid
como substituto ad-hoc para uma chave primária . Se você tiver uma (ou qualquer coluna exclusiva ), use-a.
SELECT *, row_number() OVER (PARTITION BY ctid) AS rn
FROM (
SELECT ctid, unnest(string_to_array(string, ' ')) AS word
FROM strings
) x;
Isso funciona sem nenhum ID distinto:
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 Fiddle.
Resposta à pergunta
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;