Search code examples
sqlsql-servert-sqlstring-agg

SQL query GROUP BY groups


I have something like this:

id name totalAmount
1 name1 10
2 name1 20
3 name1 25
4 name2 5
5 name2 12

And need to looks like this:

id's name totalAmount
1,2 name1 30
2,3 name1 45
1,3 name1 35
1,2,3 name1 55
4,5 name2 17

I'm using the STRING_AGG but don't know how to separated in the first 3 id's.


Solution

  • Here is a recursive version which can handle more than 3 ids for a name and returns all possible combinations. As Dai points out though, take care as the number of combinations quickly mushrooms. But if your real data is like your example (normally 2-3 ids per name) than it should be fine.

    Worth noting that I did this for fun. Probably you would be best just storing the raw data and doing this kind of shenanigans in the application layer.

    CREATE TABLE #data
    (
        id INT,
        [name] VARCHAR(10),
        totalAmount INT 
    );
    INSERT INTO #data
    VALUES 
    (1, 'name1', 10),
    (2, 'name1', 20),
    (3, 'name1', 25),
    (4, 'name2', 5),
    (5, 'name2', 12);
    
    WITH cte (name, ids, maxid, tot) AS
    (
        SELECT a.name, 
            CONVERT(VARCHAR(8000), CONVERT(VARCHAR(10), a.id) + ',' + CONVERT(VARCHAR(10), b.id) ) AS ids, 
            b.id AS maxid,
            a.totalAmount + b.totalAmount AS tot
        FROM #data a
        INNER JOIN #data b ON b.name = a.name AND a.id < b.id
        UNION ALL
        SELECT cte.name,
            CONVERT(VARCHAR(8000), cte.ids + ',' +CONVERT(VARCHAR(10), a.id)), 
            a.id AS maxid,
            cte.tot + a.totalAmount
        FROM cte
        INNER JOIN #data a ON cte.name = a.name
        WHERE a.id > cte.maxid
    )
    SELECT ids, name, tot
    FROM cte