拆分数据并将它们转换为列

Split Data and transforming them into Columns

我有一个输入 table 如下

Id  Data
1   Column1: Value1
2   Column2: Value11
3   Column3: Value111
4   Column1: Value2
5   Column2: Value22
6   Column3: Value222

我正在寻找下面的输出

Column1      Column2    Column3
Value1       Value11    Value111
Value2       Value22    Value222

我怎样才能做到这一点?它可以通过使用 WHILE 循环和一些数学逻辑轻松完成,但我正在寻找一个更优化的,如果可能的话,只需要 SELECT 查询(没有循环)。

我也尝试过使用 (':') 作为分隔符进行拆分,然后将 ROWS 转换为 COLUMNS (PIVOT),但有些无法继续。 (这是我的想法,人们可能有更好的想法)。

到目前为止我的镜头

Declare @t table(Id int identity(1,1),Data varchar(1000))
Insert into @t Values
    ('Column1: Value1'),('Column2: Value11'),('Column3: Value111')
    ,('Column1: Value2'),('Column2: Value22'),('Column3: Value222')

Select *
FROM @t
SELECT 
 F1.id,
 F1.Data,
 O.splitdata 
FROM
 (
 SELECT *,
 cast('<X>'+replace(F.Data,':','</X><X>')+'</X>' as XML) as xmlfilter from @t F
 )F1
 CROSS APPLY
 ( 
 SELECT fdata.D.value('.','varchar(50)') as splitdata 
 FROM f1.xmlfilter.nodes('X') as fdata(D)) O

如果你想要一个纯粹的 SQL 解决方案,这将有效:

Select [Column1], [Column2], [Column3] From (
    Select col, val, id = ROW_NUMBER() over(partition by d.col order by d.id)
    From (
         Select id
            , col = LEFT(Data, CHARINDEX(':', Data)-1)
            , val = RIGHT(Data, LEN(DATA) - CHARINDEX(':', Data))

         From @t
    ) as d
) as p
pivot(
    MAX(val)
    FOR col in([Column1], [Column2], [Column3])
) as piv

但它假定第 1 行的数据始终在第 2 行的数据之前。使用您的示例无法区分它们。

如果列数不固定,则必须使用动态SQL。

SQL服务器可能不是这种事情的最佳选择。

使用动态 SQL,上面的查询将像这样:

create table #t(Id int identity(1,1),Data varchar(1000))
Insert into #t Values
    ('Column1: Value1'),('Column2: Value11'),('Column3: Value111')
    ,('Column1: Value2'),('Column2: Value22'),('Column3: Value222')

Declare @sql nvarchar(max)

Select @sql = '
        Select '+left(c, len(c)-1)+' From (
        Select col, val, id = ROW_NUMBER() over(partition by d.col order by d.id)
        From (
             Select id
                , col = LEFT(Data, CHARINDEX('':'', Data)-1)
                , val = RIGHT(Data, LEN(DATA) - CHARINDEX('':'', Data))

             From #t
        ) as d
    ) as p
    pivot(
        MAX(val)
        FOR col in('+left(c, len(c)-1)+')
    ) as piv
'
From (
    Select Distinct '['+LEFT(Data, CHARINDEX(':', Data)-1)+'], '
    From #t
    FOR XML PATH('')
) as d(c)

EXEC sp_executesql @sql

SQL Fiddle

这应该有效:

Declare @t table(Id int identity(1,1),Data varchar(1000))
Insert into @t Values
    ('Column1: Value1'),('Column2: Value11'),('Column3: Value111')
    ,('Column1: Value2'),('Column2: Value22'),('Column3: Value222');

WITH Splitted AS
(
     SELECT *
           ,CAST('<X>'+REPLACE(F.Data,':','</X><X>')+'</X>' AS XML) AS xmlfilter 
     FROM @t AS F
)
SELECT p.*
FROM
(
    SELECT ROW_NUMBER() OVER(PARTITION BY xmlfilter.value('X[1]','varchar(max)') ORDER BY Id) AS Inx 
          ,xmlfilter.value('X[1]','varchar(max)') AS ColName
          ,xmlfilter.value('X[2]','varchar(max)') AS ColVal
    FROM Splitted
) AS tbl
PIVOT
(
    MAX(ColVal) FOR ColName IN(Column1,Column2,Column3)
) AS p