【问题标题】:SQL Server : split multiple strings into one row eachSQL Server:将多个字符串分别拆分为一行
【发布时间】:2016-10-11 12:12:55
【问题描述】:

我是 SQL Server 的新手,我正在处理以下问题。

假设我有一个看起来像这样的列:

ID  String
-------------------------
1   Today is a good day!
2   Whatever
3   Hello my friend

所以我的目标是将这些句子拆分为:

ID  String1   String2    String3    String4    String5
------------------------------------------------------
1   Today     is         a          good       day!
2   Whatever
3   Hello     my         friend

我尝试使用此代码:

CREATE FUNCTION [dbo].[SplitString] 
     (@str nvarchar(max), 
      @separator char(1))
RETURNS TABLE
AS
    RETURN (
         WITH tokens(p, a, b) AS 
         (
             SELECT
                 CAST(1 AS BIGINT), 
                 CAST(1 AS BIGINT), 
                 CHARINDEX(@separator, @str)

             UNION ALL

             SELECT
                 p + 1, 
                 b + 1, 
                 CHARINDEX(@separator, @str, b + 1)
             FROM 
                 tokens
             WHERE
                 b > 0
         )
         SELECT
             --p-1 ItemIndex,
             SUBSTRING(@str, a, 
                           CASE WHEN b > 0 THEN b-a 
                                ELSE LEN(@str) 
                           END) AS Item
         FROM tokens)
GO

我在 Stackoverflow 上找到的。

它似乎适用于单个字符串,但它不适用于多个字符串。 它会将每个单词放在一个新行中,如下所示:

Item
Today
is
a
good
day!

那么我该如何调整代码,使其达到预期?

还有一个问题是,我真的不知道每个字符串中的单词数。

所以它可能会有所不同,例如从 1 个字到 100 个字。

如果有人能帮我解决这个问题,我会非常高兴,因为我才刚刚开始学习如何使用 SQL。

谢谢! MG

【问题讨论】:

  • 看起来像是学校的家庭作业。如果对列号没有限制,则必须使用动态查询。
  • 这里有一些性能更好的分离器选项。 sqlperformance.com/2012/07/t-sql-queries/split-strings 要将其重新放入列中,您需要使用动态交叉表或动态枢轴。
  • 对于刚刚学习 t-sql 的人来说,这是一个非常高级的问题。
  • @SeanLange 这是一个 ETL 类。 ;)

标签: sql sql-server string split


【解决方案1】:

借助 XML:

DECLARE @xml xml

;WITH cte AS (
SELECT *
FROM (VALUES
(1, 'Today is a good day!'),
(2, 'Whatever'),
(3, 'Hello my friend')
) as t(ID, String)
)

SELECT @xml = (
SELECT CAST('<i id="' + CAST(ID as nvarchar(10)) + '"><w>' + REPLACE(REPLACE(String,' ','</w><w>'),'&','&amp;') + '</w></i>' as xml)
FROM cte
FOR XML PATH('')
)

SELECT  t.v.value('@id','int') as ID,
        t.v.value('w[1]','nvarchar(10)') as String1,
        t.v.value('w[2]','nvarchar(10)') as String2,
        t.v.value('w[3]','nvarchar(10)') as String3,
        t.v.value('w[4]','nvarchar(10)') as String4,
        t.v.value('w[5]','nvarchar(10)') as String5,
        t.v.value('w[6]','nvarchar(10)') as String6
FROM @xml.nodes('/i') as t(v)

输出:

ID          String1    String2    String3    String4    String5    String6
----------- ---------- ---------- ---------- ---------- ---------- ----------
1           Today      is         a          good       day!       NULL
2           Whatever   NULL       NULL       NULL       NULL       NULL
3           Hello      my         friend     NULL       NULL       NULL

编辑

与实际表格一起使用:

DECLARE @xml xml

SELECT @xml = (
SELECT CAST('<i id="' + CAST(ID as nvarchar(10)) + '"><w>' + REPLACE(big_string,' ','</w><w>') + '</w></i>' as xml)
FROM [table]
FOR XML PATH('')
)

SELECT  t.v.value('@id','int') as ID,
        t.v.value('w[1]','nvarchar(10)') as String1,
        t.v.value('w[2]','nvarchar(10)') as String2,
        t.v.value('w[3]','nvarchar(10)') as String3,
        t.v.value('w[4]','nvarchar(10)') as String4,
        t.v.value('w[5]','nvarchar(10)') as String5,
        t.v.value('w[6]','nvarchar(10)') as String6,
        t.v.value('w[7]','nvarchar(10)') as String7
FROM @xml.nodes('/i') as t(v)

【讨论】:

  • 这就是我正在寻找的代码。一个简短的问题: ist 是否适用于大于 6 个单词的字符串?它会删除单词 [7:] 吗?那样就好了。
  • 好的!所以我现在尝试做的是根据我的实际需要调整代码。我有一个表“表”,我只希望一列“big_string”成为代码和输出的一部分。我自己尝试过,但我没有像那样调整它。
  • 我在答案中添加了查询,请检查。
  • 我收到此错误消息:“消息 9411,级别 16,状态 1,第 3 行 XML 解析:第 1 行,字符 41,需要分号”。如果我双击错误消息,他会选择“SELECT @xml = (”这一行。另外,我真的需要 ID 吗?我知道我的原始示例就是这样,但基本上我只有一个相关列。
  • 如果没有 ID,您将无法将结果输出为行,它将只是一个包含许多列的大行。如果您只有一列,则可以使用此 ROW_NUMBER() OVER(ORDER BY big_string) 而不是 ID。
【解决方案2】:

我编辑了您的代码。尝试运行它。列是根据要追加的行动态创建的。结果是这样的:return rows 它不按顺序排列。尝试编辑上面的代码以包含您的 ID,以便它再次正常。

DECLARE @TBL TABLE (Id int, Description varchar(max))
CREATE table #tblResult(Description varchar(max))

INSERT INTO @TBL
SELECT 1, 'Today is a good day!'

DECLARE @separator varchar(1) = ' ', @str varchar(max)
SELECT @str = Description FROM @TBL


     ;WITH tokens(p, a, b) AS 
     (
         SELECT
             CAST(1 AS BIGINT), 
             CAST(1 AS BIGINT), 
             CHARINDEX(@separator, @str)

         UNION ALL

         SELECT
             p + 1, 
             b + 1, 
             CHARINDEX(@separator, @str, b + 1)
         FROM 
             tokens
         WHERE
             b > 0
     )

     INSERT INTO #tblResult
     SELECT
         SUBSTRING(@str, a, 
                       CASE WHEN b > 0 THEN b-a 
                            ELSE LEN(@str) 
                       END) AS Item
                       FROM tokens

    DECLARE @x nvarchar(MAX), @query nvarchar(MAX)

    select @x = STUFF((SELECT ',' + QUOTENAME(Description) 
                from #tblResult
                group by Description
                order by Description
        FOR XML PATH(''), TYPE
        ).value('.', 'nvarchar(MAX)') 
    ,1,1,'')


    set @query = N'SELECT ' + @x + N' from 
         (
            select Description
            from #tblResult
        ) x
        pivot 
        (
            max(Description)
            for Description in (' + @x + N')
        ) p '

  exec sp_executesql @query;


  drop table #tblResult

【讨论】:

  • 这段代码似乎也可以,但是输出不正确!?
猜你喜欢
  • 2017-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-16
  • 1970-01-01
  • 1970-01-01
  • 2018-04-18
  • 1970-01-01
相关资源
最近更新 更多