Во-первых, для этого решения требуется 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
)