0

I am looking to merge all the columns based on similar specific column value.

Suppose i have similar values in "DeckName" , so using Column2 i am looking out to merge all the distinct other column values into one .

Input Table :

DeckId     DeckName   Location   Items     Places   UserName

XK001      NOVA        USA       Cream     ASIA-P   NOVA001
XK002      NOVA        IND       DEO       AFRICA   NOVA002
XK001      NOVA        USA       Cosmetic  ASIA-P   NOVA003
VK001      VEET        RUS       PROFIX    UK       VEET001
VK003      VEET        CHI       Cream     ASIA-P   VEET002
VK002      VEET        NED       WAX       RUSSIA   VEET001
NS001      PHLIPS      USA       Cream     ASIA-P   PHLPS001
PS001      RUDS        USA       Cream     ASIA-P   VLT001

Expected Output Table Value

 DeckId                DeckName   Location       Items                 Places              UserName
XK001; XK002           NOVA       USA; IND       Cream; DEO; Cosmetic  ASIA-P; AFRICA      NOVA001; NOVA002; NOVA003
VK001; VK003; VK002    VEET       RUS; CHI; NED  PROFIX; Cream; WAX    UK; ASIA-P; RUSSIA  VEET001; VEET002
NS001                  PHLIPS     USA            Cream                 ASIA-P              PHLPS001
PS001                  RUDS       USA            Cream                 ASIA-P              VLT001

Please Suggest a query to find proceed with the expected outcome :

