-2

I Have one table with column values like Below -

Table1

id Key_value
1  1|2|3
2  1|3|2

Table2

id  Name
1   A
2   B
3   C

I need output of Table1 like

Id  key_value

1   A,B,C
2   A,C,B
GMB
  • 216,147
  • 25
  • 84
  • 135
Mukund
  • 1,679
  • 1
  • 11
  • 20
  • 1
    The *real* solution is fix your design; don't store delimited data in your Database. But splitting and aggregating strings are probably the most common (if not they're 2nd most common) questions here on Stack Overflow for SQL (Server). There are literally 100's (probably 1000's) of examples here. If you've looked at those answers, and didn't understand that, you should have explained what about them you didn't, or shown your attempts to implement them and describe why they didn't work. – Thom A Oct 28 '20 at 11:30

2 Answers2

2

You can join and use string_agg():

select t1.*, s.names
from table1 t1 cross apply
     (select string_agg(t2.name, ',') as names
      from string_split(t1.key_value, '|') s join
           table2 t2
           on t2.id = s.value
     ) s;

Note: The names are in an arbitrary order. If you want to preserve the original order, you can do:

select t1.*, s.names
from table1 t1 cross apply
     (select string_agg(t2.name, ',') within group (order by charindex('|' + s.value + '|', '|' + t1.key_value + '|')) as names
      from string_split(t1.key_value, '|') s join
           table2 t2
           on t2.id = s.value
     ) s;

Also: You should not be storing multiple values in a string for many good reasons. You should work on fixing the data model. Here are some reasons:

  • It violates the notion that a column contains a single value.
  • Foreign key relationships should be properly defined.
  • Numbers should be stored as numbers.
  • SQL in general and SQL Server in particular have pretty lousy string processing functions.
  • The queries cannot be optimized easily using indexes and partitions.
Gordon Linoff
  • 1,242,037
  • 58
  • 646
  • 786
1

Gordon Linoff's second query is fine, unless there are duplicate in the CSV list, in which case it cannot guarantee that the names will follow the original ordering of the ids.

Here is a more generic approach, that works regardless of whether there are duplicates or not. The idea is to use a recursive query to split the CSV string, which allows keeping track of the original position of each element in the list:

with cte as (
    select id, cast(null as nvarchar(max)) val, key_value + '|' rest, 0 lvl
    from table1
    union all
    select id, substring(rest, 1, charindex('|', rest) - 1), substring(rest, charindex('|', rest) + 1, len(rest)), lvl + 1
    from cte
    where charindex('|', rest) > 0
)
select c.id, string_agg(t2.name, '|') within group (order by c.lvl) names
from cte c
inner join table2 t2 on t2.id = c.val
where c.lvl > 0 
group by c.id
GMB
  • 216,147
  • 25
  • 84
  • 135
  • I never understand how some people can answer a question 10 minutes after it's closed, yet I am unable to even 1 second afterwards... – Thom A Oct 28 '20 at 11:38
  • @Larnu: ah! The closure did not load in my browser, I just found out after your comment... I guess that's a javascript thing. But 10 minutes is a lot indeed. They should really be able to check on server side at the time when the answer is submitted, though, and reject late answers. This might be considered a bug! Consider a meta post maybe? – GMB Oct 28 '20 at 11:40
  • Yeah, there is a question *somewhere* that explains it allows a "grace" period but I won't lie, it infuriates me that I can sometimes spend some time writing an answer to then go to post it within seconds of the closure and can't (and have to vote to reopen, save the markdown, and keep an eye on), while others can freely post 10 minutes afterwards. IF it's going to allow a grace period, it would be nice it is allowed it for everyone (though I personally feel 10 minutes is quite a long grace period), or at least those that had the "Post Answer" dialogue open already. – Thom A Oct 28 '20 at 11:42
  • @Larnu: mm, I see. Well indeed if there is grace period, it should be clearly documented how long it is, and consistently applied to everyone. But really I don't see the point for the grace period. If the question is closed, then you can't answer. Vote for reopening if your disagree. – GMB Oct 28 '20 at 11:44
  • 1
    For posterity, I have used this answer as an example on [meta](https://meta.stackoverflow.com/q/402436/2029983). – Thom A Oct 28 '20 at 11:56
  • @Larnu: seems like you did get a reference answer (after some fluff...). – GMB Oct 28 '20 at 23:26