从列类型开始,如何在Postgres中查找支持的聚合?

时间:2019-08-10 22:58:33

标签: sql postgresql aggregate

我正在尝试从一个列类型中找出来,该类型汇总了数据类型支持的值。类型之间有多种选择,下面只是一个示例(当然其中一些支持更多的聚合):

uuid     count()
text     count(), min(), max()
integer  count(), min, max(),avg(),sum()

我一直在system catalogs and views中苦苦挣扎,但是没有找到我想要的东西。 (请参阅“四处乱动”。)我戳过pg_typepg_aggregatepg_operator等。

有没有一种直接的方法可以从列类型开始并收集所有受支持的聚合?

对于背景,我正在编写一个客户端交叉表代码生成器,当该工具自动阻止您选择不支持的聚合时,UX会更好。我现在已经破解了一些硬编码规则,但是想改进系统。

我们正在使用Postgres 11.4。

4 个答案:

答案 0 :(得分:2)

可用的汇总功能的简单列表可以基于pg_proc,如下所示:

SELECT oid::regprocedure::text AS agg_func_plus_args
FROM   pg_proc
WHERE  prokind = 'a'
ORDER  BY 1;

或具有单独的函数名称和参数:

SELECT proname AS agg_func, pg_get_function_identity_arguments(oid) AS args
FROM   pg_proc
WHERE  prokind = 'a'
ORDER  BY 1, 2;

pg_proc.prokind替换了Postgres 11中的proisagg。在Postgres 10或更早的版本中:

...
WHERE proisagg
...

相关:

要获取每种数据类型可用功能的列表(您的问题),请从以下内容开始:

SELECT type_id::regtype::text, array_agg(proname) AS agg_functions
FROM  (
   SELECT proname, unnest(proargtypes::regtype[])::text AS type_id
   FROM   pg_proc
   WHERE  proisagg
   ORDER  BY 2, 1
   ) sub
GROUP  BY type_id;

db <>提琴here

只需开始。一些参数只是“直接”(非聚合的)(这也是为什么多次列出某些函数的原因-由于这些附加的非聚合列,例如string_agg)。对于“有序集”和“假设集”聚合,有特殊情况。请参阅其他系统目录pg_aggregateaggkindaggnumdirectargs列。 (您可能想排除初学者的特殊情况……)

许多 类型具有隐式强制转换为查询列出的类型之一。突出的示例string_agg()也可以与varchar一起使用,但仅在上面的text中列出。您可以使用pg_cast中的信息来扩展查询,以获取完整图片。

此外,某些聚合适用于pseudo types "any"anyarray等。您需要将每种适用的数据类型都纳入其中。

相同数据类型名称的多个别名的复杂性可以轻松消除,但可以:强制转换为regtype以获取规范名称。或使用pg_typeof()返回标准名称。相关:

答案 1 :(得分:2)

伙计,那真是令人惊叹谢谢。在我不知道这一点之前,宇宙的热死就到了。我不得不为PG 11兼容性而调整一条线...说那位没有说他正在使用哪个版本的家伙。我对查询进行了重新整理,使其接近所要查找的内容,并包含了一些存档输出。

with aggregates as (
SELECT pro.proname aggregate_name,
       CASE
         WHEN array_agg(typ.typname ORDER BY proarg.position) = '{NULL}'::name[] THEN
           '{}'::name[]
         ELSE
            array_agg(typ.typname ORDER BY proarg.position)
       END aggregate_types
       FROM pg_proc pro
            CROSS JOIN LATERAL unnest(pro.proargtypes) WITH ORDINALITY proarg (oid,
                                                                               position) 
            LEFT JOIN pg_type typ
                      ON typ.oid = proarg.oid
       WHERE pro. prokind = 'a' -- I needed this for PG 11, I didn't say what version I was using. 

       GROUP BY pro.oid,
                pro.proname

       ORDER BY pro.proname),

 -- The *super helpful* code above is _way_ past my skill level with Postgres. So, thrashing around a bit to get close to what I'm after.
 -- First up, a CTE to sort everything by aggregation and then combine the types.
aggregate_summary as (
 select aggregate_name,
        array_agg(aggregate_types) as types_array

   from aggregates

 group by 1
   order by 1)

-- Finally, the previous CTE is used to get the details and a count of the types.   
 select aggregate_name,
        cardinality(types_array) as types_count, -- Couldn't get array_length to work here. ¯\_(ツ)_/¯
        types_array

   from aggregate_summary

   limit 5;

还有一点输出:

aggregate_name   types_count    types_array
array_agg        2              {{anynonarray},{anyarray}}
avg              7              {{int8},{int4},{int2},{numeric},{float4},{float8},{interval}}
bit_and          4              {{int2},{int4},{int8},{bit}}
bit_or           4              {{int2},{int4},{int8},{bit}}
bool_and         1              {{bool}}

仍然在我的愿望清单上

  • 弄清楚如何执行数组(我们现在不使用数组字段,只有几个地方可以使用。那时,我不希望我们尝试在数组标签工具

  • 获取各种类型的所有别名。似乎(?)int8等可以通过pg_attribute以多种方式来传递。例如,时间戳可以从“带时区的时间戳”中返回。

这些结果将由客户端代码使用并进行处理,因此我不需要让Postgres在一个查询中找出所有内容,仅够我完成工作。

无论如何,非常非常感谢。

答案 2 :(得分:1)

pg_proc目录表,其中列出了所有功能。 proisagg列标记聚合函数,而proargtypes列包含参数类型的OID数组。

例如,要获取具有其参数类型名称的所有聚合函数的列表,可以使用:

SELECT pro.proname aggregationfunctionname,
       CASE
         WHEN array_agg(typ.typname ORDER BY proarg.position) = '{NULL}'::name[] THEN
           '{}'::name[]
         ELSE
            array_agg(typ.typname ORDER BY proarg.position)
       END aggregationfunctionargumenttypes
       FROM pg_proc pro
            CROSS JOIN LATERAL unnest(pro.proargtypes) WITH ORDINALITY proarg (oid,
                                                                               position) 
            LEFT JOIN pg_type typ
                      ON typ.oid = proarg.oid
       WHERE pro.proisagg
       GROUP BY pro.oid,
                pro.proname
       ORDER BY pro.proname;

当然,您可能需要扩展它,例如加入并尊重模式(pg_namespace)并检查pg_type中的兼容类型(为此请查看typcategory列),等等。


编辑:

我忽略了proisagg在版本11中被删除(我仍然主要使用9.6),其他提到的答案。因此,出于完整性考虑:从版本11开始,将WHERE pro.proisagg替换为WHERE pro.prokind = 'a'

答案 3 :(得分:0)

我一直在讨论建议,并希望根据Erwin的一种脚本发布一种改编:

select type_id::regtype::text as type_name,
       array_agg(proname) as aggregate_names

from  (
       select proname, 
              unnest(proargtypes::regtype[])::text AS type_id
         from pg_proc
        where prokind = 'a'
     order by 2, 1
   ) subquery

  where type_id in ('"any"', 'bigint', 'boolean','citext','date','double precision','integer','interval','numeric','smallint',
                    'text','time with time zone','time without time zone','timestamp with time zone','timestamp without time zone')

group by type_id;

这将带回有关where子句中指定的类型的详细信息。这不仅对我当前的工作有用,而且对我的一般理解也很有用。我遇到了一些情况,我必须重新铸造某些东西,例如将整数转换为双精度,以使其能够与聚合一起使用。到目前为止,这几乎是反复试验。如果运行上面的查询(或类似的查询),则从输出中更容易看到需要在类似外观类型之间进行重铸的地方。