sql >> Databáze >  >> RDS >> Sqlserver

spojit datový sloupec oddělený čárkou

V ideálním případě by bylo vaším nejlepším řešením normalizovat tabulku 2, takže neukládáte seznam oddělený čárkami.

Jakmile máte tato data normalizovaná, můžete je snadno dotazovat. Nová struktura tabulky by mohla být podobná této:

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

Normalizace tabulek by vám mnohem snadněji usnadnila dotazování na data spojením tabulek:

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

Viz Demo

Pokud byste pak chtěli data zobrazit jako seznam oddělený čárkami, můžete použít FOR XML PATH a 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;

Viz Demo.

Pokud nejste schopni normalizovat data, můžete udělat několik věcí.

Nejprve můžete vytvořit funkci rozdělení, která převede data uložená v seznamu na řádky, které lze spojit. Funkce rozdělení by byla podobná této:

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;

Když použijete funkci rozdělení, můžete buď ponechat data ve více řádcích, nebo můžete hodnoty zřetězit zpět do seznamu odděleného čárkami:

;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

Viz Demo.

Posledním způsobem, jak získat výsledek, je použití FOR XML PATH přímo.

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;

Viz SQL Fiddle with Demo



  1. Wordnet sqlite Synonyma a ukázky

  2. Kopírovat/duplikovat databázi bez použití mysqldump

  3. Spuštění MariaDB v nastavení hybridního cloudu

  4. Zkontrolujte, zda řádek existuje, jinak vložte