SQL Server 2008中的拆分功能

use*_*458 2 sql t-sql sql-server sql-server-2008

我有这样Table1的列:

+--+------+
|ID|Name  |
+--+------+
|1 |MSSQL |
+--+------+
|2 |MySQl |
+--+------+
|3 |Oracle|
+--+------+
Run Code Online (Sandbox Code Playgroud)

Table2,我有一个专栏

+------------+
|Databasename|
+------------+
|1,3         |
+------------+
|2           |
+------------+
|1,2         |
+------------+
Run Code Online (Sandbox Code Playgroud)

我的输出应该是:

+------------+
|Databasename|
+------------+
|MSSQL,Oracle|
+------------+
|MySQL       |
+------------+
|MSSQL,MYSQL |
+------------+
Run Code Online (Sandbox Code Playgroud)

我怎么得到这个,我需要查询这个..

Mik*_*son 6

您要求分割功能,但您不必分割您的值以获得所需的结果.

此查询使用for xml连接值的技巧在相关子查询中构建逗号分隔的名称列表.它用于确定每行中like使用的值.Table1Table2

select (
       select ', '+T1.Name
       from Table1 as T1
       where ','+T2.Databasename+',' like '%,'+cast(T1.ID as varchar(10))+',%'
       for xml path(''), type
       ).value('substring(text()[1], 3)', 'varchar(max)') as Databasenames
from Table2 as T2
Run Code Online (Sandbox Code Playgroud)

SQL小提琴


Tar*_*ryn 5

首先,您最好的解决方案是不将数据存储在数据库中以逗号分隔的列表中.您应该考虑修复表结构.

如果无法更改表结构,则需要将列表中的数据拆分为行以指定正确的名称.分割数据后,您可以将数据连接回列表.

split您可以在线找到许多不同的功能,但这是我通常使用的版本:

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;
Run Code Online (Sandbox Code Playgroud)

为了得到你的结果,我将从应用split函数开始,row_number()因为我没有看到与每一行相关联的唯一键.如果每行都有一个唯一的密钥,那么您将不需要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
Run Code Online (Sandbox Code Playgroud)

此查询将以逗号分隔的列表分为以下内容:

| RN |   NAME | ID |
--------------------
|  1 |  MSSQL |  1 |
|  1 | Oracle |  3 |
|  2 |  MySQl |  2 |
|  3 |  MSSQL |  1 |
|  3 |  MySQl |  2 |
Run Code Online (Sandbox Code Playgroud)

一旦你有正确的多行数据name,你就可以使用STUFF()并将FOR XML PATH它连接到列表中.您完全查询将类似于:

;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;
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo.

完整查询的结果是:

|   DATABASENAME |
------------------
|  MSSQL, Oracle |
|          MySQl |
|   MSSQL, MySQl |
Run Code Online (Sandbox Code Playgroud)