简体   繁体   中英

Postgres: string aggregation and concatenation

If I have a query like this:

SELECT 
    u.client_code, 
    max(d.created_at) as last_document_created_at, 
    u.brand_id, 
    t.name as template_name, 
    count(d)
FROM users u
    INNER JOIN documents d ON u.id = d.user_id
    INNER JOIN templates t ON t.id = d.template_id
GROUP BY 1, 3, 4

Which returns information like this:

client_code last_document_created_at    brand_id template_name  count
---------------------------------------------------------------------
client1     2017-12-06 10:03:47 +1100   39       newsletter_r   1
client1     2017-12-05 15:23:24 +1100   39       Other media    5
client2     2017-12-21 17:07:11 +1100   39       newsletter_r   4
client3     2018-01-11 12:10:43 +1100   39       newsletter_r   2
client3     2017-12-06 11:45:21 +1100   39       Other media    1

What are my options to concatenate the template_name and count fields so that each user (represented in u.client_code ) is on one line? I know I can call string_agg the column like so:

...
string_agg(distinct t.name, ', ') as template_name, 
...

But that of course ruins the respective counts:

newsletter_r, Other media   6

Update

I could do this:

string_agg(concat_ws(': ', t.name::text, count(d)::text), ', ') as template_count

But that gives me an error:

aggregate function calls cannot be nested LINE 5: string_agg(concat_ws(': ', t.name::text, count(d)::text)... ^ : SELECT u.client_code,

Not sure how you want to format your concatenated field, but have you tried putting your original query into a sub-query and applying a string_agg to it? Something like this:

SELECT client_code, STRING_AGG(template_name || template_count, ',') 
FROM (
    SELECT 
        u.client_code, 
        MAX(d.created_at) AS last_document_created_at, 
        u.brand_id, 
        t.name AS template_name, 
        COUNT(d) AS template_count
    FROM users u
    INNER JOIN documents d ON u.id = d.user_id
    INNER JOIN templates t ON t.id = d.template_id
    GROUP BY 1, 3, 4
) src
GROUP BY client_code

I haven't tested it, so you may have some syntax errors. Let me know if that works.

I think you want something like this:

SELECT u.client_code, 
       max(d.created_at) as last_document_created_at, 
       u.brand_id, 
       string_agg(t.name, ',') as template_name, 
       count(distinct d.id)
FROM users u INNER JOIN
     documents d
     ON u.id = d.user_id INNER JOIN
     templates t
     ON t.id = d.template_id
GROUP BY 1, 3;

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