2013-10-07 78 views
3

考慮具有列序號的表產品序列號。此欄採用產品的單個序列號。如何在沒有間隙的情況下查找序列號?

產品A具有從101到109,然後111至119和139至150的serialNumber 110和120-138,例如一個序列號不availabel

我想有一個查詢或東西可以返回連續的序列號集。 例如結果將

from  to 
======= ==== 
101  109 
111  119 
139  150 

要考慮的是,表中有一個巨大的集合更多然後一百萬行數據。

任何幫助將是非常appriciated

+0

你嘗試在你的數據集查詢。任何結果? –

回答

2

有更多的發揮: -

SELECT MIN(aFirstSerial), MAX(aLastSerial) 
FROM 
(
    SELECT @FirstSerial:=IF(productSerialnumber = @LastSerial + 1, IF(@FirstSerial = 0, productSerialnumber, @FirstSerial), productSerialnumber) AS aFirstSerial, 
     @RangeNum:=IF(productSerialnumber = @LastSerial + 1, @RangeNum, @RangeNum + 1) AS aRangeNum, 
     @LastSerial := productSerialnumber AS aLastSerial 
    FROM 
    (
     SELECT productSerialnumber 
     FROM Product 
     ORDER BY productSerialnumber 
    ) Sub1 
    CROSS JOIN (SELECT @PrevSerial:=0, @RangeNum:=0, @FirstSerial:=0, @LastSerial:=0) Sub2 
) Sub3 
GROUP BY aRangeNum 

SQL搗鼓在這裏: -

http://sqlfiddle.com/#!2/5cbc2/12

+0

修復發現meze的邊緣情況問題的小修改 – Kickstart

+0

+1我嘗試了這一點,它是迄今爲止最快的:-)。測試:http://sqlfiddle.com/#!2/a622a/14 –

+0

更新比較:http://sqlfiddle.com/#!2/1916b/12 –

0

這是非常快的,我因爲我們避免了連接,並且只能遍歷數據一次。唯一的瓶頸是我們使用2個臨時表,並且需要使用用戶定義的值。

沒有SET語句

select START_INTERVAL+0, END_INTERVAL+0 
from 
(
    select 
    if(@start = NULL or @start > PRODUCTSERIALNUMBER, @start='', '') as SET_START, 
    if (@start = '', @start:= @previous, @start) as START_INTERVAL, 
    if(PRODUCTSERIALNUMBER - @previous > 1, concat(@end:[email protected],@start:=''), @end:='') as END_INTERVAL, 
    @previous:= PRODUCTSERIALNUMBER as PRODUCTSERIALNUMBER 
    from 
    (
    select min(PRODUCTSERIALNUMBER)-2 as PRODUCTSERIALNUMBER from Product 
    UNION 
    (select PRODUCTSERIALNUMBER as PRODUCTSERIALNUMBER from Product ORDER BY productSerialnumber) 
    UNION 
    select max(PRODUCTSERIALNUMBER)+2 as PRODUCTSERIALNUMBER from Product  
) as TEMP 
) 
as RESULTS where 
not START_INTERVAL is null AND 
not END_INTERVAL is null AND 
not END_INTERVAL = '' AND 
not START_INTERVAL - END_INTERVAL > 0; 

設置聲明

set @start=''; 

select select START_INTERVAL+0, END_INTERVAL+0 
from 
(
    select 
    if (@start = '', @start:= @previous, @start) as START_INTERVAL, 
    if(PRODUCTSERIALNUMBER - @previous > 1, concat(@end:[email protected],@start:=''), @end:='') as END_INTERVAL, 
    @previous:= PRODUCTSERIALNUMBER as PRODUCTSERIALNUMBER 
    from 
    (
    select min(PRODUCTSERIALNUMBER)-2 as PRODUCTSERIALNUMBER from Product 
    UNION 
    (select PRODUCTSERIALNUMBER as PRODUCTSERIALNUMBER from Product ORDER BY productSerialnumber) 
    UNION 
    select max(PRODUCTSERIALNUMBER)+2 as PRODUCTSERIALNUMBER from Product  
) as TEMP 
) 
as RESULTS where 
not RESULTS.START_INTERVAL is null AND 
not RESULTS.END_INTERVAL is null AND 
not RESULTS.END_INTERVAL = '' AND 
not RESULTS.START_INTERVAL - RESULTS.END_INTERVAL > 0; 

SQLFiddle:http://sqlfiddle.com/#!2/a622a/60

相關問題