简体   繁体   English

postgres-具有数组值的数据透视查询

[英]postgres - pivot query with array values

Suppose I have this table: 假设我有这张桌子:

Content
+----+---------+
| id |  title  |
+----+---------+
| 1  | lorem   |
+----|---------|

And this one: 还有这个:

Fields
+----+------------+----------+-----------+
| id | id_content |   name   |   value   |
+----+------------+----------+-----------+
| 1  |      1     | subtitle |   ipsum   |
+----+------------+----------+-----------|
| 2  |      1     |   tags   |   tag1    |
+----+------------+----------+-----------|
| 3  |      1     |   tags   |   tag2    |
+----+------------+----------+-----------|
| 4  |      1     |   tags   |   tag3    |
+----+------------+----------+-----------|

The thing is: i want to query the content, transforming all the rows from "Fields" into columns, having something like: 事情是:我想查询内容,将“字段”中的所有行转换为列,其内容类似于:

+----+-------+----------+---------------------+
| id | title | subtitle |        tags         |
+----+-------+----------+---------------------+
|  1 | lorem | ipsum    | [tag1,tag2,tag3]    |
+----+-------+----------+---------------------|

Also, subtitle and tags are just examples. 另外,字幕和标签只是示例。 I can have as many fields as I desired, them being array or not. 我可以根据需要设置任意多个字段,无论是否为数组。

But I haven't found a way to convert the repeated "name" values into an array, even more without transforming "subtitle" into array as well. 但是我还没有找到一种将重复的“名称”值转换为数组的方法,甚至还没有将“字幕”转换为数组的方法。 If that's not possible, "subtitle" could also turn into an array and I could change it later on the code, but I needed at least to group everything somehow. 如果不可能的话,“字幕”也可以变成一个数组,我可以稍后在代码上更改它,但是我至少需要以某种方式对所有内容进行分组。 Any ideas? 有任何想法吗?

You can use array_agg , eg 您可以使用array_agg ,例如

SELECT id_content, array_agg(value)
FROM fields
WHERE name = 'tags'
GROUP BY id_content

If you need the subtitle, too, use a self-join. 如果您也需要字幕,请使用自连接。 I have a subselect to cope with subtitles that don't have any tags without returning arrays filled with NULLs, ie {NULL} . 我有一个subselect来应付没有任何标签的字幕,而不会返回填充有NULL的数组,即{NULL}

SELECT f1.id_content, f1.value, f2.value
FROM fields f1
LEFT JOIN (
    SELECT id_content, array_agg(value) AS value
    FROM fields
    WHERE name = 'tags'
    GROUP BY id_content
) f2 ON (f1.id_content = f2.id_content)
WHERE f1.name = 'subtitle';

See http://www.postgresql.org/docs/9.3/static/functions-aggregate.html for details. 有关详细信息,请参见http://www.postgresql.org/docs/9.3/static/functions-aggregate.html

If you have access to the tablefunc module, another option is to use crosstab as pointed out by Houari. 如果可以访问tablefunc模块,则另一种选择是使用Houari指出的crosstab You can make it return arrays and non-arrays with something like this: 您可以使用以下方法使其返回数组和非数组:

SELECT id_content, unnest(subtitle), tags
FROM crosstab('
    SELECT id_content, name, array_agg(value)
    FROM fields
    GROUP BY id_content, name
    ORDER BY 1, 2
') AS ct(id_content integer, subtitle text[], tags text[]);

However, crosstab requires that the values always appear in the same order. 但是, crosstab要求值始终以相同顺序出现。 For instance, if the first group (with the same id_content ) doesn't have a subtitle and only has tags, the tags will be unnested and will appear in the same column with the subtitles. 例如,如果第一组(具有相同的id_content )没有字幕,而只有标签,则标签将被取消嵌套,并与字幕显示在同一列中。

See also http://www.postgresql.org/docs/9.3/static/tablefunc.html 另请参见http://www.postgresql.org/docs/9.3/static/tablefunc.html

If the subtitle value is the only "constant" that you wan to separate, you can do: 如果subtitle值是您要分隔的唯一“常量”,则可以执行以下操作:

SELECT * FROM crosstab
(
  'SELECT content.id,name,array_to_string(array_agg(value),'','')::character varying FROM content    inner join 
    (
    select * from fields where fields.name = ''subtitle''  
        union all  
    select * from fields where fields.name <> ''subtitle'' 
    ) fields_ordered 
   on fields_ordered.id_content = content.id   group by content.id,name'
)
AS
(
       id integer,
       content_name character varying,
       tags character varying
);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM