您可能希望在Row_Number
上进行分区OrderNo
,但这应该可以帮助您入门:
declare @LineItems as Table ( LineItem Int Identity, Id VarChar(16) );
insert into @LineItems ( Id ) values
( '01' ), ( 'CA800' ), ( 'BERRY' ),
( '02' ), ( 'MSIJ54' ), ( '92-D-06' ), ( 'BERRY' );
with LineItems as (
select LineItem, Id, Row_Number() over ( order by LineItem ) as RN
from @LineItems
),
PrefixedLineItems as (
select LineItem, Id, Id as Prefix, Cast( NULL as VarChar(16) ) as Result, RN
from LineItems
where RN = 1
union all
select LI.LineItem, LI.Id,
case when IsNumeric( LI.Id ) = 1 then LI.Id else PLI.Prefix end,
case when IsNumeric( LI.Id ) = 1 then NULL else Cast( PLI.Prefix + '-' + LI.Id as VarChar(16) ) end, LI.RN
from PrefixedLineItems as PLI inner join
LineItems as LI on LI.RN = PLI.RN + 1
)
select LineItem, Id, Result
from PrefixedLineItems
order by LineItem
option ( MaxRecursion 0 )
如果重要 ID
值必须从 开始01
并计数到 ,则可以添加额外的测试20
。
编辑:嗯,这很糟糕。
生成附加样本数据的版本是:
-- Sample data.
if Object_Id( 'tempdb..#LineItems', N'U' ) is not NULL
drop table #LineItems;
create table #LineItems ( LineItem Int Identity Primary Key, Id VarChar(32) not null );
insert into #LineItems ( Id ) values
( '01' ), ( 'CA800' ), ( 'BERRY' ),
( '02' ), ( 'MSIJ54' ), ( '92-D-06' ), ( 'BERRY' );
-- Generate some additional sample data.
declare @Count as Int = 1000;
while @Count > 0
begin
if Rand() < 0.1 -- Make about 10% of the entries numeric.
insert into #LineItems ( Id ) values ( Right( '0' + Cast( Floor( Rand() * 20 ) + 1 as VarChar(2) ), 2 ) );
else
insert into #LineItems ( Id ) values ( 'Foo ' + Cast( Rand() as VarChar(16) ) );
set @Count = @Count - 1;
end;
-- Time the query.
declare @Start as DateTime = SysDateTime();
with NumberedLineItems as (
select LineItem, Id, Row_Number() over ( order by LineItem ) as RN
from #LineItems
),
PrefixedLineItems as (
select LineItem, Id, Id as Prefix, Cast( NULL as VarChar(16) ) as Result, RN
from NumberedLineItems
where RN = 1
union all
select LI.LineItem, LI.Id,
case when IsNumeric( LI.Id ) = 1 then LI.Id else PLI.Prefix end,
case when IsNumeric( LI.Id ) = 1 then NULL else Cast( PLI.Prefix + '-' + LI.Id as VarChar(16) ) end, LI.RN
from PrefixedLineItems as PLI inner join
NumberedLineItems as LI on LI.RN = PLI.RN + 1
)
select LineItem, Id, Result
from PrefixedLineItems
order by LineItem
option ( MaxRecursion 0 );
select DateDiff( ms, @Start, SysDateTime() ) as [Elapsed Milliseconds],
( select Count(*) from #LineItems ) as [Rows];
这种 RBAR 方法可以更有效地扩展:
-- Sample data.
if Object_Id( 'tempdb..#LineItems', N'U' ) is not NULL
drop table #LineItems;
create table #LineItems ( LineItem Int Identity Primary Key, Id VarChar(32) not null );
insert into #LineItems ( Id ) values
( '01' ), ( 'CA800' ), ( 'BERRY' ),
( '02' ), ( 'MSIJ54' ), ( '92-D-06' ), ( 'BERRY' );
-- Generate some additional sample data.
declare @Count as Int = 10000;
while @Count > 0
begin
if Rand() < 0.1 -- Make about 10% of the entries numeric.
insert into #LineItems ( Id ) values
( Right( '0' + Cast( Floor( Rand() * 20 ) + 1 as VarChar(2) ), 2 ) )
else
insert into #LineItems ( Id ) values ( 'Foo ' + Cast( Rand() as VarChar(16) ) )
set @Count = @Count - 1;
end;
-- Create a fiendish thingy.
declare Plod cursor fast_forward for
select LineItem, Id
from #LineItems
order by LineItem;
declare @LineItem as Int;
declare @Id as VarChar(32);
declare @Prefix as VarChar(2)
-- Create a table to hold the results.
if Object_Id( 'tempdb..#PrefixedLineItems', N'U' ) is not NULL
drop table #PrefixedLineItems;
create table #PrefixedLineItems
( LineItem Int Primary Key, Id VarChar(32) not null, Prefix VarChar(2) null );
-- RBAR.
declare @Start as DateTime = SysDateTime();
open Plod;
fetch next from Plod into @LineItem, @Id;
while @@Fetch_Status = 0
begin
set @Prefix = case when IsNumeric( @Id ) = 1 then @Id else @Prefix end;
insert into #PrefixedLineItems ( LineItem, Id, Prefix ) values
( @LineItem, @Id, case when IsNumeric( @Id ) = 1 then NULL else @Prefix end );
fetch next from Plod into @LineItem, @Id;
end;
close Plod;
deallocate Plod;
-- That's all, folks!
select LineItem, Id, Prefix
from #PrefixedLineItems
order by LineItem;
select DateDiff( ms, @Start, SysDateTime() ) as [Elapsed Milliseconds],
( select Count(*) from #LineItems ) as [Rows]