在SQL中将列值转换为一系列行和列

时间:2014-03-29 08:58:02

标签: sql sql-server sql-server-2008

我有一张表,其中一列的数据如下所示:

column value='A,B,C,D,E,F
XA123,Name1,10/20,1.11,27-03-2014,414BJE
XA154,Name2,10/10,1.143,26-03-2014,414B32
XA134,Name21,10/50,1.123,27-03-2014,414B534E
XA125,Name32,20/20,1.1234,17-02-2014,414BJ3
XA124,Name43,30/20,1.165,23-02-2014,414B432
XA1256,Name324,50/60,4.31,07-01-2014,4GHH
XA1252,Name32,70/60,6.61,09-12-2013,414B2E'

现在我需要像在单独的表中那样整理这个列值。 预期产出:

A       B       C       D       E           F
XA123   Name1   10/20   1.11    27-03-2014  414BJE
XA154   Name2   10/10   1.143   26-03-2014  414B32
XA134   Name21  10/50   1.123   27-03-2014  414B534E
XA125   Name32  20/20   1.1234  17-02-2014  414BJ3
XA124   Name43  30/20   1.165   23-02-2014  414B432
XA1256  Name324 50/60   4.31    07-01-2014  4GHH
XA1252  Name32  70/60   6.61    09-12-2013  414B2E

修改

为了得到上述解决方案,首先,我根据新的行字符划分列值并插入到新的表变量中:

Declare @value nvarchar(max) ='A,B,C,D,E,F
    XA123,Name1,10/20,1.11,27-03-2014,414BJE
    XA154,Name2,10/10,1.143,26-03-2014,414B32
    XA134,Name21,10/50,1.123,27-03-2014,414B534E
    XA125,Name32,20/20,1.1234,17-02-2014,414BJ3
    XA124,Name43,30/20,1.165,23-02-2014,414B432
    XA1256,Name324,50/60,4.31,07-01-2014,4GHH
    XA1252,Name32,70/60,6.61,09-12-2013,414B2E'

Declare @t Table
(
   Id int identity(1,1),
   Val VARCHAR(max)
)

while (charindex(char(13),@value)>0)
BEGIN
   insert into @t (Val)
   select substring(@value,1,charindex(char(13),@value))

   set @value = (select substring(@value,charindex(char(13),@value)+1,len(@value)))
END

select * from @t

然后我基于','为@t表变量的每一行创建了一个新的表变量和分隔值。现在希望得到一个通用的更好的解决方案。

再次编辑:

这里我试图为这个问题制作一个通用的解决方案..我们说这些行中的值可以转到任何数字,例如:

A,B,C,D,E,F could be
A,B,C,D,E,F,G
A,B,C,D,E,F,G,H
A,B,C,D,E,F,G,H....Z

所以我试图在下面的代码中使用动态查询来获得解决方案,但是收到错误:必须声明标量变量“@xml”

    Declare @value nvarchar(max) ='A,B,C,D,E,F,G
    XA123,Name1,10/20,1.11,27-03-2014,414BJE,afs
    XA154,Name2,10/10,1.143,26-03-2014,414B32,ag
    XA134,Name21,10/50,1.123,27-03-2014,414B534E,GSF
    XA125,Name32,20/20,1.1234,17-02-2014,414BJ3,GG
    XA124,Name43,30/20,1.165,23-02-2014,414B432,GS
    XA1256,Name324,50/60,4.31,07-01-2014,4GHH,GS
    XA1252,Name32,70/60,6.61,09-12-2013,414B2E,sg'

    declare @query varchar(max)
    declare @xml xml
    declare @count int
    declare @i int = 1

    select @xml = '<item><value>'+replace(replace(@value, ',','</value><value>'), char(10),'</value></item><item><value>')+'</value></item>'

    DECLARE @XmlTable TABLE (XmlResult XML)

    INSERT INTO @XmlTable select @xml

    set @count = (SELECT   XmlResult.value('count(/item/value)', 'int')/XmlResult.value('count(/item)', 'int') FROM   @XmlTable)

    SET @query = 'select '

    WHILE (@i <= @count)
    BEGIN  
        IF(@i!=1)
        BEGIN
            set @query = @query + ', '
        END
        set @query = @query + 'N.value(''substring(value['+ cast(@i as varchar) +'],1)'',''varchar(10)'')'
        SET @i = @i + 1

    END
    set @query = @query + ' from ' + '@xml.nodes' + '(''item'') as T(N)'

