2015-06-19 32 views
2

比方說,我有一個表,如分割字符串和列數

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需要保持有序。

我已經用下面的函數嘗試這樣的:

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列而添加的內容?

謝謝!

回答

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

+0

它的工作原理主要是!有一個問題,一些'Numbering = 1'的列有一個空的'ClassID'。有些列以逗號結尾,即「10,13,12」是什麼影響它?此外,如果'ClassID'具有多於3個條目,這仍然可以工作嗎? – jjjjjjjjjjj

+0

我解決了這個問題,方法是編寫一個在你之前執行的CTE,並刪除尾部的逗號(如果有的話),以及後面的CTE刪除空白行。感覺有點麻煩,但它現在按預期工作。 – jjjjjjjjjjj

+0

如果字符串以逗號結尾,並且將所有內容都轉換爲INT,則最終會得到0而不是null。我添加了一個例子,並確保它處理只有1個條目的行。 – Andrew

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