2013-10-07 42 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

相关问题