Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Fonction de fractionnement dans SQL Server 2008

Tout d'abord, votre meilleure solution est de ne pas stocker les données dans une liste séparée par des virgules dans votre base de données. Vous devriez envisager de corriger la structure du tableau.

Si vous ne pouvez pas modifier la structure du tableau, vous devrez diviser les données de la liste en lignes pour attribuer le nom correct. Une fois les données divisées, vous pouvez concaténer les données dans la liste.

Il existe de nombreux split différents fonction que vous pouvez trouver en ligne mais voici une version que j'utilise habituellement :

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;

Pour obtenir votre résultat, je commencerais par appliquer le split fonction et un row_number() car je ne vois pas de clé unique associée à chaque ligne. Si vous avez une clé unique sur chaque ligne, vous n'aurez pas besoin du row_number() :

;with cte as
(
  select rn, name, id
  from
  (
    select row_number() over(order by (select 1)) rn,
      databasename
    from table2
  ) t2
  cross apply dbo.split(t2.databasename, ',') i
  inner join table1 t1
    on i.items = t1.id
) 
select *
from cte

Cette requête divise votre liste séparée par des virgules comme suit :

| RN |   NAME | ID |
--------------------
|  1 |  MSSQL |  1 |
|  1 | Oracle |  3 |
|  2 |  MySQl |  2 |
|  3 |  MSSQL |  1 |
|  3 |  MySQl |  2 |

Une fois que vous avez les données dans plusieurs lignes avec le bon name , alors vous pouvez utiliser STUFF() et FOR XML PATH pour le concaténer dans la liste. Votre requête complète ressemblerait à ceci :

;with cte as
(
  select rn, name, id
  from
  (
    select row_number() over(order by (select 1)) rn,
      databasename
    from table2
  ) t2
  cross apply dbo.split(t2.databasename, ',') i
  inner join table1 t1
    on i.items = t1.id
) 
select  
  STUFF(
         (SELECT ', ' + c2.name
          FROM cte c2
          where c1.rn = c2.rn
          order by c2.id
          FOR XML PATH (''))
          , 1, 1, '') Databasename
from cte c1
group by c1.rn
order by c1.rn;

Voir SQL Fiddle avec démo.

Le résultat de la requête complète est :

|   DATABASENAME |
------------------
|  MSSQL, Oracle |
|          MySQl |
|   MSSQL, MySQl |