วิธีการรักษาลำดับขององค์ประกอบดั้งเดิมในอาร์เรย์ที่ไม่ผ่านการทดสอบ


19

รับสาย:

'ฉันคิดว่า PostgreSQL นั้นดี'

ฉันต้องการทำงานกับคำแต่ละคำที่พบในสตริงนั้น โดยพื้นฐานแล้วฉันมีส่วนแยกต่างหากซึ่งฉันสามารถรับรายละเอียดคำศัพท์และต้องการที่จะเข้าร่วมอาร์เรย์ของสตริงนั้นในพจนานุกรมนี้

จนถึงตอนนี้ฉันมี:

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;

สิ่งนี้ทำให้พื้นฐานของสิ่งที่ฉันหวังว่าจะทำได้สำเร็จ แต่ไม่ได้รักษาลำดับคำเดิมไว้

คำถามที่เกี่ยวข้อง:
PostgreSQL ไม่ถูกต้อง () พร้อมหมายเลของค์ประกอบ


คุณต้องการประมวลผลหนึ่งสตริงหรือทั้งตารางสตริง ? ถ้าเป็นเช่นนั้นตารางจะมีคีย์หลักหรือไม่
Erwin Brandstetter

@ErwinBrandstetter สตริงหนึ่งในตาราง (ที่ไม่มีคีย์หลัก)
swasheck

คำตอบ:


24

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;

ซอ Fiddle

ตอบคำถาม

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
นอกจากนี้คุณยังสามารถใช้ประโยชน์จากพฤติกรรม SELECT generate_series(1,array_length(word_array,1)), unnest(word_array) FROM ....SRF-ในรายการเลือกหน้าของโวหาร: 9.3 LATERALอาจให้บริการโซลูชั่นที่ดีกว่าสำหรับปัญหานี้
Craig Ringer

2
จะไม่generate_subscripts(arr, 1)ทำงานแทนgenerate_series(1, array_upper(arr, 1))หรือ ฉันต้องการอดีตเพื่อความชัดเจน
dezso

1
@Erwin คุณเคยเห็นสิ่งนี้กับโพสต์ที่เป็นต้นฉบับจาก depesz หรือไม่
แจ็คดักลาส

1
@JackDouglas: มันเกิดขึ้นเรามีการสนทนาเกี่ยวกับหัวข้อที่เกี่ยวข้องในวันศุกร์ซึ่งนำฉันไปสู่การค้นพบที่คล้ายกัน ฉันเพิ่มคำตอบเล็กน้อย
Erwin Brandstetter

1
ลิงค์สำหรับ "รายละเอียด" เพียงลิงค์ไปยังหน้าเดียวกันนี้ มันสับสน
สัญลักษณ์แทน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.