Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

dołącz do kolumny danych rozdzielanych przecinkami

Najlepszym rozwiązaniem byłoby znormalizowanie tabeli 2, aby nie przechowywać listy oddzielonej przecinkami.

Po znormalizowaniu tych danych możesz łatwo przeszukiwać dane. Nowa struktura tabeli może być podobna do tej:

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

Normalizacja tabel znacznie ułatwiłaby wyszukiwanie danych poprzez łączenie tabel:

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

Zobacz demo

Następnie, jeśli chcesz wyświetlić dane jako listę oddzieloną przecinkami, możesz użyć FOR XML PATH i 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;

Zobacz Demo.

Jeśli nie jesteś w stanie znormalizować danych, możesz zrobić kilka rzeczy.

Po pierwsze, możesz utworzyć funkcję podziału, która przekonwertuje dane przechowywane na liście na wiersze, które można połączyć. Funkcja podziału byłaby podobna do tego:

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;

Korzystając z funkcji podziału, możesz pozostawić dane w wielu wierszach lub połączyć wartości z powrotem w listę oddzieloną przecinkami:

;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

Zobacz Demo.

Ostatnim sposobem uzyskania wyniku jest zastosowanie FOR XML PATH bezpośrednio.

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;

Zobacz SQL Fiddle z demonstracją



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. java.sql.SQLException:nie znaleziono odpowiedniego sterownika dla jdbc:microsoft:sqlserver

  2. Czym jest BETWEEN operator logiczny w SQL Server — samouczek SQL Server / TSQL część 124

  3. Jakie jest znaczenie 1/1/1753 w SQL Server?

  4. Jak osiągnąć limity 8060 bajtów na wiersz i 8000 na wartość (varchar, nvarchar)?

  5. Dodaj zmienny kolor wiersza do raportu usług raportowania SQL Server