【问题标题】:Converting comma delimited string to multiple columns in sql server将逗号分隔的字符串转换为sql server中的多列
【发布时间】:2012-03-06 18:00:00
【问题描述】:

我想提取用逗号分隔的特定字符串,并在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 中。请输入任何想法。谢谢……

【问题讨论】:

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


【解决方案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 的作者

首先将每个逗号分隔字符串转换为如下所示的 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,以便可以将值填充到原始表中。

【讨论】:

  • 非常感谢您的输入,它的工作原理..如果可能的话,您能否解释一下代码中的 root.value 以及您遵循的步骤..谢谢..我很感激!
【解决方案2】:

借助拆分功能:

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;

【讨论】:

    【解决方案3】:
    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,但我认为 Jakes 的答案更普遍...感谢您的帮助
    【解决方案4】:

    在这里纠正我的思路...

    与其尝试“逗号”分隔一个字段,不如使用第二个表来放置名称/值对。

    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 提供的强大功能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-03
      • 1970-01-01
      • 1970-01-01
      • 2012-09-04
      • 2013-02-04
      • 1970-01-01
      • 1970-01-01
      • 2012-01-17
      相关资源
      最近更新 更多