【问题标题】:SQL Server 2012 Comma ParsingSQL Server 2012 逗号解析
【发布时间】:2017-01-03 13:05:16
【问题描述】:

我正在尝试从 SQL Server 2012 的列中解析一些逗号分隔值,同时仍保留左侧和右侧列中的数据。

我见过一些类似的主题解决方案,但似乎都不是我想要的。

我有这个:

FirstName   LastName    userid   Regions          ViewCosts HelpReviewCosts
---------------------------------------------------------------------
Darron      Peters      ya00003   All                y         y
John        Davies      ya30982   NA, EM, AP, LA     n         n

我正在尝试解析 Regions 列,以便得到这个:

FirstName   LastName    userid   Regions          ViewCosts HelpReviewCosts
---------------------------------------------------------------------
Darron      Peters      ya00003   All                y         y
John        Davies      ya30982   NA                 n         n
John        Davies      ya30982   EM                 n         n
John        Davies      ya30982   AP                 n         n
John        Davies      ya30982   LA                 n         n

【问题讨论】:

标签: sql-server split sql-server-2012


【解决方案1】:

关于如何拆分/解析字符串的示例有数千个。下面是两个示例,一个带有 UDF,另一个没有。两者都使用 CROSS APPLY

使用 UDF

Declare @Yourtable table (FirstName varchar(25)   ,LastName varchar(25),userid  varchar(25),  Regions varchar(50), ViewCosts varchar(25), HelpReviewCosts varchar(25))
Insert Into @Yourtable values
('Darron','Peters','ya00003','All','y','y'),
('John','Davies','ya30982','NA, EM, AP, LA','n','n')

Select A.FirstName
      ,A.LastName    
      ,A.userid   
      ,Regions =B.RetVal
      ,A.ViewCosts 
      ,A.HelpReviewCosts
 From @Yourtable A
 Cross Apply [dbo].[udf-Str-Parse](A.Regions,',') B

没有 UDF

Select A.FirstName
      ,A.LastName    
      ,A.userid   
      ,Regions =B.RetVal
      ,A.ViewCosts 
      ,A.HelpReviewCosts
 From @Yourtable A
 Cross Apply ( 
                Select RetSeq = Row_Number() over (Order By (Select null))
                      ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
                From  (Select x = Cast('<x>'+ replace((Select A.Regions as [*] For XML Path('')),',','</x><x>')+'</x>' as xml).query('.')) as A 
                Cross Apply x.nodes('x') AS B(i)
      ) B

两个回报

UDF(如果需要)

CREATE FUNCTION [dbo].[udf-Str-Parse] (@String varchar(max),@Delimiter varchar(10))
Returns Table 
As
Return (  
    Select RetSeq = Row_Number() over (Order By (Select null))
          ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
    From  (Select x = Cast('<x>'+ replace((Select @String as [*] For XML Path('')),@Delimiter,'</x><x>')+'</x>' as xml).query('.')) as A 
    Cross Apply x.nodes('x') AS B(i)
);
--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]('this,is,<test>,for,< & >',',')

【讨论】:

    【解决方案2】:

    我建议你使用 STRING_SPLIT 函数

    WITH 
    CTE_Sample AS
    (
        SELECT 'All'            AS txt
        UNION ALL
        SELECT 'NA, EM, AP, LA' AS txt
    )
    
    SELECT
        txt,
        value
      FROM CTE_Sample
      CROSS APPLY STRING_SPLIT(txt, ','); 
    

    【讨论】:

      【解决方案3】:

      如果你不想'udf'和'string_split'函数,那么你可以使用这个查询。它适用于逗号分隔的大字符串,也比其他的快得多......

      `CREATE TABLE TB (Number INT)
       DECLARE @I INT=0
       WHILE @I<1000
       BEGIN
       INSERT INTO TB VALUES (@I)
       SET @I=@I+1
       END
       SELECT 
          FirstName
          ,LastName
          ,userid
          ,S_DATA
          ,ViewCosts
          ,HelpReviewCosts
      FROM    (
          SELECT
                  FirstName
                  ,LastName
                  ,userid
                  ,CASE   WHEN LEN(LIST2)>0 THEN LTRIM(RTRIM(SUBSTRING(LIST2, NUMBER+1, CHARINDEX(',', LIST2, NUMBER+1)-NUMBER - 1)))
                          ELSE NULL
                  END AS S_DATA 
                  ,ViewCosts
                  ,HelpReviewCosts
                 ,NUMBER
          FROM(
              SELECT  FirstName
                      ,LastName
                      ,userid
                      ,','+Regions+',' LIST2
                      ,ViewCosts
                      ,HelpReviewCosts
                      FROM Tb1
              )DT 
               LEFT OUTER JOIN TB N ON (N.NUMBER < LEN(DT.LIST2)) OR (N.NUMBER=1 AND DT.LIST2 IS NULL)
              WHERE SUBSTRING(LIST2, NUMBER, 1) = ',' OR LIST2 IS NULL
           ) DT2
           WHERE S_DATA<>''
      

      this is my Output

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-02-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-06
        • 1970-01-01
        • 2016-12-18
        相关资源
        最近更新 更多