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

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

Linda Hamilton
Linda Hamilton原創
2025-01-23 04:25:13312瀏覽

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

PostgreSQL unnest() 函式與元素編號

問題

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

<code class="language-sql">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
...</code>

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

<code class="language-sql">id | elem | nr
---+------+---
1  | ab   | 1
1  | cd   | 2
1  | efg  | 3
1  | hi   | 4
2  | jk   | 1
...</code>

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

解決方法

PostgreSQL 14 或更高版本

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

<code class="language-sql">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</code>

示範

PostgreSQL 9.4 或更高版本

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

<code class="language-sql">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</code>

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

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

<code class="language-sql">SELECT t.id, a.elem, a.nr
FROM   tbl t, unnest(string_to_array(t.elements, ',')) WITH ORDINALITY a(elem, nr)</code>

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

<code class="language-sql">SELECT t.id, a.elem, a.nr
FROM   tbl t, unnest(t.arr) WITH ORDINALITY a(elem, nr)</code>

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

<code class="language-sql">SELECT id, a, ordinality
FROM   tbl, unnest(arr) WITH ORDINALITY a</code>

還可以再簡化:

<code class="language-sql">SELECT * FROM tbl, unnest(arr) WITH ORDINALITY a</code>

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

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

PostgreSQL 8.4 - 9.3

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

<code class="language-sql">SELECT *, row_number() OVER (PARTITION by id) AS nr
FROM  (SELECT id, regexp_split_to_table(elements, ',') AS elem FROM tbl) t</code>

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

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

<code class="language-sql">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</code>

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

<code class="language-sql">SELECT id, arr[nr] AS elem, nr
FROM  (SELECT *, generate_subscripts(arr, 1) AS nr FROM tbl) t</code>

PostgreSQL 8.1 - 8.4

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

<code class="language-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'</code>

修改後的函數如下:

<code class="language-sql">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
...</code>

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

<code class="language-sql">id | elem | nr
---+------+---
1  | ab   | 1
1  | cd   | 2
1  | efg  | 3
1  | hi   | 4
2  | jk   | 1
...</code>

輸出

<code class="language-sql">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</code>

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

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn