我有一些有效组织的表,如下例所示:
从广义上讲,有许多“资产”拥有带有名称和值的“标签”形式的多对多键/值对列表。每个资产都可以包含任何标记子集,每个资产的每个标记都有一个值。
如果只是转储显示资产,标记名称和标记值的数据,您可能会得到如下结果:
但是,我实际上想要组织数据的方式是这样的:
使用此架构是否有可能在此方法中选择数据?实际上,这涉及转换标签表中的每个条目并将其转换为列,然后填充在适当的每个列中,每个列中都包含与该标记相关联的值。
This question有完全相同的问题,但由于以下原因,我无法接受:
此外,是否有此类数据选择的名称?我认为这是一个抽象的普遍问题,但我不知道它会被称为什么。
答案 0 :(得分: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();
它将创建一个函数交叉表(),您可以从中选择:
Select * From crosstab();
tablefunc module有一些功能可以简化事情。
<强> SQLFiddle Example 强>