SQL Server 2012将几个逗号分隔的值转换为表行/列

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL Server 2012将几个逗号分隔的值转换为表行/列相关的知识,希望对你有一定的参考价值。

目前,我有一个以下列方式存储历史数据的表。我无法控制此服务器或数据的存储方式。

    ID   |  FName  |  LName  |Stuff| More
 --------+---------+---------+-----+------
 1,2,3,4 | j,p,g,r | l,m,h,s | ,,, | a,,b,

我需要将这些数据放入结果集中,以便它采用以下格式:

    ID   |  FName  |  LName  |Stuff| More
 --------+---------+---------+-----+------
     1   |    j    |    l    |     | a
     2   |    p    |    m    |     | 
     3   |    g    |    h    |     | b
     4   |    r    |    s    |     | 

我想避免使用函数,因为我不确定我将对其他环境中的服务器进行访问。我尝试过使用xml和cross apply,我可以为一个奇异的字段工作,但我似乎无法让全表工作。

任何建议将不胜感激,

谢谢~JM

答案

它可以通过递归查询来完成

;WITH CTE(ID, ID_tmp, FName, FName_tmp, LName, LName_tmp, Stuf, Stuf_tmp, more, more_tmp) 
AS
(
    SELECT CAST(LEFT(ID, CHARINDEX(',',ID+',')-1) AS NVARCHAR(50)) ID,
            STUFF(ID, 1, CHARINDEX(',',ID+','), '') ID_tmp,
            CAST(LEFT(FName, CHARINDEX(',',FName+',')-1) AS NVARCHAR(50)) FName,
            STUFF(FName, 1, CHARINDEX(',',FName+','), '') ID_tmp,
            CAST(LEFT(LName, CHARINDEX(',',LName+',')-1) AS NVARCHAR(50)) LName,
            STUFF(LName, 1, CHARINDEX(',',LName+','), '') LName_tmp,
            CAST(LEFT(Stuf, CHARINDEX(',',Stuf+',')-1) AS NVARCHAR(50)) Stuf,
            STUFF(Stuf, 1, CHARINDEX(',',Stuf+','), '') Stuf_tmp,
            CAST(LEFT(more, CHARINDEX(',',more+',')-1) AS NVARCHAR(50)) more,
            STUFF(more, 1, CHARINDEX(',',more+','), '') more_tmp
    FROM    TAB
        UNION ALL
    SELECT CAST(LEFT(ID_tmp, CHARINDEX(',',ID_tmp+',')-1) AS NVARCHAR(50)) ID,
        STUFF(ID_tmp, 1, CHARINDEX(',',ID_tmp+','), '') ID_tmp,
        CAST(LEFT(FName_tmp, CHARINDEX(',',FName_tmp+',')-1) AS NVARCHAR(50)) FName,
        STUFF(FName_tmp, 1, CHARINDEX(',',FName_tmp+','), '') FName_tmp,
        CAST(LEFT(LName_tmp, CHARINDEX(',',LName_tmp+',')-1) AS NVARCHAR(50)) LName,
        STUFF(LName_tmp, 1, CHARINDEX(',',LName_tmp+','), '') LName_tmp,
        CAST(LEFT(Stuf_tmp, CHARINDEX(',',Stuf_tmp+',')-1) AS NVARCHAR(50)) Stuf,
        STUFF(Stuf_tmp, 1, CHARINDEX(',',Stuf_tmp+','), '') Stuf_tmp,
        CAST(LEFT(more_tmp, CHARINDEX(',',more_tmp+',')-1) AS NVARCHAR(50)) more,
        STUFF(more_tmp, 1, CHARINDEX(',',more_tmp+','), '') more_tmp
    FROM CTE
    WHERE ID_tmp > ''
)
SELECT  ID, FName , LName, stuf, more
FROM    CTE

enter image description here

另一答案

如果您想避免使用UDF,那么XML nodes()方法仍然能够通过使用多个CTE方法来帮助您。

WITH cteId AS
(
    SELECT Ids.value('.', 'INT') Id FROM
    (
       SELECT 
         cast('<x>'+replace(Id, ',', '</x><x>')+'</x>' as xml) as Id 
        FROM table t 
    )a CROSS APPLY Id.nodes ('/x') as split(Ids)
), ctefname AS
(
    SELECT
            row_number() over (order by (select 1)) Seq,
            FNames.value('.', 'varchar') FNames FROM
    (
       SELECT 
         cast('<x>'+replace(FName, ',', '</x><x>')+'</x>' as xml) as FName 
       FROM table t 
    )a CROSS APPLY FName.nodes ('/x') as split(FNames)
), cteLname AS
(
    SELECT
            row_number() over (order by (select 1)) Seq,
            LNames.value('.', 'varchar') LNames FROM
    (
       SELECT
           cast('<x>'+replace(LName, ',', '</x><x>')+'</x>' as xml) as LName 
       FROM table t 
    )a CROSS APPLY LName.nodes ('/x') as split(LNames)
), ...

SELECT 
       id.Id, fn.FNames, ln.LNames, ... 
FROM cteId id
INNER JOIN ctefname fn on fn.Seq = id.Id
INNER JOIN cteLname ln on ln.Seq = id.Id
... 

以上是关于SQL Server 2012将几个逗号分隔的值转换为表行/列的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 2005 中的逗号分隔值插入

SQL Server用逗号分隔[重复]

在sql server数据库中查询一个用逗号分隔的字段的问题

从一个表中选择一个逗号分隔的值,并使用 SQL Server 中的函数在另一个表中的 where 条件中使用它

此查询对创建逗号分隔列表 SQL Server 做了啥?

BULK INSERT将CSV或TXT文件导入到SQL Server