正如@Pavel 解释的那样,不可能像遍历数组那样简单地遍历记录。但是有几种方法可以解决它 - 取决于您的确切要求。最终,由于您想要返回同一列中的所有值,您需要将它们转换为相同的类型 -text
这是明显的共同点,因为每种类型都有一个文本表示。
又快又脏
比如说,你有一个带有integer
、 atext
和一date
列的表。
CREATE TEMP TABLE tbl(a int, b text, c date);
INSERT INTO tbl VALUES
(1, '1text', '2012-10-01')
,(2, '2text', '2012-10-02')
,(3, ',3,ex,', '2012-10-03') -- text with commas
,(4, '",4,"ex,"', '2012-10-04') -- text with commas and double quotes
那么解决方案可以很简单:
SELECT unnest(string_to_array(trim(t::text, '()'), ','))
FROM tbl t;
适用于前两行,但不适用于第 3 行和第 4 行的特殊情况。
您可以使用文本表示中的逗号轻松解决问题:
SELECT unnest(('{' || trim(t::text, '()') || '}')::text[])
FROM tbl t
WHERE a < 4;
这可以正常工作 - 除了第 4 行在文本表示中有双引号。通过将它们加倍来逃脱。但是数组构造函数需要将它们转义为\
. 不知道为什么会出现这种不兼容...
SELECT ('{' || trim(t::text, '()') || '}') FROM tbl t WHERE a = 4
产量:
{4,""",4,""ex,""",2012-10-04}
但是你需要:
SELECT '{4,"\",4,\"ex,\"",2012-10-04}'::text[]; -- works
适当的解决方案
如果您事先知道列名,那么干净的解决方案将很简单:
SELECT unnest(ARRAY[a::text,b::text,c::text])
FROM tbl
由于您对熟知类型的记录进行操作,因此您只需查询系统目录:
SELECT string_agg(a.attname || '::text', ',' ORDER BY a.attnum)
FROM pg_catalog.pg_attribute a
WHERE a.attrelid = 'tbl'::regclass
AND a.attnum > 0
AND a.attisdropped = FALSE
将其放入具有动态 SQL 的函数中:
CREATE OR REPLACE FUNCTION unnest_table(_tbl text)
RETURNS SETOF text LANGUAGE plpgsql AS
$func$
BEGIN
RETURN QUERY EXECUTE '
SELECT unnest(ARRAY[' || (
SELECT string_agg(a.attname || '::text', ',' ORDER BY a.attnum)
FROM pg_catalog.pg_attribute a
WHERE a.attrelid = _tbl::regclass
AND a.attnum > 0
AND a.attisdropped = false
) || '])
FROM ' || _tbl::regclass;
END
$func$;
称呼:
SELECT unnest_table('tbl') AS val
回报:
val
-----
1
1text
2012-10-01
2
2text
2012-10-02
3
,3,ex,
2012-10-03
4
",4,"ex,"
2012-10-04
这无需安装额外的模块即可工作。另一种选择是安装hstore扩展并像@Craig 演示的那样使用它。