将表转换为不同的表

时间:2010-07-22 00:48:40

标签: sql sql-server tsql

我有一张这样的表:

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

如果可能,我想避免使用光标。

感谢您的评论/意见。

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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
    )