此查询正常,
WITH test AS (
SELECT array_agg(t) as x FROM (
SELECT 1111 as id, 'aaaaa' as cc
) AS t
) SELECT x[1] FROM test;
但是,可以访问recod元素吗?我尝试SELECT x[1].id
; SELECT x[1][1]
; ......什么都行不通
我也尝试
select x[1] from (select array[row(1,2)] as x) as t;
无法仅访问第1项或仅访问第2项的解决方案。
我无法关注的线索:postgresql.1045698.n5.nabble.com使用CREATE TYPE
解决问题...好的,但我需要“查询全部”解决方案。 PostgreSQL的“动态打字”在哪里?如何在没有CREATE TYPE
子句的情况下进行CAST或表达类型?
答案 0 :(得分:10)
目前似乎没有任何语法可以访问匿名类型的记录,除非通过函数调用语法或通过hstore。这是不幸的,但不太可能匆忙修复,除非真正关心的人来实现它。还有其他优先事项。
您有三种解决方法选项:
CREATE TYPE
hstore
CREATE TYPE
问题在于匿名类型的记录。所以不要匿名。不幸的是,这只有在它成为匿名记录类型之前才有可能;您目前无法从record
转换为usertype。所以你需要这样做:
CREATE TYPE some_t AS (id integer, cc text);
WITH test AS (
SELECT array_agg(t::some_t) as x FROM (
SELECT 1111 as id, 'aaaaa' as cc
) AS t
) SELECT x[1].id FROM test;
请注意在聚合之前将子查询输出转换为some_t
。
我不能说我理解为什么在索引数组之后无法执行此强制转换。
hstore
像往常一样,hstore
以困难类型的问题为主导救援。
regress=> WITH test AS (
SELECT array_agg(t) as x FROM (
SELECT 1111 as id, 'aaaaa' as cc
) AS t
) SELECT hstore(x[1])->'id' FROM test;
?column?
----------
1111
(1 row)
您需要hstore
扩展程序,我确信它效率不高,但它确实有效。这构建于hstore
支持,用于从匿名记录创建hstore,这些记录已添加到触发器中支持NEW
和OLD
,这是过去的痛点。
事实证明,你无法通过一个简单的包装函数解决它,让你在调用网站上指定类型:
regress=> CREATE OR REPLACE FUNCTION identity(record) RETURNS record AS $$
SELECT $1;
$$ LANGUAGE sql IMMUTABLE;
ERROR: SQL functions cannot have arguments of type record
因此您必须使用更高级的过程语言,此时您也可以使用hstore,它会更快更容易。
所以,这有点难看。永远不可能直接从匿名记录索引字段,因为它可能不存在并且无法推断其类型。但是我们没有理由不能使用允许我们从函数返回record
的类型系统功能,并在调用者端指定其类型以在强制转换中也这样做。
应该可以使PostgreSQL支持如下:
WITH test AS (
SELECT array_agg(t) as x FROM (
SELECT 1111 as id, 'aaaaa' as cc
) AS t
) SELECT (x[1] AS some_t(id integer, cc text)).id FROM test;
它只涉及适当的解析器攻击,并且确保从不与列别名冲突时进行模糊解析。
实际上,如果有人愿意投入工作并说服团队相当大量的查询规划处理器所需的时间是值得的,那么即使是类型推断也是可能的。 (不太可能)。
这是类型系统中一个令人恼火的,但很小的角落。如果你想改变它,你需要在pgsql-general上发出噪音,并伴随着这种噪音,愿意做真正的工作来改善问题。这可能涉及学习比你想知道的更多关于PostgreSQL类型系统内部的知识,学习“向后兼容性”的乐趣,以及围绕和围绕圈子的令人沮丧的争论。欢迎来到开源!