【问题标题】:Treating multiple delimiter separated fields as distinct rows将多个分隔符分隔的字段视为不同的行
【发布时间】:2016-12-12 00:26:19
【问题描述】:

我继承了一个表(谁没有,对吧?),其中的数据如下所示:

Item          |             Properties        |        Quantity
--------------------------------------------------------------------
Shirt         |  button-down,polo,sleeveless  |          4,5,8

短期内,我想创建一个视图,但最终我想在时间允许的情况下将数据导出到新版本的表中,并使其更像:

Item          |             Properties        |        Quantity
--------------------------------------------------------------------
Shirt         |            button-down        |            4   
Shirt         |               polo            |            5
Shirt         |             sleeveless        |            8

基本上,采用多个列组(我想会有其他表的列多于两列具有这种行为)已知是分隔符分隔并将它们分成不同的行?收集的任何其他与此不同的行将在它们之间共享,如本示例中的 Item。 # 个逗号在这些类型之间是一致的。

编辑:我使用了How to convert comma separated NVARCHAR to table records in SQL Server 2005? 的答案中给出的函数,这就是我目前所拥有的:

select distinct data.item, tmptbl.[String] from
  data cross apply [ufn_CSVToTable](data.properties, ',') tmptbl ...

这适用于单列上下文,但将该函数直接应用于第二列(在本例中为数量)会生成所有可能的属性和数量组合,对吗?事实上,是的,当我尝试时,它确实导致了这种情况。看来我需要一个游标或类似的东西来有效地分解成单独的属性行 [i] |数量[i],将尝试构建它。或者可能只是选择数据并在应用程序端拆分它。

【问题讨论】:

  • 一节讲SQL的课刚刚结束。在过去的几分钟里,我在 sql/tsql 上看到了多个未定义的问题,其中没有一个显示他们自己尝试解决的代码。请附上您自己尝试过的内容、遇到问题的地方以及准确而准确的问题,否则您的问题无法回答。
  • 好的,谢谢。将更新以包含(尽管它只允许以这种方式破坏单个列)。
  • 您是在使用 SQL Server 2005,还是只是顺便提及?使用适当的软件(MySQL、Oracle、DB2 等)和版本标记数据库问题很有帮助,例如sql-server-2014。语法和功能的差异通常会影响答案。

标签: tsql sql-server-2005


【解决方案1】:

使用来自here..的拆分字符串之一。

如果您确定属性将始终具有与数量相同的计数(我的意思是属性中的 3 个值和数量中的 3 个值),那么您可以将下面的连接替换为内部连接..

;With cte
as
(select t.item ,a1.item as 'Properties',row_number() over (order by (select null)) as rownum1
 from #test t
cross apply
[dbo].[SplitStrings_Numbers](proper,',') a1
)
,cte1 as
(
select a2.item as quantity,row_number() over (order by (select null)) as rownum2
 from #test t
cross apply
[dbo].[SplitStrings_Numbers](quantity,',') a2
)
Select c.ite,c.Properties,c1.quantity
from cte c
full join
cte1 c1
on c.rownum1=c1.rownum2

输出:

item    Properties  quantity
Shirt   button-down    4
Shirt   polo           5
Shirt   sleeveless     8

【讨论】:

  • 啊,这是一种非常新颖的方法:单独拆分,加入行号。会试一试。
【解决方案2】:

借助拆分器和交叉应用

Declare @YourTable table (item varchar(50),Properties varchar(50),Quantities varchar(50))
Insert into @YourTable values
('Shirt','button-down,polo,sleeveless','4,5,8')


Select A.item
      ,B.Properties
      ,B.Quantities
 From @YourTable A
 Cross Apply (Select Properties=A.Key_Value
                    ,Quantities=B.Key_Value
               From (Select * from [dbo].[udf-Str-Parse](A.Properties,',')) A
               Left Join (Select * from [dbo].[udf-Str-Parse](A.Quantities,',')) B on A.Key_PS=B.Key_PS 
 ) B

返回

item    Properties    Quantities
Shirt   button-down   4
Shirt   polo          5
Shirt   sleeveless    8

UDF

CREATE FUNCTION [dbo].[udf-Str-Parse] (@String varchar(max),@Delimeter varchar(10))
--Usage: Select * from [dbo].[udf-Str-Parse]('Dog,Cat,House,Car',',')
--       Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ')
--       Select * from [dbo].[udf-Str-Parse]('id26,id46|id658,id967','|')
--       Select * from [dbo].[udf-Str-Parse]('hello world. It. is. . raining.today','.')

Returns @ReturnTable Table (Key_PS int IDENTITY(1,1), Key_Value varchar(max))
As
Begin
   Declare @XML xml;Set @XML = Cast('<x>' + Replace(@String,@Delimeter,'</x><x>')+'</x>' as XML)
   Insert Into @ReturnTable Select Key_Value = ltrim(rtrim(String.value('.', 'varchar(max)'))) FROM @XML.nodes('x') as T(String)
   Return 
End

【讨论】:

    【解决方案3】:
    CREATE FUNCTION [dbo].[ReturnTableOfVarchars]  
      (@IDList varchar(8000))  
        -- allow up to 256 varchar  
        RETURNS @IDTable table (RecordID varchar(256) NOT NULL)  
    AS  
      BEGIN  
        DECLARE @IDListPosition int,   
          @ArrValue varchar(8000)  
        SET @IDList = COALESCE(@IDList,'')  
        IF @IDList<>''  
          BEGIN  
            -- add a comma to end of list  
            SELECT @IDList = @IDList+','  
            -- Loop through the comma delimited string list  
            WHILE PATINDEX('%,%',@IDList)<>0  
            BEGIN  
              -- find the position of the first comma in the list  
              SELECT @IDListPosition = PATINDEX('%,%',@IDList)  
              -- extract the string  
              SELECT @ArrValue = LEFT(@IDList, @IDListPosition - 1)  
              INSERT @IDTable (RecordID) VALUES(@ArrValue)  
              -- remove processed string  
              SELECT @IDList = STUFF(@IDList,1,@IDListPosition ,'')  
            END  
          END  
        RETURN  
      END  
    

    使用:

    declare @itemvalues varchar(100) ,@itemcount varchar(100)
    set @itemvalues='button-down,polo,sleeveless'
    SET @itemcount =' 4,5,8'
    
    select * from dbo.ReturnTableOfVarchars(@itemvalues)
    select * from dbo.ReturnTableOfVarchars(@itemcount)
    

    上面的函数从字符串中拆分值,您可以根据您的流程插入选择或更新中的值。

    【讨论】:

    • 这似乎以与 CSVToTable 函数类似的方式处理。有没有办法加入这些按钮? 4、马球| 5等?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-14
    • 2016-12-13
    • 1970-01-01
    • 1970-01-01
    • 2013-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多