简体   繁体   中英

Nested grouping of rows in PostgreSQL

I have the following "Transactions" table in PostgreSQL 11:

    |=====================|==================|==================|===========================|
    |        owner        |      amount      |     category     |        timestamp          |
    |=====================|==================|==================|===========================|
    |        robb         |        34        |       food       |  2020-01-30 18:30:00+00   |
    |---------------------|------------------|------------------|---------------------------|
    |        ned          |       1500       |      travel      |  2020-03-15 15:00:00+00   |
    |---------------------|------------------|------------------|---------------------------|
    |        jon          |        56        |     equipment    |  2020-01-01 11:30:00+00   |
    |---------------------|------------------|------------------|---------------------------|
    |        petyr        |        78        |       food       |  2020-06-29 14:30:00+00   |
    |---------------------|------------------|------------------|---------------------------|

My final goal is to get an object in my webservice (NodeJS) of the following schema:

{
  "food": {
    "2020-01-01": [...], // Array of Rows (JSON) that have category = "food" and timestamp within Jan-20
    "2020-06-01": [...] // Array of Rows (JSON) that have category = "food" and timestamp within Jun-20
  },
  "travel": {
    "2020-03-01": [...] // Array of Rows (JSON) that have category = "travel" and timestamp within Mar-20
  },
  "equipment": {
    "2020-01-01": [...] // Array of Rows (JSON) that have category = "equipment" and timestamp within Jan-20
  }
}

I am no expert in SQL, but I reckon it will require the following two steps:

  1. Group the rows in the table by category.
  2. Now, take each group formed in point 1, and group the rows inside it by time interval truncated to month.

I am aware of only the basics of SQL and PostgreSQL. I was able to group the rows individually by category and interval using the following two queries:

  1. Grouping by category:

    SELECT category, JSON_AGG(ROW_TO_JSON("Transactions")) as results FROM "Transactions" GROUP BY category;

  2. Grouping by time interval:

    SELECT date_trunc('month', timestamp) as interval, JSON_AGG(ROW_TO_JSON("Transactions")) as results FROM "Transactions" GROUP BY interval;

But how to combine these two queries and produce a result like the JSON object I've mentioned above?

Use two levels of aggregation. I think you want:

SELECT category,
       JSON_AGG(JSON_BUILD_OBJECT(interval, results))
FROM (SELECT category,
             date_trunc('month', timestamp) as interval,
             JSON_AGG(ROW_TO_JSON("Transactions")) as results
      FROM "Transactions"
      GROUP BY category, interval
     ) i
GROUP BY category;

SELECT category,JSON_AGG(JSON_BUILD_OBJECT(interval, results)) FROM (SELECT category,date_trunc('month', timestamp) as interval,JSON_AGG(ROW_TO_JSON(txn)) as results FROM txn GROUP BY category,timestamp having (category='food' AND timestamp<'2020-02-01') OR (category='food' AND timestamp<'2020-07-01') OR (category='travel' AND timestamp<'2020-04-01') OR (category='equipment' AND timestamp<'2020-02-01')) i GROUP BY category;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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