Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Durch Komma getrennte Datenspalte beitreten

Idealerweise wäre Ihre beste Lösung, Table2 zu normalisieren, sodass Sie keine durch Kommas getrennte Liste speichern.

Sobald Sie diese Daten normalisiert haben, können Sie die Daten einfach abfragen. Die neue Tabellenstruktur könnte etwa so aussehen:

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')
;

Das Normalisieren der Tabellen würde es Ihnen viel einfacher machen, die Daten abzufragen, indem Sie die Tabellen verbinden:

select t2.col1, t1.col2
from t2
inner join t1
  on t2.col2 = t1.col1

Siehe Demo

Wenn Sie die Daten dann als kommagetrennte Liste anzeigen möchten, können Sie FOR XML PATH verwenden und 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;

Siehe Demo.

Wenn Sie die Daten nicht normalisieren können, gibt es mehrere Möglichkeiten, die Sie tun können.

Erstens könnten Sie eine Aufteilungsfunktion erstellen, die die in der Liste gespeicherten Daten in Zeilen umwandelt, die verknüpft werden können. Die Split-Funktion wäre ähnlich wie diese:

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;

Wenn Sie die Split-Funktion verwenden, können Sie die Daten entweder in mehreren Zeilen belassen oder die Werte wieder zu einer durch Kommas getrennten Liste verketten:

;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

Siehe Demo.

Eine letzte Möglichkeit, das Ergebnis zu erhalten, ist die Anwendung von FOR XML PATH direkt.

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;

Siehe SQL Fiddle mit Demo