2025年9月25日: PostgreSQL 18 发布!
支持的版本: 当前 (18) / 17 / 16 / 15 / 14 / 13
开发版本: devel
不支持的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3

F.18. intagg — 整数聚合器和枚举器 #

intagg 模块提供了一个整数聚合器和一个枚举器。intagg 现在已经过时,因为内置函数提供了其功能的超集。但是,该模块仍然作为对内置函数的兼容性包装器提供。

F.18.1. 函数 #

聚合器是一个聚合函数 int_array_aggregate(integer),它生成一个包含其接收的整数的整数数组。这是 array_agg 的一个包装器,它对任何数组类型执行相同的操作。

枚举器是一个函数 int_array_enum(integer[]),它返回 setof integer。它本质上是聚合器的逆操作:给定一个整数数组,将其展开为一组行。这是 unnest 的一个包装器,它对任何数组类型执行相同的操作。

F.18.2. 示例用法 #

许多数据库系统都有多对多表的概念。这样的表通常位于两个索引表之间,例如

CREATE TABLE left_table  (id INT PRIMARY KEY, ...);
CREATE TABLE right_table (id INT PRIMARY KEY, ...);
CREATE TABLE many_to_many(id_left  INT REFERENCES left_table,
                          id_right INT REFERENCES right_table);

通常用法如下:

SELECT right_table.*
FROM right_table JOIN many_to_many ON (right_table.id = many_to_many.id_right)
WHERE many_to_many.id_left = item;

这将返回左侧表中某个条目在右侧表中的所有条目。这是 SQL 中一个非常常见的构造。

现在,对于 many_to_many 表中非常多的条目,这种方法可能会很麻烦。通常,这样的连接会为左侧表中特定条目的每个右侧条目导致索引扫描和获取。如果您有一个非常动态的系统,您也无能为力。但是,如果您的数据相当静态,您可以创建一个带有聚合器的摘要表。

CREATE TABLE summary AS
  SELECT id_left, int_array_aggregate(id_right) AS rights
  FROM many_to_many
  GROUP BY id_left;

这将创建一个表,其中左侧项有一行,右侧项有一个数组。现在,如果没有办法使用该数组,这将是无用的;这就是为什么有一个数组枚举器。您可以这样做:

SELECT id_left, int_array_enum(rights) FROM summary WHERE id_left = item;

上面使用 int_array_enum 的查询会产生与以下查询相同的结果:

SELECT id_left, id_right FROM many_to_many WHERE id_left = item;

区别在于,对摘要表的查询只需要从表中获取一行,而直接对 many_to_many 的查询必须为每个条目进行索引扫描和行获取。

在一个系统中,EXPLAIN 显示一个成本为 8488 的查询被降低到成本 329。原始查询是涉及 many_to_many 表的连接,该连接被替换为:

SELECT id_right, count(id_right) FROM
  ( SELECT id_left, int_array_enum(rights) AS id_right
    FROM summary
    JOIN (SELECT id FROM left_table
          WHERE id = item) AS lefts
    ON (summary.id_left = lefts.id)
  ) AS list
  GROUP BY id_right
  ORDER BY count DESC;

提交更正

如果您在文档中看到任何不正确、与您对特定功能的经验不符或需要进一步澄清的内容,请使用 此表格 报告文档问题。