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

时间:2018-03-02 23:33:29

标签: sql sql-server 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,我可以为一个奇异的字段工作,但我似乎无法让全表工作。

非常感谢任何建议,

由于 〜JM

2 个答案:

答案 0 :(得分:1)

可以通过递归查询

完成
;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

答案 1 :(得分:0)

如果您想避免使用 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
...