首頁 > 資料庫 > mysql教程 > 使用PostgreSQL的unnest()函數時如何取得元素編號?

使用PostgreSQL的unnest()函數時如何取得元素編號?

Linda Hamilton
發布: 2025-01-23 04:25:13
原創
310 人瀏覽過

How to Get the Element Number When Using PostgreSQL's unnest() Function?

PostgreSQL unnest() 函式與元素編號

問題

當遇到包含分隔值的欄位時,unnest() 函數提供了一種提取這些值的方法:

myTable
id | elements
---+------------
1  |ab,cd,efg,hi
2  |jk,lm,no,pq
3  |rstuv,wxyz

select id, unnest(string_to_array(elements, ',')) AS elem
from myTable

id | elem
---+-----
1  | ab
1  | cd
1  | efg
1  | hi
2  | jk
...
登入後複製
登入後複製

但是,您可能希望也包含元素編號,格式如下:

id | elem | nr
---+------+---
1  | ab   | 1
1  | cd   | 2
1  | efg  | 3
1  | hi   | 4
2  | jk   | 1
...
登入後複製
登入後複製

最終目標是在不使用視窗函數(如row_number()rank())的情況下獲得來源字串中每個元素的原始位置,因為這些函數始終傳回1,這可能是因為所有元素都位於來源表的同一行中。

解決方法

PostgreSQL 14 或更高版本

對於逗號分隔的字串,請使用 string_to_table() 來取代 unnest(string_to_array())

SELECT t.id, a.elem, a.nr
FROM   tbl t
LEFT   JOIN LATERAL string_to_table(t.elements, ',') WITH ORDINALITY AS a(elem, nr) ON true
登入後複製
登入後複製

示範

PostgreSQL 9.4 或更高版本

對於傳回集合的函數,使用 WITH ORDINALITY

SELECT t.id, a.elem, a.nr
FROM   tbl AS t
LEFT   JOIN LATERAL unnest(string_to_array(t.elements, ',')) WITH ORDINALITY AS a(elem, nr) ON true
登入後複製

LEFT JOIN ... ON true 確保保留左側表中的所有行,而不管右側表表達式是否回傳任何行。

或者,由於 LEFT JOIN ... ON true 保留了所有行,因此可以使用更簡潔的查詢版本:

SELECT t.id, a.elem, a.nr
FROM   tbl t, unnest(string_to_array(t.elements, ',')) WITH ORDINALITY a(elem, nr)
登入後複製

對於實際數組(arr 為數組列),可以使用更簡潔的形式:

SELECT t.id, a.elem, a.nr
FROM   tbl t, unnest(t.arr) WITH ORDINALITY a(elem, nr)
登入後複製

為了簡單起見,可以使用預設列名:

SELECT id, a, ordinality
FROM   tbl, unnest(arr) WITH ORDINALITY a
登入後複製

還可以再簡化:

SELECT * FROM tbl, unnest(arr) WITH ORDINALITY a
登入後複製

此最終形式傳回 tbl 的所有欄位。當然,明確指定列別名和表格限定列可以提高清晰度。

a 既用作表別名,也用作列別名(對於第一列),附加的序號列的預設名稱為 ordinality

PostgreSQL 8.4 - 9.3

使用 row_number() OVER (PARTITION BY id ORDER BY elem) 依照排序順序(而非序號位置)取得數字:

SELECT *, row_number() OVER (PARTITION by id) AS nr
FROM  (SELECT id, regexp_split_to_table(elements, ',') AS elem FROM tbl) t
登入後複製

雖然這通常有效,並且在簡單的查詢中沒有觀察到失敗,但 PostgreSQL 不保證在沒有 ORDER BY 的情況下行的順序。當前行為是實現細節的結果。

保證空格分隔字串中元素的序號

SELECT id, arr[nr] AS elem, nr
FROM  (
   SELECT *, generate_subscripts(arr, 1) AS nr
   FROM  (SELECT id, string_to_array(elements, ' ') AS arr FROM tbl) t
   ) sub
登入後複製

對於實際陣列,可以使用更簡單的版本:

SELECT id, arr[nr] AS elem, nr
FROM  (SELECT *, generate_subscripts(arr, 1) AS nr FROM tbl) t
登入後複製

PostgreSQL 8.1 - 8.4

由於 PostgreSQL 8.1 到 8.4 版本缺少某些功能,例如 RETURNS TABLEgenerate_subscripts()unnest()array_length(),因此可以使用名為 f_unnest_ord 的自訂 SQL 函數:

CREATE FUNCTION f_unnest_ord(anyarray, OUT val anyelement, OUT ordinality integer)
  RETURNS SETOF record
  LANGUAGE sql IMMUTABLE AS
'SELECT [i], i - array_lower(,1) + 1
 FROM   generate_series(array_lower(,1), array_upper(,1)) i'
登入後複製

修改後的函數如下:

myTable
id | elements
---+------------
1  |ab,cd,efg,hi
2  |jk,lm,no,pq
3  |rstuv,wxyz

select id, unnest(string_to_array(elements, ',')) AS elem
from myTable

id | elem
---+-----
1  | ab
1  | cd
1  | efg
1  | hi
2  | jk
...
登入後複製
登入後複製

此擴充函數 f_unnest_ord_idx 傳回附加的 idx 欄位。比較:

id | elem | nr
---+------+---
1  | ab   | 1
1  | cd   | 2
1  | efg  | 3
1  | hi   | 4
2  | jk   | 1
...
登入後複製
登入後複製

輸出

SELECT t.id, a.elem, a.nr
FROM   tbl t
LEFT   JOIN LATERAL string_to_table(t.elements, ',') WITH ORDINALITY AS a(elem, nr) ON true
登入後複製
登入後複製

以上是使用PostgreSQL的unnest()函數時如何取得元素編號?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板