2

我有一些有效组织的表,如本例所示:

基本架构

从广义上讲,有许多“资产”拥有多对多的键/值对列表,其形式为带有名称和值的“标签”。每个资产可以有任何标签子集,每个资产的每个标签都有一个值。

如果只是简单地转储显示资产、标签名称和标签值的数据,您最终可能会得到如下结果:

数据,但不是我想要的

但是,我实际上想要组织数据的方式是这样的:

现在看起来好多了

是否有可能,使用这个模式,而不是能够在这个方法中选择数据? 实际上,这涉及将标签表中的每个条目转换为一列,然后在适用的情况下使用与每个资产的该标签关联的值填充这些列中的每一列。

这个问题有完全相同的问题,但我不能接受,原因如下:

  1. 这是关于 Oracle,而我正在使用PostgreSQL
  2. 所有给定的答案都求助于引用特定数据名称的硬编码查询,而我要求我的答案可以动态地处理任何数据
  3. 它根本没有足够的视图。浏览了 37 次?我不相信任何真正的专家曾经看到过这一点。

此外,这种数据选择是否有名称?我相信这是一个抽象而普遍的问题,但我不知道它会叫什么。

4

1 回答 1

1

这种设计模式有时称为实体属性值 (EAV)。您可以动态创建所需的查询,尽管这有点费力。我不确定有没有办法返回匿名表类型,所以我不得不创建一个函数来创建一个函数:

Create or replace function generatecrosstab() returns void as $BODY$
Declare
    sql varchar := '';
    type varchar := '(assetid int, ';
    sep varchar := '';
    tagid int;
    tname varchar(50);
Begin
    for tagid, tname in select id, tagname from tag order by id
    loop
        sql := sql || sep || 'max(case tagid when ' 
            || tagid::varchar || ' then tagvalue end) ' || tname;
        type := type || sep || tname || ' varchar(255)';
        sep := ', ';
    end loop;
    type := type || ')';
    sql = 'create or replace function crosstab() returns table ' 
       || type || ' as $$' 
       || ' select assetid, ' || sql
       || ' from assettag group by assetid order by assetid;'
       || ' $$ Language sql;';
    execute sql;
End;
$BODY$ Language plpgsql;

如果您执行此功能,例如:

select generatecrosstab(); 

它将创建一个函数 crosstab() ,您可以从中选择:

Select * From crosstab();

tablefunc 模块有一些可以简化事情的函数。

SQLFiddle Example

于 2013-11-01T23:51:18.003 回答