-- select @query

    EXEC(@query)

伙计们,任何建议......

2 个答案:

答案 0 :(得分:2)

这是......

Declare @value nvarchar(max) ='A,B,C,D,E,F
    XA123,Name1,10/20,1.11,27-03-2014,414BJE
    XA154,Name2,10/10,1.143,26-03-2014,414B32
    XA134,Name21,10/50,1.123,27-03-2014,414B534E
    XA125,Name32,20/20,1.1234,17-02-2014,414BJ3
    XA124,Name43,30/20,1.165,23-02-2014,414B432
    XA1256,Name324,50/60,4.31,07-01-2014,4GHH
    XA1252,Name32,70/60,6.61,09-12-2013,414B2E'

declare @xml xml

select @xml = '<item><value>'+replace(replace(@value, ',','</value><value>'), char(13),'</value></item><item><value>')+'</value></item>'

select 
N.value('substring(value[1],1)', 'varchar(10)') as V1,
N.value('substring(value[2],1)', 'varchar(10)') as V2,
N.value('substring(value[3],1)', 'varchar(10)') as V3,
N.value('substring(value[4],1)', 'varchar(10)') as V4,
N.value('substring(value[5],1)', 'varchar(10)') as V5,
N.value('substring(value[6],1)', 'varchar(10)') as V6
from @xml.nodes('item') as T(N)

答案 1 :(得分:0)

试试这个,首先创建一个标量函数AS

Create FUNCTION [dbo].[funcSplit_OneVal]
(
    @param      NVARCHAR(MAX),
    @delimiter  CHAR(1),
    @nThVal   int
)
RETURNS varchar(50) 

--select  dbo.funcSplit_OneVal('1,2,3,4',',',5)
AS


BEGIN

    Declare @t TABLE (val NVARCHAR(MAX))
    Declare @retVal  varchar(50) = ''

    SET @param += @delimiter

    ;WITH a AS
    (
        SELECT CAST(1 AS BIGINT) f,
               CHARINDEX(@delimiter, @param) t,
               1 seq
        UNION ALL
        SELECT t + 1,
               CHARINDEX(@delimiter, @param, t + 1),
               seq + 1
        FROM   a
        WHERE  CHARINDEX(@delimiter, @param, t + 1) > 0
    )
    INSERT @t
    SELECT SUBSTRING(@param, f, t - f)         
    FROM    a
           OPTION(MAXRECURSION 0)
    select top (@nThVal) @retVal =val from @t       
    RETURN @retVal
END

然后执行以下脚本,

Declare @value nvarchar(max) ='A,B,C,D,E,F
    XA123,Name1,10/20,1.11,27-03-2014,414BJE
    XA154,Name2,10/10,1.143,26-03-2014,414B32
    XA134,Name21,10/50,1.123,27-03-2014,414B534E
    XA125,Name32,20/20,1.1234,17-02-2014,414BJ3
    XA124,Name43,30/20,1.165,23-02-2014,414B432
    XA1256,Name324,50/60,4.31,07-01-2014,4GHH
    XA1252,Name32,70/60,6.61,09-12-2013,414B2E'

DECLARE @xml AS XML = CAST(('<X>'+REPLACE(@value,' ' ,'</X><X>')+'</X>') AS XML)
;With CTE as 
(
SELECT C.value('.', 'varchar(250)') AS value
FROM @xml.nodes('X') as X(C)
)
select dbo.funcSplit_OneVal(value,',',1)
        ,dbo.funcSplit_OneVal(value,',',2)
        ,dbo.funcSplit_OneVal(value,',',3)
        ,dbo.funcSplit_OneVal(value,',',4)
        ,dbo.funcSplit_OneVal(value,',',5)
        ,dbo.funcSplit_OneVal(value,',',6)
     from CTE
where len(value) > 0

如果需要,您可以从变量&amp;中删除'A,B,C ...在最后选择中给予alise。