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

Funkcja podziału w SQL Server 2008

Po pierwsze, najlepszym rozwiązaniem jest nie przechowywanie danych w bazie danych na liście rozdzielanej przecinkami. Powinieneś rozważyć naprawienie struktury tabeli.

Jeśli nie możesz zmienić struktury tabeli, musisz podzielić dane na liście na wiersze, aby przypisać poprawną nazwę. Po podzieleniu danych możesz połączyć dane z powrotem na listę.

Istnieje wiele różnych split funkcję, którą można znaleźć w Internecie, ale oto wersja, której zwykle używam:

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;

Aby uzyskać Twój wynik, zacząłbym od zastosowania split funkcja i row_number() ponieważ nie widzę unikalnego klucza związanego z każdym wierszem. Jeśli masz unikalny klucz w każdym wierszu, nie będziesz potrzebować 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

To zapytanie dzieli twoją listę oddzieloną przecinkami na następującą:

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

Gdy masz dane w wielu wierszach z poprawną name , możesz użyć STUFF() i FOR XML PATH połączyć go z listą. Twoje pełne zapytanie byłoby podobne do tego:

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

Zobacz SQL Fiddle z wersją demonstracyjną.

Wynik pełnego zapytania to:

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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Kiedy lepiej przechowywać flagi jako maskę bitową zamiast używać tabeli asocjacyjnej?

  2. Zgrupowana agregacja ciągów / LISTAGG dla SQL Server

  3. Policz na podstawie warunku w SQL Server

  4. Plan wykonania SQL Server — co to jest i jak pomaga w problemach z wydajnością?

  5. 2 sposoby tworzenia tabeli na serwerze połączonym za pomocą T-SQL