拆分字符串和数字列

时间:2015-06-19 16:45:41

标签: sql sql-server sql-server-2012

假设我有一个表格,如

ItemID        ClassID
------------------------
1             10, 13, 12
2             5, 7

并希望将数据复制到另一个表中,如此

ItemID     Numbering       ClassID
----------------------------------
1          1               10
1          2               13
1          3               12
2          1               5
2          2               7
  1. 将逗号分隔的ClassID字段分隔为单独的行,保留第一个表中的顺序
  2. 在插入时填充Numbering行。 Numbering列对每批ClassID都有连续的整数,这就是ClassID需要按顺序排列的原因。
  3. 我尝试使用以下功能:

      CREATE FUNCTION dbo.Split
       (
          @String NVARCHAR(MAX)
       )
      RETURNS @SplittedValues TABLE(
       Value INT
      )
     AS
     BEGIN
      DECLARE @SplitLength INT
      DECLARE @Delimiter VARCHAR(10) 
      SET @Delimiter = ','
    
      WHILE len(@String) > 0
       BEGIN
        SELECT @SplitLength = (CASE charindex(@Delimiter, @String)
             WHEN 0 THEN
               datalength(@String) / 2
             ELSE
               charindex(@Delimiter, @String) - 1
           END)
    
       INSERT INTO @SplittedValues
       SELECT cast(substring(@String, 1, @SplitLength) AS INTEGER)
       WHERE
       ltrim(rtrim(isnull(substring(@String, 1, @SplitLength), ''))) <> '';
    
       SELECT @String = (CASE ((datalength(@String) / 2) - @SplitLength)
             WHEN 0 THEN
               ''
             ELSE
               right(@String, (datalength(@String) / 2) - @SplitLength - 1)
           END)
    
      END
    
     RETURN
    
    END
    

    但它只是部分有效。它会将行复制正确的次数(例如,ItemID=1为三次,上例中为ItemID=2两次),但它们是该行的精确副本(所有这些都是'10,13, 12')和逗号分隔的部分不分开。函数中也没有任何内容可以添加到Numbering列。

    所以,我有两个问题:如何修改上述函数以拆分ClassID字符串,以及我添加什么来正确增加Numbering列?

    谢谢!

2 个答案:

答案 0 :(得分:4)

我使用递归CTE来完成它。

WITH SplitCTE AS
(
    SELECT
        itemid,
        LEFT(ClassID,CHARINDEX(',',ClassID)-1) AS ClassID
        ,RIGHT(ClassID,LEN(ClassID)-CHARINDEX(',',ClassID)) AS remaining
        FROM table1
        WHERE ClassID IS NOT NULL AND CHARINDEX(',',ClassID)>0
    UNION ALL
    SELECT
        itemid,
        LEFT(remaining,CHARINDEX(',',remaining)-1)
        ,RIGHT(remaining,LEN(remaining)-CHARINDEX(',',remaining))
        FROM SplitCTE
        WHERE remaining IS NOT NULL AND CHARINDEX(',',remaining)>0
    UNION ALL
    SELECT
        itemid,remaining,null
        FROM SplitCTE
        WHERE remaining IS NOT NULL AND CHARINDEX(',',remaining)=0

)
SELECT 
 itemid,
 row_number() over (partition by itemid order by cast(classid as int) asc) as Numbering,
 cast (ClassID  as int) as ClassID
FROM 
 SplitCTE 

 UNION ALL
 select 
 ItemId,
 1,
 cast(classid as int)
 FROM table1
 WHERE ClassID IS NOT NULL AND CHARINDEX(',',ClassID) = 0

SQL Fiddle

答案 1 :(得分:0)

DECLARE @t TABLE( ID INT IDENTITY, data VARCHAR(50))
INSERT INTO @t(data) SELECT '10, 13, 12'
INSERT INTO @t(data) SELECT '5, 7'

select F1.id,O.splitdata, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY (SELECT 1))
from ( select *,cast(''+replace(F.data,',','')+'' as XML) as xmlfilter from @t F
)F1
cross apply ( select fdata.D.value('.','varchar(50)') as splitdata from f1.xmlfilter.nodes('X') as fdata(D) ) O