sql >> Database teknologi >  >> RDS >> Sqlserver

join kommasepareret datakolonne

Ideelt set ville din bedste løsning være at normalisere tabel2, så du ikke gemmer en kommasepareret liste.

Når du har normaliseret disse data, kan du nemt forespørge dataene. Den nye tabelstruktur kunne ligne denne:

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

Normalisering af tabellerne ville gøre det meget nemmere for dig at forespørge dataene ved at forbinde tabellerne:

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

Se Demo

Så hvis du ville vise dataene som en kommasepareret liste, kunne du bruge FOR XML PATH og 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;

Se Demo.

Hvis du ikke er i stand til at normalisere dataene, så er der flere ting, du kan gøre.

Først kan du oprette en opdelt funktion, der vil konvertere de data, der er gemt på listen, til rækker, der kan sammenføjes. Opdelingsfunktionen ville ligne denne:

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;

Når du bruger splitfunktionen, kan du enten lade dataene ligge i flere rækker, eller du kan sammenkæde værdierne tilbage til en kommasepareret liste:

;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

Se Demo.

En sidste måde, du kan få resultatet på, er ved at anvende FOR XML PATH direkte.

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;

Se SQL Fiddle with Demo



  1. Alternativ til at bruge LIMIT søgeord i en underforespørgsel i MYSQL

  2. Hvad er den bedste måde at skrive det første bogstav i hvert ord i en streng i SQL Server med stort

  3. Hvad er SQL Server? (Definition, versioner, udgaver)

  4. Opret og konfigurer Oracle Linked Server i SQL Server