2012-03-06 51 views
1

我想提取用逗号分隔的特定字符串和SQL服务器通过特定的列解析2008年在SQL Server的表结构如下:转换逗号分隔的字符串的多个列在SQL Server

CREATE TABLE SAMP(COMMASEPA VARCHAR(255),X VARCHAR(10),Y VARCHAR(10),Z VARCHAR(10),A VARCHAR(10),B VARCHAR(10),C VARCHAR(10),D VARCHAR(10)) 
INSERT INTO SAMP VALUES('X=1,Y=2,Z=3',null,null,null,null,null,null,null), 
('X=3,Y=4,Z=5,A=6',null,null,null,null,null,null,null), 
('X=1,Y=2,Z=3,A=5,B=6,C=7,D=8',null,null,null,null,null,null,null) 

我想根据逗号和[x/y/z/a/b/c/d]中的一个字符串来分隔字符串。例如,在第一行X = 1的结果表中应该在X col中,Y = 2应该在Y col中,Z = 3应该在Z col中。请在此输入任何想法。谢谢...

+0

我一次有同样的问题。你可以到这里http://www.sommarskog.se/arrays-in-sql-2008.html或http://www.apexa.net/Blog/web_design_Blog_20080619.aspx。这两个页面都向您展示了将表格/数组解析/解析到表格中的方法 – Patriotec 2012-03-06 18:24:53

回答

1

你可以看到这方面的工作在SQL小提琴:http://sqlfiddle.com/#!3/8c3ee/32

下面是它的肉:

with parsed as (
    select 
    commasepa, 
    root.value('(/root/s/col[@name="X"])[1]', 'varchar(20)') as X, 
    root.value('(/root/s/col[@name="Y"])[1]', 'varchar(20)') as Y, 
    root.value('(/root/s/col[@name="Z"])[1]', 'varchar(20)') as Z, 
    root.value('(/root/s/col[@name="A"])[1]', 'varchar(20)') as A, 
    root.value('(/root/s/col[@name="B"])[1]', 'varchar(20)') as B, 
    root.value('(/root/s/col[@name="C"])[1]', 'varchar(20)') as C, 
    root.value('(/root/s/col[@name="D"])[1]', 'varchar(20)') as D 
FROM 
(
select 
    commasepa, 
    CONVERT(xml,'<root><s><col name="' + REPLACE(REPLACE(COMMASEPA, '=', '">'),',','</col></s><s><col name="') + '</col></s></root>') as root 
FROM 
    samp 
) xml 
) 
update 
    samp 
    set 
    samp.x = parsed.x, 
    samp.y = parsed.y, 
    samp.z = parsed.z, 
    samp.a = parsed.a, 
    samp.b = parsed.b, 
    samp.c = parsed.c, 
    samp.d = parsed.d 
from 
    parsed 
where 
    parsed.commasepa = samp.commasepa; 

充分披露 - 我sqlfiddle.com笔者

这是通过首先将每个commasepa字符串转换为如下所示的XML对象:

<root> 
<s> 
    <col name="X">1</col> 
</s> 
<s> 
    <col name="Y">2</col> 
</s> 
    .... 
</root> 

一旦我获得了格式化的字符串,我就可以使用SQL Server 2005(及更高版本)支持的xquery选项,即.value('(/root/s/col[@name="X"])[1]', 'varchar(20)')部分。我单独选择每个潜在列,以便在可用时对其进行标准化和填充。用这种规范化的格式,我用一个我称之为“解析”的公用表达式(CTE)定义了结果集。这个CTE然后在更新语句中重新加入,以便可以将值填充到原始表中。

+0

非常感谢您输入,它的工作..如果可能,请您解释代码中的root.value以及您遵循的步骤。谢谢你,我很感激! – alex 2012-03-06 19:19:53

+0

@alex肯定 - 我已经用解释更新了答案。 – 2012-03-06 19:31:29

+0

非常感谢:) – alex 2012-03-07 22:37:47

0

有分流功能的帮助:

CREATE FUNCTION [dbo].[SplitStrings] 
(
    @List  VARCHAR(MAX), 
    @Delimiter CHAR(1) 
) 
RETURNS TABLE 
AS 
    RETURN (SELECT Item FROM (SELECT Item = x.i.value('(./text())[1]', 'varchar(max)') 
     FROM (SELECT [XML] = CONVERT(XML, '<i>' + REPLACE(@List, @Delimiter, '</i><i>') 
       + '</i>').query('.')) AS a CROSS APPLY [XML].nodes('i') AS x(i) 
     ) AS y WHERE Item IS NOT NULL 
    ); 
GO 

你可以这样来做:

