2012-03-06 50 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所提供的功能。

相關問題