2013-05-20 202 views
0

我需要一個選擇查詢來根據訂單事務表中前一行的數字創建一個新項目。在T-SQL SQL Server 2008中基於另一行分配行號

有一個連續LineItem,所以ID與01,02,03等之間的差異會有所不同。我正在考慮查詢中的臨時表:OrderNo,ID其中ID爲01到20以及測試LineItem的情況說明以及它是否在...

ID 01 2834111和ID CA800 = 2834112更多01小於02,所以-01就是它的前綴。

我在正確的軌道上嗎?這似乎是一個長期的案例陳述。

OrderNo LineItem ID  Need to Make 
----------------------------------------------------------------------  
236201 2834111 01   
236201 2834112 CA800      01-CA800 
236201 2834113 BERRY 01-BERRY 
236201 2834114 02   
236201 2834115 MSIJ54 02-IJ54 
236201 2834116 92-D-06 02-92-D-06 
236201 2834117 BERRY 02-BERRY 
236201 2834118 03   
236201 2834119 SACOLBS24 03-SACOLBS24 
236201 2834121         OWK32 03-OWK32 
236201 2834122         04    
236201 2834123         SBMRY 04-SBMRY 
236201 2834124         DAWN 04-DAWN 
236201 2834125         05    
236201 2834126         NWM216D  05-NWM216D 
236201 2834127         DAWN  05-DAWN 
+1

讓我試着重新措辭。你想在'LineItem'順序中移動表格。當你遇到一個恰好是兩位數的「ID」值時,你希望將該值作爲前綴(帶短劃線)傳播給後續的ID,直到遇到下一個數字「ID」。這是總結嗎? – HABO

+0

除了匹配'01'到'20'之外,是否還有其他區別像'01'的行? – criticalfix

+0

是 - 有一個全局唯一的int列與每個ID相關聯,所以ID'01%'= 36221會更清晰,但沒有任何東西可以連接到另一個表中的值。 – user1529496

回答

0

開始拉動的關鍵行到一個臨時表:

SELECT OrderNo, LineItem, ID 
INTO #TempOrder 
FROM YourOrderTable 
WHERE SUBSTRING(LINEITEM, 1, 1) IN ('1','2') 
AND SUBSTRING(LINEITEM, 2, 1) IN ('1','2','3','4','5','6','7','8','9','0') 
AND LEN(LINEITEM) = 2 

然後,如果你正在尋找一個特定@LineItem:

SELECT @MaxLineItem = MAX(LineItem) 
FROM #TempOrder 
WHERE LineItem <= @LineItem 

你可以再看看:

SELECT @MaxLineItemID = ID 
FROM #TempOrder 
WHERE LineItem = @MaxLineItem 

@MaxLineItem是否有t o與@LineItem不同?如果是這樣的:

SELECT CASE WHEN @LineItem = @MaxLineItem THEN ID 
    ELSE @MaxLineItemID + ' - ' + ID END AS NewID 
FROM YourOrderTable 
WHERE LineItem = @LineItem 
0

你可能想在OrderNo分區Row_Number,但這應該讓你開始:

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] 
+0

如果我限制記錄,上面的方法很好,遞歸錯誤:「語句終止。語句完成前,最大遞歸100已耗盡。「源表超過了100K lzy – user1529496

+0

@ user1529496 - 簡單修復,我在查詢的末尾添加了'option(MaxRecursion 0) '來禁用遞歸限制 – HABO

+0

它已經運行了10分鐘,但沒有結果尚未 – user1529496

1

IF HABO有你的要求吧,你可以試試這個:

SELECT 
    p.*, id.id + '- ' + p.id AS prefixedid 
FROM 
    (SELECT 
     tbl.orderno, 
     tbl.lineitem, 
     tbl.id, 
     MAX(id.lineitem) AS max_id_lineitem 
    FROM 
     tbl INNER JOIN 
     (SELECT * FROM tbl WHERE id >='01' AND id <='20') id ON 
     tbl.orderno = id.orderno AND 
     tbl.lineitem > id.lineitem LEFT OUTER JOIN 
     (SELECT * FROM tbl WHERE id >='01' AND id <='20') id_fornull ON 
     tbl.orderno = id_fornull.orderno AND 
     tbl.lineitem = id_fornull.lineitem 
    WHERE 
     id_fornull.lineitem IS NULL 
    GROUP BY 
     tbl.orderno, 
     tbl.lineitem, 
     tbl.id) p INNER JOIN 
    (SELECT * FROM tbl WHERE id >='01' AND id <='20') id ON 
    p.orderno = id.orderno AND 
    p. max_id_lineitem = id.lineitem 
+0

這似乎正在工作感謝! – user1529496

+0

不用客氣,你也可以upvote和/或接受答案 – Beth

+0

+1把這個答案放在頂部,因爲OP顯然是打算點擊接受按鈕。 – criticalfix