1

What I have:

Two postgres tables, one with data, one with groups to aggregate. Both tables can be changes, e.g. its planed to add locations later on and also define new categories.

locations:
| id | zipcode | name    | type   |
|----+---------+---------+--------|
|  1 |    1234 | Burger1 | burger | 
|  2 |    1234 | Burger2 | burger |
|  3 |    1234 | Gas1    | gas    |
|  4 |    5678 | FriesA  | fries  |
|  5 |    9876 | FriesB  | fries  |
|  6 |    9876 | GarageA | garage |

categories:
| category | item   |
|----------+--------|
| food     | burger | 
| food     | fries  |
| car      | gas    | 
| car      | garage | 

What I expect to get: The number of facilities per zip-code, aggregated by given categories:

result:
| zipcode | cnt(food) | cnt(car) |
|---------+-----------+----------|
|    1234 |         2 |        1 | 
|    5678 |         1 |          |
|    9876 |         1 |        1 |

What I tried: Pivot the table using postgres' crosstab()-function: (see https://www.postgresql.org/docs/current/static/tablefunc.html#AEN186219).

Unfortunately crosstab() returntype is record, so you need to define explicit column definitions. To allow categories to be added later, I'm trying to get the column definition list from a query:

SELECT * FROM crosstab(
    'SELECT location.zipcode, categories.category, count(location.id)
    FROM locations
    JOIN categories
    ON categories.item = location.type
    GROUP BY zipcode, categories.category'
    ,
    'SELECT DISTINCT category FROM categories ORDER BY category ASC;')
AS
    ct(
        SELECT array_to_string(
            array_cat(
                array(SELECT 'zipcode varchar'::varchar),
                array(SELECT DISTINCT (category || ' int')::varchar AS category FROM categories ORDER BY category ASC)
            ),
        ', '
        )
    );

Whats the problem

Postgres won't accept a query as column definition list. If possible, I want to avoid using PL\pgSQL-functions but only "regular" querys:

ERROR:  syntax error at or near »select«
LINE 16:   select array_to_string(
           ^
4

1 回答 1

0
select zipcode, jsonb_object_agg(category, total)
from (
        select zipcode, category, count(*) as total
        from
            locations l
            inner join
            categories c on l.type = c.item
        group by zipcode, category
    ) a
    right join (
        (select distinct category from categories) c
        cross join
        (select distinct zipcode from locations) l
    ) dc using (zipcode, category)
group by zipcode
;
 zipcode |     jsonb_object_agg     
---------+--------------------------
    9876 | {"car": 1, "food": 1}
    5678 | {"car": null, "food": 1}
    1234 | {"car": 1, "food": 2}
于 2017-08-17T11:51:20.917 回答