sql >> Databasteknik >  >> RDS >> Sqlserver

Split-funktion i SQL Server 2008

För det första är din bästa lösning att inte lagra data i en kommaseparerad lista i din databas. Du bör överväga att fixa tabellstrukturen.

Om du inte kan ändra tabellstrukturen måste du dela upp data i listan i rader för att tilldela rätt namn. När data är uppdelade kan du sammanfoga data tillbaka till listan.

Det finns många olika split funktion som du kan hitta online men här är en version som jag vanligtvis använder:

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;

För att få ditt resultat skulle jag börja med att använda split funktion och en row_number() eftersom jag inte ser en unik nyckel kopplad till varje rad. Om du har en unik nyckel på varje rad behöver du inte 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

Den här frågan delar upp din kommaseparerade lista i följande:

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

När du har data i flera rader med rätt name , då kan du använda STUFF() och FOR XML PATH för att sammanfoga det i listan. Din fullständiga fråga skulle likna denna:

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

Se SQL Fiddle with Demo.

Resultatet av hela frågan är:

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


  1. Oracle jämför tidsstämpel med datum

  2. MySQL – ELT() och FILED() funktioner för att extrahera indexposition från listan

  3. Hur man ändrar användare till superanvändare i PostgreSQL

  4. Det går inte att lägga till eller uppdatera en underordnad rad:en begränsning av främmande nyckel misslyckas