【问题标题】:How to split a comma delimited string using ONLY a select statement?如何仅使用 select 语句拆分逗号分隔的字符串?
【发布时间】:2018-08-21 22:45:48
【问题描述】:

情况如下:

  • 我无法实现自定义函数。请让我们不要讨论为什么。网站就是这样,我无法改变
  • 我需要使用某种 SELECT 语句以某种方式拆分逗号分隔的值
  • 我不能使用内置的 STRING_SPLIT 函数,因为我需要将数据库兼容地设置为 130,但由于权限问题我不能这样做

既然都提到了,我怎么能用 select 语句吐出像“This,Is,A,Sentence”这样的东西?

我使用的是 SQL Server 2008。

【问题讨论】:

  • T-SQL split string的可能重复
  • 至少有一个关于该骗子的答案显示了如何使用 CTE 做到这一点。如果您不能使用 CTE 或临时函数进行交易,那么您就不走运了
  • @morgan-thrapp,不,您不必使用 CTE、proc 或 UDF。请参阅下面的答案。
  • @digital.aaron 我的意思是,临时表和 CTE 并没有什么不同。
  • 一开始你为什么要让自己陷入这种境地? SQL Server 有 设计 用于保存多个值(表、xml)的类型,但是当 T-SQL 的字符串操作功能非常薄弱时,你却让别人给你一个字符串。

标签: sql-server split


【解决方案1】:

查询

 Declare @String nvarchar(500) = 'This,Is,A,Sentence';

SELECT  Split.a.value('.', 'VARCHAR(100)') Words
FROM (
      SELECT Cast ('<X>' 
                   + Replace(@String, ',', '</X><X>') 
                   + '</X>' AS XML) AS Data
     ) AS t CROSS APPLY Data.nodes ('/X') AS Split(a); 

结果集:

╔══════════╗
║  Words   ║
╠══════════╣
║ This     ║
║ Is       ║
║ A        ║
║ Sentence ║
╚══════════╝

【讨论】:

    【解决方案2】:

    给推荐 cte 的人加 1。您可能会发现他们的建议将是最佳选择。我为此使用的代码通常包含在用户定义的函数中,但我已将其剥离出来作为示例:

    DECLARE @str       NVARCHAR(MAX) = 'This,Is,A,Sentence'
    ,       @Delimiter NCHAR(1)      = ',';
    
    WITH cte AS
        (SELECT 1                                                  AS ID
         ,      CASE WHEN CHARINDEX(@Delimiter, @str, 1) = 0 THEN @str
                     ELSE LEFT(@str, CHARINDEX(@Delimiter, @str, 1) - 1)
                END  Words
         ,      CASE WHEN CHARINDEX(@Delimiter, @str, 1) = 0 THEN ''
                     ELSE STUFF(@str, 1, CHARINDEX(@Delimiter, @str, 1), '')
                END  Remainder
         UNION ALL
         SELECT cte.ID + 1
         ,      CASE WHEN CHARINDEX(@Delimiter, cte.Remainder, 1) = 0 THEN cte.Remainder
                     ELSE LEFT(cte.Remainder, CHARINDEX(@Delimiter, cte.Remainder, 1) - 1)
                END
         ,      CASE WHEN CHARINDEX(@Delimiter, cte.Remainder, 1) = 0 THEN ''
                     ELSE STUFF(cte.Remainder, 1, CHARINDEX(@Delimiter, cte.Remainder, 1), '')
                END  Remainder
           FROM cte
           WHERE Remainder <> '')
    SELECT  cte.ID [Index]
    ,       cte.Words
      FROM  cte;
    

    结果集:

    如果您不需要它,当然可以去掉 id/index 列

    顺便说一句,如果你将它与最新版本的 SQL Server 中内置的拆分功能进行比较,这实际上要高效得多。两者一起运行 cte 版本 16% 的负载,内置功能 84%。这是一个很大的不同。

    【讨论】:

      【解决方案3】:

      嗯,不是一个 SELECT,但这里有一些你可以在不调用 proc 或 UDF 的情况下使用的东西:

      CREATE TABLE #OutputTable( SValues VARCHAR(100) )
      
      DECLARE @StringInput VARCHAR(MAX)
              ,@StringTemp    VARCHAR(100)
      
      WHILE LEN(@StringInput) > 0
      BEGIN
          SET @StringTemp      = 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 ( SValues )
          VALUES ( @StringTemp )
      END
      

      #OutputTable 将保存每个“单词”作为记录。然后您可以根据需要进行查询。

      【讨论】:

        【解决方案4】:

        如果你可以使用 CTE .....

        DECLARE @word VARCHAR(200) = 'This,Is,A,Sentence'
        
        ;WITH
        a AS (SELECT i=-1, j=0 UNION ALL SELECT j, CHARINDEX(',', @word, j + 1) FROM a WHERE j > i),
        b AS (SELECT SUBSTRING(@word, i+1, IIF(j>0, j, LEN(@word)+1)-i-1) word FROM a WHERE i >= 0)
        SELECT * FROM b
        

        【讨论】:

          【解决方案5】:

          感谢提问:Find nth Occurrence in a string

          DECLARE @Val varchar(200) = 'this,is,a,string'
          
          ;with t as (
              select @Val as val, 1 as starts, charindex(',', @Val) as pos 
              union all
              select @Val, pos + 1, charindex(',', @Val, pos + 1)
              from t
              where pos > 0
          )
          select 
              *, substring(@Val, starts, case when pos > 0 then pos - starts else len(@Val) end) token
          from T
          order by starts
          

          【讨论】:

            【解决方案6】:

            这就是我要做的:

                DECLARE @t TABLE     
            (
            ID INT,
            Words VARCHAR(500)
            )
            INSERT @t VALUES (1,'This,Is,A,Sentence')
            
            
            
            SELECT 
            LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)'))) AS Words
            FROM
            (
            SELECT CAST('<XMLRoot><RowData>' + REPLACE(Words,',','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x
            FROM   @t
            )t
            CROSS APPLY x.nodes('/XMLRoot/RowData')m(n)
            

            结果:

            |Words|
             This
             Is
             A
             Sentence
            

            【讨论】:

              猜你喜欢
              • 2015-03-07
              • 2012-05-24
              • 2018-12-21
              • 2013-06-04
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多