如何在遇到特殊字符时拆分列

时间:2017-08-01 08:25:46

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

我需要将单列数据拆分为多列 我有这样的数据

ID       NAME                COMMENT
1        TEST      Reg: 0001 Inv: B0001 Cus: A0001 Br: F0001
2        TEST1     Reg: 0002 Inv: B0002 Cus: A0002 Br: F0002
3        TEST2     Reg: 0003 Inv: B0003 Cus: A0003 Br: F0003
4        TEST3     Reg: 0004 Inv: B0004 Cus: A0004 Br: F0004
5        TEST4     Reg: 0005 Inv: B0005 Cus: A0005 Br: F0005
5        TEST4     Reg: 00010 Inv: B00010 Cus: A00010 Br: F00010

我需要在表注释中拆分数据,所以它变成这样:

REG        INV      BR 
0001      B0001    F0001
0002      B0002    F0002
0003      B0003    F0003
0004      B0004    F0004
0005      B0005    F0005
00010      B00010    F00010    

有任何建议怎么做?

我的代码。

;WITH Split_Names (Comment)
    AS
    -- Define the CTE query.
    (
        SELECT 
        CONVERT(XML,'<COMMENTS><Comment>'  
        + REPLACE(
     REPLACe(
     REPLACE(
     REPLACE(
    REPLACE(
     REPLACE(Comment,'Reg:',''),'Inv:',','),'Cus:',','),'Br:',','),' ' ,'')
        ,',', '</Comment><Comment>') + '</Comment></COMMENTS>') AS xmlComments
         FROM GenTransaction
    )
    -- Define the outer query referencing the CTE name.
     SELECT      
     Comment.value('/COMMENTS[1]/Comment[1]','varchar(100)') AS Reg,    
     Comment.value('/COMMENTS[1]/Comment[2]','varchar(100)') AS Inv,
     Comment.value('/COMMENTS[1]/Comment[3]','varchar(100)') AS Cus,
     Comment.value('/COMMENTS[1]/Comment[4]','varchar(100)') AS Br

     FROM Split_Names

2 个答案:

答案 0 :(得分:2)

以下解决方案应该有效

[1]无论哪个订单用于Comment列(Reg, Inv, Cus BrCus, Br, Reg, Inv或其他内容)以及

[2] Comment列的某些项目可能会丢失(例如TEST4 / Cus缺失)

[3]如果Comment包含XML保留字符,则应使用REPLACE(t1.Comment,而不是REPLACE((SELECT t1.Comment AS '*' FOR XML PATH('')),

DECLARE @Table1 TABLE (
    ID      INT NOT NULL,
    Name    NVARCHAR(50),
    Comment NVARCHAR(500)
);
INSERT  @Table1 (ID, Name, Comment)
VALUES 
(1, 'TEST ', 'Reg: 0001 Inv: B0001 Cus: A0001 Br: F0001'),
(2, 'TEST1', 'Reg: 0002 Inv: B0002 Cus: A0002 Br: F0002'),
(3, 'TEST2', 'Reg: 0003 Inv: B0003 Cus: A0003 Br: F0003'),
(4, 'TEST3', 'Reg: Coco&Jambo Inv: B0004 Cus: A0004 Br: F0004'), -- & = reserved XML char
(5, 'TEST4', 'Reg: 0005 Inv: B0005 Br: F0005'), -- Cus is missing
(5, 'TEST4', 'Cus: 3333 Br: 4444 Reg: 1111 Inv: 22222'); -- Different order

;WITH BaseQuery AS 
(
    SELECT  t1.ID, t1.Name, 
                CONVERT(XML, '<root><item>' 
                + REPLACE(
                    REPLACE(
                        REPLACE(
                            REPLACE((SELECT t1.Comment AS '*' FOR XML PATH('')), 
                            'Reg:', 
                            '</item><item type="Reg">'), 
                        'Inv:', 
                        '</item><item type="Inv">'), 
                    'Cus:', 
                    '</item><item type="Cus">'), 
                'Br:', 
                '</item><item type="Br">') + '</item></root>') CommentAsXml
    FROM    @Table1 t1
)
SELECT  bq.ID, bq.Name, 
        Reg = LTRIM(RTRIM(bq.CommentAsXml.value('(root/item[@type="Reg"])[1]', 'VARCHAR(11)'))),
        Inv = LTRIM(RTRIM(bq.CommentAsXml.value('(root/item[@type="Inv"])[1]', 'VARCHAR(11)'))),
        Cus = LTRIM(RTRIM(bq.CommentAsXml.value('(root/item[@type="Cus"])[1]', 'VARCHAR(11)'))),
        Br  = LTRIM(RTRIM(bq.CommentAsXml.value('(root/item[@type="Br"])[1]', 'VARCHAR(11)')))
FROM    BaseQuery bq

结果:

enter image description here

Demo here

答案 1 :(得分:1)

试试这个。基本上我正在做的是用逗号替换Reg:Inv:etc,删除空格并使用XML来派生列值。

enter image description here

所以我正在考虑下面的@Bogdan Sahlean解决方案来处理评论字段中的XMl特殊字符。试试这个;

      ;WITH Split_Names (COMMENT)
        AS
        -- Define the CTE query.
        (
            SELECT 
            CONVERT(XML,'<COMMENTS><COMMENT>'  
    + 
    REPLACE(
    REPLACe(
    REPLACE(
    REPLACE(
    REPLACE(
    REPLACE(
    (SELECT Comment AS '*' FOR XML PATH('')) 
    ,'Reg:',''),'Inv:',','),'Cus:',','),'Br:',','),' ' ,'')
    ,',', '</COMMENT><COMMENT>') + '</COMMENT></COMMENTS>') AS xmlname
             FROM 


 GenTransaction
        )
        -- Define the outer query referencing the CTE name.
         SELECT      
         COMMENT.value('/COMMENTS[1]/COMMENT[1]','varchar(100)') AS Reg,    
         COMMENT.value('/COMMENTS[1]/COMMENT[2]','varchar(100)') AS Inv,
         COMMENT.value('/COMMENTS[1]/COMMENT[3]','varchar(100)') AS Cus,
         COMMENT.value('/COMMENTS[1]/COMMENT[4]','varchar(100)') AS Br

         FROM Split_Names