我想提取用逗号分隔的特定字符串并解析SQL Server 2008中的特定列.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 :(得分:1)
你可以在SQL Fiddle上看到这个: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连接回来,以便可以在原始表中填充值。
答案 1 :(得分:0)
借助Split功能:
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;
答案 2 :(得分: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
答案 3 :(得分: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提供的强大功能。