SQL Server Transforming Table into different Table

new9mtju  于 2023-03-17  发布在  其他
关注(0)|答案(2)|浏览(182)

I have a table like this:
| RowID | ProductDescription1 |
| ------------ | ------------ |
| 1 | 0296620300-0296620399; |
| 2 | 0296620400-0296620499;0296620500-0296620599; |
| 3 | 0296620600-0296620699;0296620700-0296620799; |

I want to become like this:

NewRowIDStartEndSourceRowID
1029662030002966203991
2029662040002966204992
3029662050002966205992
4029662060002966206993
5029662070002966207993

Now I have a function that can do splitting stuff which returning table :

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

I want to avoid using cursor if it's possible.

I am appreciated your comment/input.

rryofs0p

rryofs0p1#

First, this solution requires SQL Server 2005+. Second, at the bottom, I offer an alternate Split function which does not use a cursor. Third, here is a solution that does not rely on the values being of a specified length but instead that the delimiter is consistent:

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

And the Split function:

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
    )
p4rjhz4m

p4rjhz4m2#

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

Gives

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

相关问题