【问题标题】:split a string in a column and pivot in sql在列中拆分字符串并在 sql 中进行透视
【发布时间】:2017-01-13 12:04:11
【问题描述】:

我使用的是 sql server 2014,我有一个这样的表 (##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     |

我想从这样的表中(预期输出)

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    |

如何拆分我的初始表并根据拆分对其进行旋转。我想看看下面的结果

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

【问题讨论】:

  • @Chanukya - 我已经更新了这个问题。如果您还有任何问题,请随时提问。
  • 你想要的结果是什么?
  • @iamdave - 我的问题中的预期输出表。
  • @iamdave - 如有任何问题,请随时提问。
  • 首先,得到你得到的结果,然后根据“:”进行另一个拆分;然后分别为旧值、新值、工作站执行三个枢轴,并将它们连接在一起(或者您可以在第二部分使用 CASE)。对此已有很多答案。

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


【解决方案1】:

不需要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

退货

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)会生成以下内容

【讨论】:

  • @Abe 很高兴它有帮助
【解决方案2】:

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

          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

【讨论】:

  • 你的答案中的“字符串”是什么?
  • @Abe 这是我 CROSS Apply 的用户定义函数的输出。尽管正如我提到的,对于您提供的当前数据,我们有一个问题,您无法正确旋转它显示 2 记录而不是 3 。您需要稍作修改,但几乎所有问题都在查询中得到解答。我希望这对您有帮助。
  • 我已经执行了你的函数,但我无法运行你的脚本。 “字符串”是问题所在。我错过了什么吗?
  • 很奇怪,因为它运行良好。如您所见,该函数将表的输出作为名称为 String 的列。所以这应该不是问题。
猜你喜欢
  • 2021-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-06
  • 2014-02-21
  • 1970-01-01
相关资源
最近更新 更多