【问题标题】:Split Data and transforming them into Columns拆分数据并将它们转换为列
【发布时间】:2016-01-05 16:02:32
【问题描述】:

我有一个输入表如下

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 LOOP 和一些数学逻辑轻松完成,但如果可能的话,我正在寻找一个更优化的,如果可能的话,只通过 SELECT 查询(没有 LOOPS)。

我也尝试过使用 (':') 作为分隔符进行拆分,然后将 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

【问题讨论】:

  • 您是否有固定数量的列,它们的排列方式是否与您的样本中的显示方式一致?
  • is Column1 Column2 Column3 是列名或只是一个值

标签: sql-server tsql pivot sql-server-2014


【解决方案1】:

如果您想要纯 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 Server 可能不是这类事情的最佳选择。

使用动态 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

【讨论】:

    【解决方案2】:

    这应该可行:

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-29
      • 1970-01-01
      • 1970-01-01
      • 2020-09-29
      • 2019-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多