将字符串拆分成列中的单词

时间:2018-10-08 05:51:26

标签: sql sql-server tsql sql-server-2014

我希望在SQL Server 2014中将字符串拆分成列中的单词。我找到了一些解决方案,但所有解决方案都将结果按行给出。如何将下面的字符串分成几列?

  

“第一,第二,第三,第四,第五”

3 个答案:

答案 0 :(得分:2)

您可以使用SQL split string function将字符串分成单词,并使用单词在原始字符串中的顺序,可以使用CASE语句(例如PIVOT查询)并显示为列

这是一个样本

declare @string varchar(max) = 'First Second Third Fourth Fifth'

;with cte as (
select
    case when id = 1 then val end as Col1,
    case when id = 2 then val end as Col2,
    case when id = 3 then val end as Col3,
    case when id = 4 then val end as Col4,
    case when id = 5 then val end as Col5
from dbo.split( @string,' ')
)
select
    max(Col1) as Col1,
    max(Col2) as Col2,
    max(Col3) as Col3,
    max(Col4) as Col4,
    max(Col5) as Col5
from cte

如果无法创建UDF,则可以按以下方式在SQL代码中使用逻辑

请注意,如果您的数据位于数据库表列中,则只需替换第一个SQL CTE expression

中的列内容
declare @string varchar(max) = 'First Second Third Fourth Fifth'

;with cte1 as (
    select convert(xml, N'<root><r>' + replace(@string,' ','</r><r>') + '</r></root>') as rawdata
), cte2 as (
  select
    ROW_NUMBER() over (order by getdate()) as id,
    r.value('.','varchar(max)') as val
  from cte1
  cross apply rawdata.nodes('//root/r') as records(r)
)
select
    max(Col1) as Col1,
    max(Col2) as Col2,
    max(Col3) as Col3,
    max(Col4) as Col4,
    max(Col5) as Col5
from (
    select
        case when id = 1 then val end as Col1,
        case when id = 2 then val end as Col2,
        case when id = 3 then val end as Col3,
        case when id = 4 then val end as Col4,
        case when id = 5 then val end as Col5
    from cte2
) t

答案 1 :(得分:2)

您可以使用XML并按其位置抓取元素:

DECLARE @YourString VARCHAR(100)='First Second Third Fourth Fifth';

WITH StringAsXML AS
(
    SELECT CAST('<x>' + REPLACE((SELECT @YourString AS [*] FOR XML PATH('')),' ','</x><x>') + '</x>' AS XML) TheXml
)
SELECT TheXml.value('x[1]/text()[1]','nvarchar(max)') AS FirstElement
      ,TheXml.value('x[2]/text()[1]','nvarchar(max)') AS SecondElement
      ,TheXml.value('x[3]/text()[1]','nvarchar(max)') AS ThirdElement
      ,TheXml.value('x[4]/text()[1]','nvarchar(max)') AS FourthElement
      ,TheXml.value('x[5]/text()[1]','nvarchar(max)') AS FifthElement
FROM StringAsXML;

备注

您可以使用PIVOT条件聚合FROM(VALUES())或以上版本。但是这些方法中的任何一种都需要一组已知的列(已知的元素数量或至少最大的元素数量)。

如果您不能依靠这样的知识,则可以使用动态创建的SQL 。这将意味着在字符串基础上创建一个工作语句,并使用EXEC进行动态执行。

更新:一种动态方法

这种方法将处理可变数量的元素

DECLARE @YourString VARCHAR(100)='First Second Third Fourth Fifth';
DECLARE @Delimiter CHAR(1)=' ';
DECLARE @countElements INT = LEN(@YourString)-LEN(REPLACE(@YourString,@Delimiter,''));

DECLARE @Statement VARCHAR(MAX)=
'WITH StringAsXML AS
(
    SELECT CAST(''<x>'' + REPLACE((SELECT ''ReplaceYourString'' AS [*] FOR XML PATH('''')),'' '',''</x><x>'') + ''</x>'' AS XML) TheXml
)
SELECT ReplaceColumnList
FROM StringAsXML;';

DECLARE @columnList VARCHAR(MAX);

WITH cte AS
(
    SELECT 1 AS ElementCounter
          ,CAST('TheXml.value(''x[1]/text()[1]'',''nvarchar(max)'') AS Element_01' AS VARCHAR(MAX)) AS ColStatement
    UNION ALL 
    SELECT cte.ElementCounter+1
          ,cte.ColStatement + CAST(',TheXml.value(''x[' + CAST(cte.ElementCounter+1 AS VARCHAR(10)) + ']/text()[1]'',''nvarchar(max)'') AS Element_' + REPLACE(STR(cte.ElementCounter + 1,2),' ','0') AS VARCHAR(MAX))
    FROM cte
    WHERE cte.ElementCounter <= @countElements
)
SELECT @columnList=(SELECT TOP 1 cte.ColStatement FROM cte ORDER BY cte.ElementCounter DESC)

--replace the string you want to split
SET @Statement = REPLACE(@Statement,'ReplaceYourString',@YourString);
--replace the columnList
SET @Statement = REPLACE(@Statement,'ReplaceColumnList',@columnList);

EXEC(@Statement);

更新2:我所知道的最小的全嵌入式且位置安全拆分器

尝试一下:

DECLARE @inp VARCHAR(200) = 'First Second Third Fourth Fifth';
DECLARE @dlmt VARCHAR(100)=' ';

;WITH
a AS (SELECT n=0, i=-1, j=0 UNION ALL SELECT n+1, j, CHARINDEX(@dlmt, @inp, j+1) FROM a WHERE j > i),
b AS (SELECT n, SUBSTRING(@inp, i+1, IIF(j>0, j, LEN(@inp)+1)-i-1) s FROM a WHERE i >= 0)
SELECT * FROM b;

为了使它完整,请执行以下操作:将上面的微小拆分器与PIVOT组合在一起:

;WITH
a AS (SELECT n=0, i=-1, j=0 UNION ALL SELECT n+1, j, CHARINDEX(@dlmt, @inp, j+1) FROM a WHERE j > i),
b AS (SELECT n, SUBSTRING(@inp, i+1, IIF(j>0, j, LEN(@inp)+1)-i-1) s FROM a WHERE i >= 0)

SELECT p.* 
FROM b
PIVOT(MAX(s) FOR n IN([1],[2],[3],[4],[5])) p;

答案 2 :(得分:0)

您可以将parsename函数用作:

create table tab ( str varchar(100));

insert into tab values('First Second Third Fourth Fifth');

with t as
(
select replace(str,' ','.') as str
  from tab
)    
Select substring(str,1,charindex('.',str)-1) as col_first,
       parsename(substring(str,charindex('.',str)+1,len(str)),4) as col_second,
       parsename(substring(str,charindex('.',str)+1,len(str)),3) as col_third,
       parsename(substring(str,charindex('.',str)+1,len(str)),2) as col_fourth,
       parsename(substring(str,charindex('.',str)+1,len(str)),1) as col_fifth
  from t;

col_first   col_second  col_third   col_fourth  col_fifth
---------   ----------  ---------   ----------  ---------
First       Second      Third       Fourth      Fifth

P.S。首先,需要将主字符串分成最多3个三点(.)字符的部分(否则该功能不起作用)。这是对parsename的限制。

Rextester Demo