sql >> Database >  >> RDS >> Sqlserver

deelnemen aan door komma's gescheiden gegevenskolom

Idealiter zou uw beste oplossing zijn om Tabel 2 te normaliseren, zodat u geen door komma's gescheiden lijst opslaat.

Zodra u deze gegevens hebt genormaliseerd, kunt u de gegevens eenvoudig opvragen. De nieuwe tabelstructuur zou er ongeveer zo uit kunnen zien:

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

Het normaliseren van de tabellen zou het voor u veel gemakkelijker maken om de gegevens op te vragen door de tabellen samen te voegen:

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

Zie demo

Als u vervolgens de gegevens als een door komma's gescheiden lijst wilt weergeven, kunt u FOR XML PATH gebruiken en 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;

Zie demo.

Als u de gegevens niet kunt normaliseren, zijn er verschillende dingen die u kunt doen.

Ten eerste zou u een splitsingsfunctie kunnen maken die de gegevens die in de lijst zijn opgeslagen, omzet in rijen die kunnen worden samengevoegd. De splitsingsfunctie zou er ongeveer zo uitzien:

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;

Wanneer u de functie Splitsen gebruikt, kunt u de gegevens in de meerdere rijen laten staan ​​of u kunt de waarden weer samenvoegen in een door komma's gescheiden lijst:

;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

Zie demo.

Een laatste manier om het resultaat te krijgen is door FOR XML PATH toe te passen rechtstreeks.

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;

Zie SQL Fiddle met demo



  1. Maximum aantal records in een MySQL-databasetabel

  2. Android:deelnemen aan de kindertafel met oudertabel Sqlite

  3. Converteer 'datetime2' naar 'smalldatetime' in SQL Server (T-SQL-voorbeelden)

  4. DevOps Database Woordenlijst voor de MySQL-beginner