How to query a table with multiple values ββin one column with union
Table 1:
A B C
Test 1 This
Test1 1;4 That
Test2 7 What
Test3 6;2 Which
Test4 1;2;7 Where
Table 2:
X Z
1 Sun
2 Mon
3 Tue
4 Wed
5 Thu
6 Fri
7 Sat
Sql:
Select
t1.A,
t2.Z
from
[dbo].[Table 1] t1
inner join [dbo].[Table2] t2
on t1.B = t2.X
It only works for rows that only have 1 record per column B
, but does not work with 2 or more records.
How can I change Sql so that it gives me the output like this:
A Z
Test Sun
Test1 Sun;Wed
Test2 Sat
Test3 Fri;Mon
Test4 Sun;Mon;Sat
source to share
Fun with Strings and XML , here is a small (minified) technique for tokenizing data.
Generating some sample data
Declare @Table1 table (A varchar(100),B varchar(100), C varchar(100))
Insert Into @Table1 values
('Test','1','This'),('Test1','1;4','That'),('Test2','7','What'),('Test3','6;2','Which'),('Test4','1;2;7','Where')
Declare @Table2 table (X int,Z varchar(100))
Insert Into @Table2 values
(1,'Sun'),(2,'Mon'),(3,'Tue'),(4,'Wed'),(5,'Thu'),(6,'Fri'),(7,'Sat')
SQL
Declare @XML xml,@Str varchar(max) = (Select a,z='['+replace(b,';','];[')+']' From @Table1 For XML Raw)
Select @Str = Replace(@Str,'['+cast(X as varchar(25))+']',Z) From @Table2
Select @XML = @Str
Select a = r.value('@a','varchar(100)')
,z = r.value('@z','varchar(100)')
From @XML.nodes('/row') as A(r)
Returns
a z
Test Sun
Test1 Sun;Wed
Test2 Sat
Test3 Fri;Mon
Test4 Sun;Mon;Sat
source to share
You really shouldn't be storing multiple values ββin the same column, it will lead to poor performance when you really need to do something with those values.
Using CSV Splitter function, Jeff Moden's function and using with string concatenation method . stuff()
select ... for xml path ('')
select
t1.a
, z = stuff((
select ';'+t2.Z
from t1 i
cross apply dbo.delimitedsplit8K(i.b,';') s
inner join t2
on s.Item = t2.x
where i.a = t1.a
order by s.ItemNumber
for xml path(''),type).value('(./text())[1]','nvarchar(max)')
,1,1,'')
from t1
rextester demo :
returns: http://rextester.com/HNNP95095
+-------+-------------+
| a | z |
+-------+-------------+
| Test | Sun |
| Test1 | Sun;Wed |
| Test2 | Sat |
| Test3 | Fri;Mon |
| Test4 | Sun;Mon;Sat |
+-------+-------------+
link for separating lines:
- Tally OH! Enhanced SQL 8K "CSV Splitter" Feature - Jeff Moden
- Splitting Lines: Continued - Aaron Bertrand
- Split strings in the correct way - or in the next best way - Aaron Bertrand
-
string_split()
in SQL Server 2016: Follow-Up # 1 - Aaron Bertrand
<h / "> Jeff Moden's function is used to demonstrate:
create function [dbo].[delimitedsplit8K] (
@pstring varchar(8000)
, @pdelimiter char(1)
)
returns table with schemabinding as
return
with e1(N) as (
select 1 union all select 1 union all select 1 union all
select 1 union all select 1 union all select 1 union all
select 1 union all select 1 union all select 1 union all select 1
)
, e2(N) as (select 1 from e1 a, e1 b)
, e4(N) as (select 1 from e2 a, e2 b)
, ctetally(N) as (
select top (isnull(datalength(@pstring),0))
row_number() over (order by (select null)) from e4
)
, ctestart(N1) as (
select 1 union all
select t.N+1 from ctetally t where substring(@pstring,t.N,1) = @pdelimiter
)
, ctelen(N1,L1) as (
select s.N1,
isnull(nullif(charindex(@pdelimiter,@pstring,s.N1),0)-s.N1,8000)
from ctestart s
)
select itemnumber = row_number() over(order by l.N1)
, item = substring(@pstring, l.N1, l.L1)
from ctelen l
;
go
source to share