Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

присъединете колона с данни, разделени със запетая

В идеалния случай най-доброто решение би било да нормализирате Table2, така че да не съхранявате списък, разделен със запетая.

След като нормализирате тези данни, можете лесно да направите заявка за данните. Новата структура на таблицата може да бъде подобна на тази:

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

Нормализирането на таблиците би ви улеснило много по-лесно да правите заявки за данните, като се присъедините към таблиците:

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

Вижте Демо

След това, ако искате да покажете данните като разделен със запетая списък, можете да използвате FOR XML PATH и 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;

Вижте Демо.

Ако не сте в състояние да нормализирате данните, тогава има няколко неща, които можете да направите.

Първо, можете да създадете функция за разделяне, която ще преобразува съхраняваните в списъка данни в редове, които могат да бъдат присъединени. Функцията за разделяне би била подобна на тази:

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;

Когато използвате функцията split, можете или да оставите данните в множество редове, или можете да свържете стойностите обратно в разделен със запетая списък:

;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

Вижте Демо.

Последният начин, по който можете да получите резултата, е като приложите FOR XML PATH директно.

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;

Вижте SQL Fiddle с демонстрация



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Елиминиране на присъединяване:Когато SQL Server премахва ненужните таблици

  2. Как да прочетете последния ред с SQL Server

  3. Как да използвате функциите на SQL Server AlwaysOn

  4. Дилема за именуване на таблица:имена в единствено число срещу множествено число

  5. Как да върнете *всичко* от съхранена процедура с помощта на JDBC