3

考虑一个带有列序列号的表 productSerialnumber。此列采用产品的单个序列号。

产品 A 的序列号从 101 到 109,然后是 111 到 119 和 139 到 150。例如,序列号 110 和 120-138 不可用

我想要一个查询或可以返回连续序列号集的东西。例如结果将是

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

要考虑的是该表具有超过一百万行的大量数据。

任何帮助都会非常感激

4

2 回答 2

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 Fiddle 在这里:-

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

于 2013-10-07T11:02:54.813 回答
0

我认为这非常快,因为我们避免了连接并且只遍历数据一次。唯一的瓶颈是我们使用了 2 个临时表,并且需要使用用户定义的值。

没有设置语句

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:=@previous,@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 语句

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:=@previous,@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

于 2013-10-08T08:13:08.390 回答