;WITH x AS 
(
    SELECT s.*, f.Item 
     FROM #samp AS s 
     CROSS APPLY dbo.SplitStrings(s.COMMASEPA, ',') AS f 
), p AS 
( 
    SELECT x.COMMASEPA, 
     X = MAX(CASE WHEN x.Item LIKE 'X=%' THEN x.Item END), 
     Y = MAX(CASE WHEN x.Item LIKE 'Y=%' THEN x.Item END), 
     Z = MAX(CASE WHEN x.Item LIKE 'Z=%' THEN x.Item END), 
     A = MAX(CASE WHEN x.Item LIKE 'A=%' THEN x.Item END), 
     B = MAX(CASE WHEN x.Item LIKE 'B=%' THEN x.Item END), 
     C = MAX(CASE WHEN x.Item LIKE 'C=%' THEN x.Item END), 
     D = MAX(CASE WHEN x.Item LIKE 'D=%' THEN x.Item END) 
    FROM x GROUP BY x.COMMASEPA 
) 
UPDATE s SET X = p.X, Y = p.Y, Z = p.Z, 
    A = p.A, B = p.B, C = p.C, D = p.D 
FROM #samp AS s INNER JOIN p 
ON p.COMMASEPA = s.COMMASEPA; 
0
DECLARE @SAMP TABLE 
(
    COMMASEPA VARCHAR(255), 
    X VARCHAR(10), 
    Y VARCHAR(10), 
    Z VARCHAR(10), 
    A VARCHAR(10), 
    B VARCHAR(10), 
    C VARCHAR(10), 
    D VARCHAR(10) 
) 
INSERT INTO @SAMP VALUES 
('X=1,Y=2,Z=3',null,null,null,null,null,null,null), 
('X=3,Y=4,Z=5,A=6',null,null,null,null,null,null,null), 
('X=1,Y=2,Z=3,A=5,B=6,C=7,D=8',null,null,null,null,null,null,null) 

update S set 
    X = case when P.X > 3 then substring(T.COMMASEPA, P.X, charindex(',', T.COMMASEPA, P.X) - P.X) end, 
    Y = case when P.Y > 3 then substring(T.COMMASEPA, P.Y, charindex(',', T.COMMASEPA, P.Y) - P.Y) end, 
    Z = case when P.C > 3 then substring(T.COMMASEPA, P.Z, charindex(',', T.COMMASEPA, P.Z) - P.Z) end, 
    A = case when P.A > 3 then substring(T.COMMASEPA, P.A, charindex(',', T.COMMASEPA, P.A) - P.A) end, 
    B = case when P.B > 3 then substring(T.COMMASEPA, P.B, charindex(',', T.COMMASEPA, P.B) - P.B) end, 
    C = case when P.C > 3 then substring(T.COMMASEPA, P.C, charindex(',', T.COMMASEPA, P.C) - P.C) end, 
    D = case when P.D > 3 then substring(T.COMMASEPA, P.D, charindex(',', T.COMMASEPA, P.D) - P.D) end 
from @SAMP as S 
    cross apply (select ','+S.COMMASEPA+',') as T(COMMASEPA) 
    cross apply (select charindex(',X=', T.COMMASEPA)+3 as X, 
         charindex(',Y=', T.COMMASEPA)+3 as Y, 
         charindex(',Z=', T.COMMASEPA)+3 as Z, 
         charindex(',A=', T.COMMASEPA)+3 as A, 
         charindex(',B=', T.COMMASEPA)+3 as B, 
         charindex(',C=', T.COMMASEPA)+3 as C, 
         charindex(',D=', T.COMMASEPA)+3 as D) as P 
+0

谢谢..它解决了我引用作为一个例子的表格的问题,因为所有的数字都大于3,但我认为杰克斯的答案更普遍...感谢您的帮助 – alex 2012-03-07 22:42:50

0

纠正我想这里的行...

相反试图用“逗号”分隔一个字段时,在第二个表中放置你的名字/值对可能会更谨慎。

Modify SAMP to have the following field: 
ID - integer - Primary Key Auto increment 

Create a table NVP 
ID - integer - Primary Key Auto increment 
SAMPID - integer Foreign key SAMP.ID 
Name - varchar(255) - or any realistic size 
Value - varchar(255) - or any realistic size 

This will allow for the following: 
1. Unlimited fields 
2. Faster Data Access 
3. Since you are not trying to shove several values into 1 field, you now don't have to worry about running out of space. 
4. Less code to worry about trying to split/join data 
5. No longer restricted where you can't store a "," as one of your names or values. 

SQL表应该始终是关系型的,以利用SQL所提供的功能。

相关问题