Manz
  • 593
  • 5
  • 23
  • 2
    Please only tag the RDBMS you are *really* using. Though there are *plenty* of examples on how to aggregate strings in both SQL Server and MySQL if you have a quick search. What about the 1,000's of examples didn't you understand? What were your attempt(s)? Why didn't they work? – Thom A Dec 23 '21 at 14:06
  • which database you are using here ? Oracle syntax will be different then SQL Server – NNM Dec 23 '21 at 14:11
  • @NNM - I am using SQL server Database – Manz Dec 23 '21 at 14:11
  • Also, I *really* hope DeckID is not a key – Alan Dec 23 '21 at 14:12
  • @Alan - Yes DeckID is not a key – Manz Dec 23 '21 at 14:14
  • @Larnu - I have tried using samples from "https://www.mssqltips.com/sqlservertip/2914/rolling-up-multiple-rows-into-a-single-row-and-column-for-sql-server-data/", But didn't worked – Manz Dec 23 '21 at 14:17
  • What version of SQL Server, @Manz >? – Thom A Dec 23 '21 at 14:18
  • @Larnu I have been using SQL Server 2014 – Manz Dec 23 '21 at 14:24
  • Blargh... This will be a pain in SQL Server 2014; no `STRING_AGG` support. It's going to require *multiple* `FOR XML PATH` subqueries and thus unlikely to be performant. Why do you want a denormalised result set in the first place? – Thom A Dec 23 '21 at 14:26
  • Does this answer your question? [String_agg for SQL Server before 2017](https://stackoverflow.com/questions/49361088/string-agg-for-sql-server-before-2017) – Thom A Dec 23 '21 at 14:28

2 Answers2

2

Are you trying something like :

select STRING_AGG(DeckId,';') as DeckId , 
       DeckName , 
       STRING_AGG(Location,';') as Location,
       STRING_AGG(Items,';') as Items,
       STRING_AGG(Places,';') as Places,
       STRING_AGG(UserName,';') as UserName
from  test_tbl
group by DeckName;

Demo: https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=ece626d2ce2919c2148cccbe83e4634e

Check for more info: https://learn.microsoft.com/en-us/sql/t-sql/functions/string-agg-transact-sql?view=sql-server-ver15

For Older SQL Server Version , maybe not the best solution but you can try:

SELECT DISTINCT ST2.DeckName, 
    SUBSTRING(
        (
            SELECT ';'+DeckId  AS [text()]
            FROM test_tbl ST1
            WHERE ST1.DeckName = ST2.DeckName
            FOR XML PATH (''), TYPE
        ).value('text()[1]','nvarchar(max)'), 2, 9999) [DeckId],
        
      SUBSTRING(
        (
            SELECT ';'+Location  AS [text()]
            FROM test_tbl ST1
            WHERE ST1.DeckName = ST2.DeckName
            FOR XML PATH (''), TYPE
        ).value('text()[1]','nvarchar(max)'), 2, 9999) [Location]  ,
        
      SUBSTRING(
        (
            SELECT ';'+Items  AS [text()]
            FROM test_tbl ST1
            WHERE ST1.DeckName = ST2.DeckName
            FOR XML PATH (''), TYPE
        ).value('text()[1]','nvarchar(max)'), 2, 9999) [Items]  , 
        
      SUBSTRING(
        (
            SELECT ';'+Places  AS [text()]
            FROM test_tbl ST1
            WHERE ST1.DeckName = ST2.DeckName
            FOR XML PATH (''), TYPE
        ).value('text()[1]','nvarchar(max)'), 2, 9999) [Places]  ,
        
     SUBSTRING(
        (
            SELECT ';'+UserName  AS [text()]
            FROM test_tbl ST1
            WHERE ST1.DeckName = ST2.DeckName
            FOR XML PATH (''), TYPE
        ).value('text()[1]','nvarchar(max)'), 2, 9999) [UserName]  
        
FROM test_tbl ST2

Demo: https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=53aef222b43a50f6e4874e3b307a018b

Ergest Basha
  • 7,870
  • 4
  • 8
  • 28
  • 1
    I'd recommend the usage of `STUFF` to remove the leading separator over `SUBSTRING`. This'll lead to truncation for values over 1000 characters (`STUFF` would not). – Thom A Dec 23 '21 at 14:36
  • @Ergest Basha - Thanks for the answer but similar column values are also getting separated for DeckID, Items and other columns. Any solution for it. – Manz Dec 23 '21 at 14:48
  • @Manz and if you add distinct like in this fiddle : https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=198f417f2d4df3f953f813dd5b0c0a8a ? – Ergest Basha Dec 23 '21 at 16:33
0

Which version of SQL server are you using ?

you can use string_agg function in sql server (same as listagg in Oracle) if you are using 2017 and above. Something like below -

select deck_name, 
        STRING_AGG(deck_id, ';') within group(order by deck_name) as deck_id,
        STRING_AGG(Location, ';') within group(order by deck_name) as location,
        STRING_AGG(items, ';') within group(order by deck_name) as items,
        STRING_AGG(places, ';') within group(order by deck_name) as place,
        STRING_AGG(username, ';') within group(order by deck_name) as username
from deck_table dt
group by deck_name

for older version, you will have to use the STUFF function with XML path. I cant run it and you may have to play around with the XML expression, but you can try something like below -

select deck_name, 
        STUFF((
       SELECT distinct ';' + dt1.deck_id
         FROM deck_table dt1
        WHERE dt1.deck_name = dt.deck_name
        ORDER BY dt1.deck_id
          FOR XML PATH('')), 1, LEN(','), '') AS deck_id,
          STUFF((
       SELECT distinct ';' + dt1.location
         FROM deck_table dt1
        WHERE dt1.deck_name = dt.deck_name
        ORDER BY dt1.location
          FOR XML PATH('')), 1, LEN(','), '') AS location,
          STUFF((
       SELECT distinct ';' + dt1.items
         FROM deck_table dt1
        WHERE dt1.deck_name = dt.deck_name
        ORDER BY dt1.items
          FOR XML PATH('')), 1, LEN(','), '') AS items,
          STUFF((
       SELECT distinct ';' + dt1.place
         FROM deck_table dt1
        WHERE dt1.deck_name = dt.deck_name
        ORDER BY dt1.place
          FOR XML PATH('')), 1, LEN(','), '') AS place,
          STUFF((
       SELECT distinct ';' + dt1.username
         FROM deck_table dt1
        WHERE dt1.deck_name = dt.deck_name
        ORDER BY dt1.username
          FOR XML PATH('')), 1, LEN(','), '') AS username
from deck_table dt
group by deck_name
NNM
  • 358
  • 1
  • 10
  • Thanks for the Answer , But i am using SQL Server version 2014, As STRING_AGG is not applicable in it , any other method to solve it – Manz Dec 23 '21 at 14:34
  • i have updated my answer with STUFF function. – NNM Dec 23 '21 at 14:57
  • Thanks for the suggestion but similar column values are also getting separated for DeckID, Items and other columns. For Eg For Column DeckID - XK001; XK002;XK001 instead of XK001; XK002 Any Suggestion for it – Manz Dec 23 '21 at 14:59
  • you should be able to distinct in STUFF like - SELECT distinct ';' + dt1.deck_id. I will update in the query too – NNM Dec 23 '21 at 15:01
  • Getting the error " Msg 145, Level 15, State 1, Line 16 ORDER BY items must appear in the select list if SELECT DISTINCT is specified. " – Manz Dec 23 '21 at 15:04
  • updated the order by to use the column in STUFF function call, you can remove the order by clause too. it will just not sort your values, if thats not an issue – NNM Dec 23 '21 at 15:07
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/240389/discussion-between-nnm-and-manz). – NNM Dec 23 '21 at 15:15