【问题标题】:PostgreSQL v9.X have real "array of record"?PostgreSQL v9.X 有真正的“记录数组”吗?
【发布时间】:2014-01-20 23:24:54
【问题描述】:

这个查询工作正常,

 WITH test AS (
   SELECT array_agg(t) as x FROM (
     SELECT 1111 as id, 'aaaaa' as cc  
   ) AS t
 ) SELECT x[1] FROM test;

但是,我可以访问记录元素吗?我试试SELECT x[1].idSELECT x[1][1]; ...没有任何作用。

PS:对于 Google,我们只看到旧的解决方案...这里的上下文是 v9.X,没有关于“记录数组”的消息?


我也试试

 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 子句的情况下转换或表达类型?

【问题讨论】:

  • 您可以将值转换为hstore 并从中获取字段,但这并不是您真正想要的。 PostgreSQL 的 record 伪类型有点受限 - 特别是,没有匿名记录转换,例如CAST(somerecord AS t(x integer, y text)) 不起作用。
  • 顺便说一句,如果这是您想要的,您需要对此发出声音,并且可能会以愿意做实际工作和/或为开发时间做出贡献的意愿来支持这种声音。这是类型系统的一个角落,没有人真正热衷于处理它,所以你需要足够关心自己来实现它,或者想办法让别人足够关心来处理它。
  • 你有更多的上下文吗?可能还有另一种方法可以到达您需要的地方。
  • 抱歉@Mu,我们不需要“更多上下文”,这是 PostgreSQL 的句法矛盾......我认为 Craig 证实了我对 pg9.X 的欺骗:没有消息。
  • @PeterKrauss 它是开源的。如果您做出贡献,您就是利益相关者 - 无论是帮助列表或此处的人、详细设计、错误搜索和报告、错误修复、代码清理、功能贡献、补丁审查等。我建议您参与并做出贡献想要被听到。 (另外,请不要说“9.x” - 9.0、9.1、9.2,......都是主要版本。是的,这很愚蠢,但我们坚持下去)。你关心这件事——其他人关心双向复制,其他人关心行级安全性和多租户,......制造噪音,被听到,做出贡献。

标签: arrays postgresql record


【解决方案1】:

目前似乎没有任何语法可以访问匿名类型的记录,除非通过函数调用语法或通过 hstore。这很不幸,但除非有真正关心的人出现,否则不太可能匆忙解决。还有其他优先事项。

您有三种解决方法:

  • CREATE TYPE
  • hstore

CREATE TYPE

问题在于匿名类型的记录。所以不要匿名。不幸的是,这只有在它成为匿名记录类型之前才有可能;您目前无法从 record 转换为用户类型。所以你需要这样做:

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 的基础上,该支持已添加以支持触发器中的 NEWOLD,这是过去的痛点。

包装函数?

事实证明,您无法使用简单的包装函数来绕过它,让您在调用站点上指定类型:

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 类型系统的内部知识,学习“向后兼容性”的乐趣,以及围绕着令人沮丧的争论。欢迎开源!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-12
    • 1970-01-01
    • 2010-11-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多