"As @Pavel已经解释过的,遍历一个记录并不像你遍历一个数组那么简单。但是,根据您的具体要求,有几种方法可以绕过去。最终,因为您想返回同一列中的所有值,所以您需要将它们转换为相同的类型-
文本
是明显的共同点,因为每种类型都有一个文本表示。
快速而简单的方法
假设您有一个包含一个整数
、一个文本
和一个日期
列的表。
"
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')
,(4, '",4,"ex,"', '2012-10-04')
那么解决方案可能就像这样简单:
SELECT unnest(string_to_array(trim(t::text, '()'), ','))
FROM tbl t;
第一和第二行的工作正常,但在第三和第四行的特殊情况下失败。
您可以通过在文本表示中使用逗号轻松解决该问题。
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[];
正确的解决方案
如果您事先知道列名,那么一个干净的解决方案将会很简单:
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 演示的那样。