在列中拆分字符串并在 sql 中进行旋转

split a string in a column and pivot in sql

我正在使用 sql 服务器 2014,我有一个 table 这样的 (##tt_allresults)

ID      |       Area        |       Event                                                                           |
1       |       FB1         |   Dev_Chg, Old Value: 0, New Value: 50, Workstation: Blah1, Function: Blah1 func      |
1       |       FB2         |   Dev_Chg, Old Value: 99, New Value: 5, Workstation: Blah2, Function: Blah2 func      |       
1       |       FB1         |   Dev_Chg, Old Value: 50, New Value: 55, Workstation: Blah1, Function: Blah1 func     |

我想从 table 像这样(预期输出)

Area    |   Old Value   |       New Value   |       Function        |
FB1     |   0           |       50          |   Blah1 func          |   
FB2     |   99          |       5           |   Blah2 func          |   
FB1     |   50          |       55          |   Blah1 func          |   

这是我目前尝试过的

Declare @id int
WHILE EXISTS(SELECT * FROM ##tt_allresults)
BEGIN
Select Top 1 @id = Id from ##tt_allresults

-- Do the work --
Declare @area nvarchar(100)
set @area = (Select Area from ##tt_allresults where id = @id)

Insert into ##tt_changedetails
select @area, * from fnsplit((Select [event] from ##tt_allresults where id = @id),',')

-- Scrap the ID and Move On --
Delete ##tt_allresults where ID = @id
END


select * from ##tt_changedetails

我得到以下结果

Area    |       ChangeDetails       |
FB1     |   Dev_Chg                 |
FB1     |   Old value :0            |
FB1     |   New Value :50           |
FB1     |   Workstation :blah1      |
FB1     |   Function :blah1 func    |
FB2     |   Dev_Chg                 |
FB2     |   Old value :99           |
FB2     |   New Value :5            |
FB2     |   Workstation :blah2      |
FB2     |   Function :blah2 func    |
FB1     |   Dev_Chg                 |
FB1     |   Old value :50           |
FB1     |   New Value :55           |
FB1     |   Workstation :blah1      |
FB1     |   Function :blah1 func    |

我如何拆分我的初始 table 并根据拆分来调整它。我想看到下面的结果

FB1     |   0           |       50          |   Blah1 func          |   
FB2     |   99          |       5           |   Blah2 func          |   
FB1     |   50          |       55          |   Blah1 func          |   

这是正确的查询,希望对您有所帮助。

          declare @str varchar(1000) 

        declare @temp as table (id int , area varchar(10) , [event] varchar(100))

        insert into @temp (id,area,[event]) values (1,'FB1','Dev_Chg, Old Value: 0, New Value: 50, Workstation: Blah1, Function: Blah1 func')
        insert into @temp (id,area,[event]) values (1,'FB2','Dev_Chg, Old Value: 99, New Value: 5, Workstation: Blah2, Function: Blah2 func')
        insert into @temp (id,area,[event]) values (1,'FB1','Dev_Chg, Old Value: 50, New Value: 55, Workstation: Blah1, Function: Blah1 func')

        set @str ='Dev_Chg, Old Value: 0, New Value: 50, Workstation: Blah1, Function: Blah1 func'



        select  * from (
        select area,  RTRIM( LTRIM(  SUBSTRING( String,0 , CHARINDEX (':',String ))) )as theader  , SUBSTRING( String,  CHARINDEX (':',String )+1,15) as tvalue from (
        select * from 
        @temp cross apply 
        dbo.ufn_CSVToTable ([event])
        ) b
        where b.String!='Dev_Chg'

        ) 
         as final 
         pivot (  max ( tvalue ) for theader in ([Old Value] , [New Value],[Workstation],[Function])
         ) as pvt

-- 我用了一个表值函数来完成它来源是这个

        ALTER FUNCTION [dbo].[ufn_CSVToTable] ( @StringInput VARCHAR(8000) )
        RETURNS @OutputTable TABLE ( [String] nVARCHAR(1000) )
        AS
        BEGIN

            DECLARE @String    nVARCHAR(1000)

            WHILE LEN(@StringInput) > 0
            BEGIN
                SET @String      = LEFT(@StringInput, 
                                        ISNULL(NULLIF(CHARINDEX(',', @StringInput) - 1, -1),
                                        LEN(@StringInput)))
                SET @StringInput = SUBSTRING(@StringInput,
                                             ISNULL(NULLIF(CHARINDEX(',', @StringInput), 0),
                                             LEN(@StringInput)) + 1, LEN(@StringInput))

                INSERT INTO @OutputTable ( [String] )
                VALUES ( @String )
            END

            RETURN
        END

无需 UDF,只需借助 CROSS APPLY 和一点 XML

您可以根据需要扩展或收缩。我留了9个位置来说明

1) 没有函数

Declare @YourTable table (ID int,Area varchar(25),Event varchar(500))
Insert Into @YourTable values
(1,'FB1','Dev_Chg, Old Value: 0, New Value: 50, Workstation: Blah1, Function: Blah1 func'),
(1,'FB2','Dev_Chg, Old Value: 99, New Value: 5, Workstation: Blah2, Function: Blah2 func'),
(1,'FB1','Dev_Chg, Old Value: 50, New Value: 55, Workstation: Blah1, Function: Blah1 func')

Select A.Area
      ,[Old Value] = Substring(Pos2,CharIndex(':',Pos2)+1,Len(Pos2))
      ,[New Value] = Substring(Pos3,CharIndex(':',Pos3)+1,Len(Pos3))
      ,[Function]  = Substring(Pos5,CharIndex(':',Pos5)+1,Len(Pos5))
 From  @YourTable A
 Cross Apply (
                Select Pos1 = ltrim(rtrim(xDim.value('/x[1]','varchar(max)')))
                      ,Pos2 = ltrim(rtrim(xDim.value('/x[2]','varchar(max)')))
                      ,Pos3 = ltrim(rtrim(xDim.value('/x[3]','varchar(max)')))
                      ,Pos4 = ltrim(rtrim(xDim.value('/x[4]','varchar(max)')))
                      ,Pos5 = ltrim(rtrim(xDim.value('/x[5]','varchar(max)')))
                      ,Pos6 = ltrim(rtrim(xDim.value('/x[6]','varchar(max)')))
                      ,Pos7 = ltrim(rtrim(xDim.value('/x[7]','varchar(max)')))
                      ,Pos8 = ltrim(rtrim(xDim.value('/x[8]','varchar(max)')))
                      ,Pos9 = ltrim(rtrim(xDim.value('/x[9]','varchar(max)')))
                 From  (Select Cast('<x>' + replace((Select A.Event as [*] For XML Path('')),',','</x><x>')+'</x>' as xml) as xDim) as A 
       ) B

Returns

Area    Old Value   New Value   Function
FB1     0           50          Blah1 func
FB2     99          5           Blah2 func
FB1     50          55          Blah1 func

或2个同一个函数

Select A.Area
      ,[Old Value] = Substring(Pos2,CharIndex(':',Pos2)+1,Len(Pos2))
      ,[New Value] = Substring(Pos3,CharIndex(':',Pos3)+1,Len(Pos3))
      ,[Function]  = Substring(Pos5,CharIndex(':',Pos5)+1,Len(Pos5))
 From  @YourTable A
 Cross Apply [dbo].[udf-Str-Parse-Row](A.Event,',') B

UDF(如果需要)

ALTER FUNCTION [dbo].[udf-Str-Parse-Row] (@String varchar(max),@Delimiter varchar(10))
Returns Table 
As
Return (
    Select Pos1 = ltrim(rtrim(xDim.value('/x[1]','varchar(max)')))
            ,Pos2 = ltrim(rtrim(xDim.value('/x[2]','varchar(max)')))
            ,Pos3 = ltrim(rtrim(xDim.value('/x[3]','varchar(max)')))
            ,Pos4 = ltrim(rtrim(xDim.value('/x[4]','varchar(max)')))
            ,Pos5 = ltrim(rtrim(xDim.value('/x[5]','varchar(max)')))
            ,Pos6 = ltrim(rtrim(xDim.value('/x[6]','varchar(max)')))
            ,Pos7 = ltrim(rtrim(xDim.value('/x[7]','varchar(max)')))
            ,Pos8 = ltrim(rtrim(xDim.value('/x[8]','varchar(max)')))
            ,Pos9 = ltrim(rtrim(xDim.value('/x[9]','varchar(max)')))
     From  (Select Cast('<x>' + replace((Select @String as [*] For XML Path('')),@Delimiter,'</x><x>')+'</x>' as xml) as xDim) as A 
)
--Select * from [dbo].[udf-Str-Parse-Row]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse-Row]('John <test> Cappelletti',' ')

如果它有助于可视化,CROSS APPLY(很容易成为 TVF)会产生以下结果