Lý tưởng nhất, giải pháp tốt nhất của bạn là chuẩn hóa Table2 để bạn không lưu trữ danh sách được phân tách bằng dấu phẩy.
Khi bạn đã chuẩn hóa dữ liệu này thì bạn có thể dễ dàng truy vấn dữ liệu. Cấu trúc bảng mới có thể tương tự như sau:
CREATE TABLE T1
(
[col1] varchar(2),
[col2] varchar(5),
constraint pk1_t1 primary key (col1)
);
INSERT INTO T1
([col1], [col2])
VALUES
('C1', 'john'),
('C2', 'alex'),
('C3', 'piers'),
('C4', 'sara')
;
CREATE TABLE T2
(
[col1] varchar(2),
[col2] varchar(2),
constraint pk1_t2 primary key (col1, col2),
constraint fk1_col2 foreign key (col2) references t1 (col1)
);
INSERT INTO T2
([col1], [col2])
VALUES
('R1', 'C1'),
('R1', 'C2'),
('R1', 'C4'),
('R2', 'C3'),
('R2', 'C4'),
('R3', 'C1'),
('R3', 'C4')
;
Việc chuẩn hóa các bảng sẽ giúp bạn truy vấn dữ liệu dễ dàng hơn nhiều bằng cách nối các bảng:
select t2.col1, t1.col2
from t2
inner join t1
on t2.col2 = t1.col1
Xem Demo
Sau đó, nếu bạn muốn hiển thị dữ liệu dưới dạng danh sách được phân tách bằng dấu phẩy, bạn có thể sử dụng FOR XML PATH
và STUFF
:
select distinct t2.col1,
STUFF(
(SELECT distinct ', ' + t1.col2
FROM t1
inner join t2 t
on t1.col1 = t.col2
where t2.col1 = t.col1
FOR XML PATH ('')), 1, 1, '') col2
from t2;
Xem Demo.
Nếu bạn không thể chuẩn hóa dữ liệu, thì có một số điều bạn có thể làm.
Đầu tiên, bạn có thể tạo một hàm tách sẽ chuyển đổi dữ liệu được lưu trữ trong danh sách thành các hàng có thể được nối với nhau. Hàm tách sẽ tương tự như sau:
CREATE FUNCTION [dbo].[Split](@String varchar(MAX), @Delimiter char(1))
returns @temptable TABLE (items varchar(MAX))
as
begin
declare @idx int
declare @slice varchar(8000)
select @idx = 1
if len(@String)<1 or @String is null return
while @idx!= 0
begin
set @idx = charindex(@Delimiter,@String)
if @idx!=0
set @slice = left(@String,@idx - 1)
else
set @slice = @String
if(len(@slice)>0)
insert into @temptable(Items) values(@slice)
set @String = right(@String,len(@String) - @idx)
if len(@String) = 0 break
end
return
end;
Khi bạn sử dụng hàm tách, bạn có thể để dữ liệu trong nhiều hàng hoặc bạn có thể nối các giá trị lại thành một danh sách được phân tách bằng dấu phẩy:
;with cte as
(
select c.col1, t1.col2
from t1
inner join
(
select t2.col1, i.items col2
from t2
cross apply dbo.split(t2.col2, ',') i
) c
on t1.col1 = c.col2
)
select distinct c.col1,
STUFF(
(SELECT distinct ', ' + c1.col2
FROM cte c1
where c.col1 = c1.col1
FOR XML PATH ('')), 1, 1, '') col2
from cte c
Xem Demo.
Cách cuối cùng mà bạn có thể nhận được kết quả là áp dụng FOR XML PATH
trực tiếp.
select col1,
(
select ', '+t1.col2
from t1
where ','+t2.col2+',' like '%,'+cast(t1.col1 as varchar(10))+',%'
for xml path(''), type
).value('substring(text()[1], 3)', 'varchar(max)') as col2
from t2;
Xem SQL Fiddle với Demo