Làm thế nào để duy trì thứ tự ban đầu của các phần tử trong một mảng không được kiểm tra?


17

Cho chuỗi:

'Tôi nghĩ rằng PostgreSQL là tiện lợi'

Tôi muốn hoạt động trên các từ riêng lẻ được tìm thấy trong chuỗi đó. Về cơ bản, tôi có một phần riêng biệt để tôi có thể nhận được các chi tiết từ và muốn tham gia một mảng không được kiểm tra của chuỗi đó trong từ điển này.

Cho đến nay tôi có:

select word, meaning, partofspeech
from unnest(string_to_array('I think that PostgreSQL is nifty',' ')) as word
from table t
join dictionary d
on t.word = d.wordname;

Điều này hoàn thành các nguyên tắc cơ bản của những gì tôi đã hy vọng sẽ làm, nhưng nó không giữ được trật tự từ gốc.

Câu hỏi liên quan:
PostgreSQL unsest () với số phần tử


Bạn có muốn xử lý một chuỗi hoặc toàn bộ bảng chuỗi không? Nếu vậy, bảng có khóa chính không?
Erwin Brandstetter

@ErwinBrandstetter một chuỗi trong một bảng (có khóa chính)
swasheck

Câu trả lời:


22

WITH ORDINALITY trong Postgres 9,4 trở lên

Tính năng mới đơn giản hóa lớp vấn đề này. Truy vấn trên có thể chỉ đơn giản là:

SELECT *
FROM   regexp_split_to_table('I think postgres is nifty', ' ') WITH ORDINALITY x(word, rn);

Hoặc, áp dụng cho bảng:

SELECT *
FROM   tbl t, regexp_split_to_table(t.my_column, ' ') WITH ORDINALITY x(word, rn);

Chi tiết:

Về việc LATERALtham gia ngầm :

Postgres 9.3 trở lên - và giải thích tổng quát hơn

Đối với một chuỗi

Bạn có thể áp dụng chức năng cửa sổ row_number()để ghi nhớ thứ tự các phần tử. Tuy nhiên, với thông thường, row_number() OVER (ORDER BY col)bạn nhận được các số theo thứ tự sắp xếp , không phải vị trí ban đầu trong chuỗi.

Bạn có thể thử và chỉ cần bỏ qua ORDER BYđể có được vị trí "như hiện tại":

SELECT *, row_number() OVER () AS rn
FROM  (
   SELECT regexp_split_to_table('I think postgres is nifty', ' ') AS word
   ) x;

Hiệu suất của regexp_split_to_table()suy thoái với chuỗi dài. unnest(string_to_array(...))cân tốt hơn:

SELECT *, row_number() OVER () AS rn
FROM  (
   SELECT unnest(string_to_array('I think postgres is nifty', ' ')) AS word
   ) x;

Tuy nhiên, trong khi điều này thường hoạt động và tôi chưa bao giờ thấy nó bị hỏng trong các truy vấn đơn giản, PostgreQuery khẳng định không có gì về thứ tự của các hàng mà không có một điều rõ ràng ORDER BY.

Để đảm bảo số thứ tự của các phần tử trong chuỗi gốc, hãy sử dụng generate_subscript()(được cải thiện với nhận xét của @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;

Đối với một bảng chuỗi

Thêm PARTITION BY idvào OVERmệnh đề ...

Bảng demo:

CREATE TEMP TABLE strings(string text);
INSERT INTO strings VALUES
  ('I think postgres is nifty')
 ,('And it keeps getting better');

Tôi sử dụng ctidnhư là một thay thế ad-hoc cho một khóa chính . Nếu bạn có một (hoặc bất kỳ cột duy nhất ), hãy sử dụng thay thế.

SELECT *, row_number() OVER (PARTITION BY ctid) AS rn
FROM  (
   SELECT ctid, unnest(string_to_array(string, ' ')) AS word
   FROM   strings
   ) x;

Điều này hoạt động mà không có bất kỳ ID riêng biệt:

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;

Câu đố SQL.

Trả lời câu hỏi

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;

1
Bạn cũng có thể khai thác hành vi SRF-in-SELECT-list kỳ quặc của PG : SELECT generate_series(1,array_length(word_array,1)), unnest(word_array) FROM ..... 9.3 LATERALcó thể cung cấp giải pháp tốt hơn cho vấn đề này.
Craig Ringer

2
Sẽ không generate_subscripts(arr, 1)làm việc thay vì generate_series(1, array_upper(arr, 1))? Tôi muốn trước đây cho rõ ràng.
dezso

@dezso: Điểm tốt. Đơn giản hóa một số truy vấn thêm. Tôi sửa đổi câu trả lời cho phù hợp.
Erwin Brandstetter

1
@Erwin bạn đã thấy bài này với bài đăng ORDINALITY từ depesz chưa?
Jack Douglas

1
@JackDoumund: Khi nó xảy ra, chúng tôi đã có một cuộc thảo luận về một chủ đề liên quan vào thứ Sáu , dẫn tôi đến một khám phá tương tự. Tôi đã thêm một chút vào câu trả lời.
Erwin Brandstetter
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.