拆分数据并将它们转换为列
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
这应该有效:
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
我有一个输入 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
这应该有效:
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