CREATE TABLE test_array (
id SERIAL PRIMARY KEY,
str1 INT[][][] -- 三維整數陣列
);
INSERT INTO test_array VALUES
(1, ARRAY[[[1,2],[3,4],[5,6]], [[20,30],[40,50],[70,100]]]),
(2, ARRAY[[[100,200],[300,400],[500,600]], [[2000,3000],[4000,5000],[7000,10000]]]);
CREATE OR REPLACE FUNCTION sp_array2table_simple(anyarray)
RETURNS TABLE(element INT) AS $$
DECLARE
arr ALIAS FOR $1;
x INT;
BEGIN
DROP TABLE IF EXISTS tmp_1;
CREATE TEMPORARY TABLE tmp_1 (id INT);
FOREACH x IN ARRAY arr LOOP
INSERT INTO tmp_1 VALUES (x);
END LOOP;
RETURN QUERY SELECT * FROM tmp_1;
END; $$ LANGUAGE plpgsql;
測試:SELECT sp_array2table_simple(str1) FROM test_array WHERE id = 2;
耗時:~7.78 ms(12 筆記錄)
CREATE OR REPLACE FUNCTION sp_array2table(anyarray)
RETURNS TABLE(element INT) AS $$
DECLARE
arr ALIAS FOR $1;
slice INT[];
nlen INT := 0;
i INT := 1;
BEGIN
DROP TABLE IF EXISTS tmp_1;
CREATE TEMPORARY TABLE tmp_1 (id INT);
FOREACH slice SLICE 1 IN ARRAY arr LOOP -- 按第一維切片
nlen := array_length(slice, 1);
i := 1;
WHILE i <= nlen LOOP
INSERT INTO tmp_1 VALUES (slice[i]);
i := i + 1;
END LOOP;
END LOOP;
RETURN QUERY SELECT * FROM tmp_1;
END; $$ LANGUAGE plpgsql;
測試:相同查詢
耗時:~20.14 ms(較慢,因 WHILE 迴圈開銷)
SELECT unnest(str1) AS array_list
FROM test_array WHERE id = 2;
耗時:~1.00 ms (最快,C 語言層級實現)
SELECT regexp_split_to_table(array_to_string(str1, ','), ',+') AS array_list
FROM test_array WHERE id = 2;
原理:陣列 → 逗號字串 → 正則分割為資料列
耗時:~0.85 ms(極快,但涉及型別轉換開銷)
| 方法 | 耗時 | 適用場景 | 優點 | 缺點 |
|---|---|---|---|---|
| unnest() | 1.00 ms | 生產環境首選 | 原生、高效、支援多維 | 較新版本才支援完整功能 |
| array_to_string + regexp_split | 0.85 ms | 舊版本相容 | 純 SQL、無需建立函數 | 型別轉換風險、正則開銷 |
| 自訂 FOREACH 簡單版 | 7.78 ms | 教學/邏輯複雜 | 可控制遍歷邏輯 | 臨時表開銷大 |
| 自訂 SLICE 版 | 20.14 ms | 特殊切片需求 | 精確控制維度 | 效能最差 |
若需保留維度資訊(如索引位置):
SELECT
generate_subscripts(str1, 1) AS dim1,
generate_subscripts(str1, 2) AS dim2,
generate_subscripts(str1, 3) AS dim3,
unnest(str1) AS value
FROM test_array WHERE id = 2;
unnest():PostgreSQL 9.4+ 完整支援多維陣列展開,效能最優。anyarray 多態函數方便,但生產環境建議針對具體型別(如 INT[])建立專用函數。unnest() 記憶體佔用較大,可分批處理或使用游標。