微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Postgresql 交叉表:可变数量的列,所有一种类型

如何解决Postgresql 交叉表:可变数量的列,所有一种类型

我知道这不是第一个“动态交叉表列”问题,但我的具体情况有点不同。

我正在为我的公司设计库存架构,crosstab 似乎是为其生成人类可读摘要的最便捷方式。有很多产品类型不能都放在同一张表中,所以我选择了这样的模式:

  • vendor_products 表,具有唯一的 product_id 列和 product_type
  • 具有 inventory 和 bigserial product_id 列(代表产品实例)的中央 unique_id
  • 一个单独的 attribute_types 表,其中包含 attr_idattr_name 列 - 可以附加到产品实例的任何内容(颜色、mac 地址、序列号等...)进入这里
  • 结合 device_attributesinventory 表的 attribute_types 表。它有 3 列:unique_idattr_idattr_value(pkey 是 unique_id + attr_id)。这是将多个 attr_id 及其值映射到相关 unique_id 的地方。看起来像:
unique_id attr_id attr_value
u_1 1(颜色) 蓝色
u_1 2 (serial#) 1234567
u_2 1(颜色) 黑色
u_2 2 (serial#) 7654321

这种设计的结果是所有 attr_value 都是 varchars。

假设所有正确的外键都在那里。

现在,我想使用 crosstab() 从这个设计中得到一个人类可读的表格,以查看产品类型的所有实例。程序是:

  1. 使用 inventory.product_idvendor_products.product_type 进行子查询
  2. 获取inventory.unique_ids的结果集
  3. 使用unique_id的集合获取device_attributes表中的匹配信息并将其交叉表

device_attributes 表已经是函数所需的确切输入形式。标题标题是已知的 - 它们是 attr_name,对应于附加到产品子集的唯一一组“attr_id”。

唯一的问题是列数会随 product_type 的不同而变化。我发现这个 answer 表明如果可以在执行时给出列的返回类型(第一个建议),则可以制作动态 crosstab 表。如前所述,每一列都是一个 varchar。唯一的问题是为从当前 attr_name 派生的函数提供一种格式,每个函数都附加了一个 varchar。虽然引用的问题表明这是可能的,但它没有链接到实现。

您可以在下面看到我的尝试,“不存在列“product_subset”的错误”,我不知道为什么。 (到现在为止我从来没有做过函数,所以请原谅我的次优设计。我知道这很糟糕)。

是否可以挽救此功能,或者在 Postgres 中是否有另一种方法可以做到这一点?我之所以提出这个问题,是因为我还没有找到关于 crosstab 使用这种类型的架构结构的问题,但我觉得它最有可能奏效。

编辑:稍微修正了该函数,但似乎给定的表类型需要看起来像输出内容。想知道是否可以在父函数中构造表类型并将其传递给下面的函数

如果没有,那么我将在后端实现所需的逻辑。非常感谢任何帮助/帮助!

CREATE OR REPLACE FUNCTION getProducts(tbltype anyelement,_id integer)
  RETURNS SetoF anyelement
  LANGUAGE plpgsql AS
$func$
DECLARE
   _cols text := 'id bigint,';
BEGIN
    CREATE temporary table product_subset AS (
        SELECT * FROM device_attributes
        WHERE unique_id IN
            (SELECT unique_id FROM inventory
                WHERE product_id IN
                    (SELECT product_id FROM vendor_products
                        WHERE type_id IN (_id)
                    )
            )
        );
        
    _cols := _cols || ( SELECT string_agg(attrt.attr_name,' varchar,') 
                        FROM attribute_types AS attrt
                           WHERE 
                               attrt.attr_id IN (SELECT disTINCT ps.attr_id FROM product_subset AS ps)
                );
    _cols := _cols || ' varchar';
    raise notice 'Cols: ',_cols; -- For debugging
   RETURN QUERY EXECUTE '
      SELECT *
        FROM crosstab(
            ''SELECT
                ps.unique_id,ps.attr_id,ps.value 
            FROM
                product_subset AS ps
            ORDER BY 1''
    ) AS ct (' || _cols || ')';
END
$func$;

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。