SQL Challenge - 'aggregating columns into grouped rows'

  • I'm trying to do something quite odd which may ring alarm bells. Anyway I've a table like this:

    Key Value1 Value2 Value3

    1 a b c

    1 d e f

    1 g h i

    2 j k l

    2 m n o

    2 p q z

    I want a resultset in the format

    Key Values

    1 abc;def;ghi

    2 jkl;mno;pqz

    I can do this procedurally with a cursor but I'm trying to avoid the use of cursors. Anyone got any clever ways of achieving this?

    Thanks,

    Andrew

  • Hi,

    I Don't have sql server right now but you can achive this using coleasce

    read this blog http://sqlservercoollinks.blogspot.com/2009/05/returning-comma-seperated-values-in-sql.html

    Declare @vComma Varchar(max);

    Select @vComma = COALESCE(@vComma+';','') + column1+Column2+column3 from table1

    select @vComma

  • That's a great start. Thanks.

    This statement 'serializes' the whole table. I need to be able to have one serialization per key field, if that makes sense.

    I.e.

    1 abc;def;ghi

    2 jkl;mno;pqz

    at the moment all I can get is abc;def;ghi;jkl;mno;pqz

    Any ideas how I can split my resultset in this way?

    Andrew

  • You can use a function to get this working

    IF (SELECT OBJECT_ID('tempTable')) IS NOT NULL

    DROP TABLE tempTable

    GO

    CREATE TABLE tempTable (test int, test2 VARCHAR(10))

    INSERT INTO tempTable VALUES (1, 'Test')

    INSERT INTO tempTable VALUES (2, 'Test2')

    INSERT INTO tempTable VALUES (3, 'Test3')

    INSERT INTO tempTable VALUES (4, 'Test4')

    INSERT INTO tempTable VALUES (1, 'Test5')

    INSERT INTO tempTable VALUES (2, 'Test6')

    INSERT INTO tempTable VALUES (3, 'Test7')

    INSERT INTO tempTable VALUES (4, 'Test8');

    GO

    IF (SELECT OBJECT_ID('testCombiningRows')) IS NOT NULL

    DROP FUNCTION testCombiningRows

    go

    CREATE FUNCTION [dbo].[testCombiningRows]

    (

    @test-2 int

    )

    RETURNS VARCHAR(100)

    AS

    BEGIN

    DECLARE @temp AS VARCHAR(100)

    SELECT @temp = COALESCE(@temp+',','')+[test2] FROM tempTable

    WHERE test = @test-2

    RETURN @temp

    END

    GO

    SELECT test, dbo.testCombiningRows(test) AS commaSeparated

    FROM tempTable

    GROUP BY test

    You will have to change it based on your primary key but this should get you going.

  • Next time pleas create a small script that creates that table and insert the test data into it. This will save some time for anyone that wants to show you how to do what you asked.

    The code bellow shows one way of doing it. The code takes advantage of the for xml clause. When you use the for xml clause, you get back one column in one row only. Because of this I can use the correlated sub query in the select clause. The empty string that I have after the I specify the path mode, causes the XML not to have an element name (you can play with to see how it works)

    use tempdb

    go

    --Creating the table

    create table demo (RoKkey tinyint, value1 char(1), value2 char(1), value3 char(1))

    go

    --Inserting the data

    insert into demo (RoKkey, value1, value2, value3)

    select 1, 'a', 'b', 'c'

    union

    select 1, 'd', 'e', 'f'

    union

    select 1, 'g', 'h', 'i'

    union

    select 2, 'j', 'k', 'l'

    union

    select 2, 'm', 'n', 'o'

    union

    select 2, 'p', 'q', 'r'

    go

    select distinct RoKkey, (select value1 + value2 + value3 + ';'

    from demo as InnerDemo

    where InnerDemo.RoKkey = Demo.RoKkey

    for xml path(''))

    from demo

    go

    drop table demo

    Adi

    --------------------------------------------------------------
    To know how to ask questions and increase the chances of getting asnwers:
    http://www.sqlservercentral.com/articles/Best+Practices/61537/

    For better answers on performance questions, click on the following...
    http://www.sqlservercentral.com/articles/SQLServerCentral/66909/

  • Hi,

    Reference: http://www.sqlyoga.com/2009/02/sql-server-get-comma-separated-list.html

    Tejas

    Tejas Shah

  • Look at my solution on this thread:

    CLicky

  • Many thanks to all. I plumped for the XML variant in the end as it fits my existing stored procedure quite nicely.

    Cheers,

    Andrew

  • A slightly different version of the XML, if you want to get rid of that nagging semicolon at the end. Put the semicolons in front and then use STUFF to get rid of the first character of each string.

    if OBJECT_ID(N'tempdb..#temp') is not null drop table #temp

    create table #temp (pk int, Value1 char(1), Value2 char(1), Value3 char(1))

    insert into #temp

    select 1, 'a', 'b', 'c' union all

    select 1, 'd', 'e', 'f' union all

    select 1, 'g', 'h', 'i' union all

    select 2, 'j', 'k', 'l' union all

    select 2, 'm', 'n', 'o' union all

    select 2, 'p', 'q', 'z'

    select * from #temp

    select PK,stuff((SELECT ';' + value1+value2+value3

    FROM #temp t2

    WHERE t2.PK = t1.PK -- must match GROUP BY below

    ORDER BY value1+value2+value3

    FOR XML PATH('')

    ),1,1,'') as [Concatenated]

    from #temp t1

    GROUP BY pk -- without GROUP BY multiple rows are returned

    ORDER BY pk

    __________________________________________________

    Against stupidity the gods themselves contend in vain. -- Friedrich Schiller
    Stop, children, what's that sound? Everybody look what's going down. -- Stephen Stills

Viewing 9 posts - 1 through 8 (of 8 total)

You must be logged in to reply to this topic. Login to reply