2010-07-22 17 views
0

我有這樣的一個表:轉化表分成不同的表

RowID | ProductDescription1 
----------------------------------------------------- 
1  | 0296620300-0296620399; 
2  | 0296620400-0296620499;0296620500-0296620599; 
3  | 0296620600-0296620699;0296620700-0296620799; 

我想成爲這樣的:

NewRowID | Start  | End  | SourceRowID 
-------------------------------------------------- 
1  | 0296620300 | 0296620399 | 1 
2  | 0296620400 | 0296620499 | 2 
3  | 0296620500 | 0296620599 | 2 
4  | 0296620600 | 0296620699 | 3 
5  | 0296620700 | 0296620799 | 3 

現在我能做到這回表分裂的東西的功能:

ALTER FUNCTION [dbo].[ufn_stg_SplitString] 
(
    -- Add the parameters for the function here 
    @myString varchar(500), 
    @deliminator varchar(10) 
) 
RETURNS 
@ReturnTable TABLE 
(
    -- Add the column definitions for the TABLE variable here 
    [id] [int] IDENTITY(1,1) NOT NULL, 
    [part] [varchar](50) NULL 
) 
AS 
BEGIN 
     Declare @iSpaces int 
     Declare @part varchar(50) 

     --initialize spaces 
     Select @iSpaces = charindex(@deliminator,@myString,0) 
     While @iSpaces > 0 

     Begin 
      Select @part = substring(@myString,0,charindex(@deliminator,@myString,0)) 

      Insert Into @ReturnTable(part) 
      Select @part 

    Select @myString = substring(@mystring,charindex(@deliminator,@myString,0)+ len(@deliminator),len(@myString) - charindex(' ',@myString,0)) 


      Select @iSpaces = charindex(@deliminator,@myString,0) 
     end 

     If len(@myString) > 0 
      Insert Into @ReturnTable 
      Select @myString 

    RETURN 
END 

我想要避免使用遊標,如果可能的。

我很感謝您的評論/輸入。

+1

我假設這是一個單一的遷移工作,所以它的工作方式的任何限制(例如「無遊標」)應該是任意的。 – 2010-07-22 00:51:53

+0

什麼版本的SQL Server? – 2010-07-22 00:52:17

+1

所以你需要規範化數據,有分裂功能來做到這一點...你需要我們什麼? – 2010-07-22 00:52:31

回答

2

首先,這種解決方案需要SQL Server 2005+。其次,在底部,我提供了一個不使用遊標的替代Split功能。第三,這裏是不依賴於被指定長度的值,而是該分隔符是一致的解決方案:

Select Row_Number() Over (Order By Z.PairNum) As ItemNum 
    , Min(Case When Z.PositionNum = 1 Then Z.Value End) As [Start] 
    , Min(Case When Z.PositionNum = 2 Then Z.Value End) As [End] 
    , Z.RowId As SourceRowId 
From (
     Select T2.RowId, S.Value, T2.PairNum 
      , Row_Number() Over (Partition By T2.RowId, T2.PairNum Order By S.Value) As PositionNum 
     From (
       Select T.RowId, S.Value 
        , Row_Number() Over (Order By S.Value) As PairNum 
       From MyTable As T 
        Cross Apply dbo.Split(T.ProductDescription, ';') As S 
       ) As T2 
      Cross Apply dbo.Split(T2.Value, '-') As S 
     ) As Z 
Group By Z.RowId, Z.PairNum 

和分割功能:

Create FUNCTION [dbo].[Split] 
( 
    @DelimitedList nvarchar(max) 
    , @Delimiter nvarchar(2) = ',' 
) 
RETURNS TABLE 
AS 
RETURN 
    (
    With CorrectedList As 
     (
     Select Case When Left(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End 
      + @DelimitedList 
      + Case When Right(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End 
      As List 
      , Len(@Delimiter) As DelimiterLen 
     ) 
     , Numbers As 
     (
     Select TOP (Len(@DelimitedList)) Row_Number() Over (Order By c1.object_id) As Value 
     From sys.objects As c1 
      Cross Join sys.columns As c2 
     ) 
    Select CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen As Position 
     , Substring (
        CL.List 
        , CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen  
        , CharIndex(@Delimiter, CL.list, N.Value + 1)       
         - (CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen) 
        ) As Value 
    From CorrectedList As CL 
     Cross Join Numbers As N 
    Where N.Value < Len(CL.List) 
     And Substring(CL.List, N.Value, CL.DelimiterLen) = @Delimiter 
    ) 
+0

就像那種非光標功能的方法 – dcpartners 2010-07-22 05:00:46

+0

只是認爲...這個功能似乎不能用''(空白)作爲分隔符。有任何想法嗎? – dcpartners 2010-07-23 02:01:37

+0

@ dewacorp.alliances - 不需要使用上述分割功能分割每個字符。您可以使用Substring和Numbers CTE或表直接執行此操作。 – Thomas 2010-07-23 02:45:13

2

SQL 2005/2008

with prods as 
(
select 1 as RowID, '0296620300-0296620399;' AS ProductDescription1 union all 
select 2 as RowID, '0296620400-0296620499;0296620500-0296620599;' AS ProductDescription1 union all 
select 3 as RowID, '0296620600-0296620699;0296620700-0296620799;' AS ProductDescription1 
) 

select 
ROW_NUMBER() OVER(ORDER BY RowId) as NewRowID, 
LEFT(Part,10) AS Start, /*Might need charindex if they are not always 10 characters*/ 
RIGHT(Part,10) AS [End], 
RowId as SourceRowID from prods 
cross apply [dbo].[ufn_stg_SplitString] (ProductDescription1,';') p 

給人

NewRowID    Start  End  SourceRowID 
-------------------- ---------- ---------- ----------- 
1     0296620300 0296620399 1 
2     0296620400 0296620499 2 
3     0296620500 0296620599 2 
4     0296620600 0296620699 3 
5     0296620700 0296620799 3