我有一张看起来像这样的表:
id | serial_number_basic | product_id
-------------------------------------
serial_number_basic是一个运行号码,每次需要一个新号码时都会计数。在过去,可以将此数字的整个范围留空,下一个数字为MAX() + 1
。
由于要求的变化,现在应填补空洞。 serial_number_basic当然取决于product_id。每个产品都有自己的serial_number_basics序列。问题是找到漏洞。
此查询确实根据每个[productid]查找漏洞,但不幸的是它太慢了:
SELECT (
MIN( serial_number_basic ) + 1
) as next_available_box
FROM (
SELECT DISTINCT t0.serial_number_basic, t1.serial_number_basic AS number_plus_one
FROM (SELECT * FROM conv WHERE product_id = [productid]) AS t0
LEFT JOIN
(SELECT * FROM conv WHERE product_id = [productid]) AS t1
ON t0.serial_number_basic + 1 = t1.serial_number_basic
) AS sub
WHERE number_plus_one IS NULL;
答案 0 :(得分:2)
没有任何聚合,没有order-by,只是一个简单的外连接,请尝试:
SELECT MIN(c1.serial_number_basic) + 1
FROM conv c1
LEFT JOIN conv c2
ON c2.serial_number_basic = c1.serial_number_basic+1
AND c2.product_id = c1.product_id
WHERE c1.product_id = 2
AND c2.id IS null
答案 1 :(得分:1)
您可以使用GROUP BY
删除所有子查询。然后SELECT子句中的MIN
将仅涵盖每行的一个product_id:
SELECT
MIN(c.serial_number_basic) + 1 AS next_available_box,
c.product_id
FROM conv c
LEFT JOIN conv AS c1
ON (c1.product_id = c.product_id AND c1.serial_number_basic - 1 = c.serial_number_basic)
WHERE c1.serial_number_basic IS NULL
GROUP BY c.product_id
ORDER BY c.product_id ASC;
返回:
+--------------------+------------+
| next_available_box | product_id |
+--------------------+------------+
| 4 | 1 |
| 2 | 2 |
+--------------------+------------+
来自以下数据集:
+---------------------+------------+
| serial_number_basic | product_id |
+---------------------+------------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 5 | 1 |
| 6 | 1 |
| 1 | 2 |
| 3 | 2 |
| 8 | 2 |
| 9 | 2 |
+---------------------+------------+
只需注意一点 - 您只能获得第一个缺口,如果您的serial_number_basic没有以每个产品的最低编号开始,则必须验证另一种方式。
答案 2 :(得分:0)
表:
create table conv (id int, serial_number_basic int, product_id int);
insert into conv (id, serial_number_basic, product_id) values
(1,1,1),
(2,2,1),
(3,3,1),
(4,5,1),
(5,6,1),
(6,1,2),
(7,3,2),
(8,8,2),
(9,9,2),
(10,2,3)
;
查询:
set @snb := 1;
set @pid := -1;
select sw.product_id, min(sw.serial_number_basic) as lowest_gap
from (
select
case
when @pid != ss.product_id
then @snb := 1
else @snb := @snb + 1
end as serial_number_basic,
@pid := ss.product_id as product_id
from (
select serial_number_basic, product_id
from conv
order by product_id, serial_number_basic
) ss
) sw
left outer join conv
on sw.product_id = conv.product_id
and
sw.serial_number_basic = conv.serial_number_basic
where conv.product_id is null
group by sw.product_id
order by sw.product_id
;
结果:
+------------+------------+
| product_id | lowest_gap |
+------------+------------+
| 1 | 4 |
| 2 | 2 |
| 3 | 1 |
+------------+------------+
3 rows in set (0.00 sec)
编辑:
可能要快得多:
set @snb := 1;
set @pid := -1;
select product_id, min(gap) as lowest_gap
from (
select
case
when @pid != product_id
then @snb := 1
else @snb := @snb + 1
end,
case
when @snb != serial_number_basic
then @snb else null
end as gap,
@pid := ss.product_id as product_id
from (
select serial_number_basic, product_id
from conv
order by product_id, serial_number_basic
) ss
) sw
where gap is not null
group by product_id
order by product_id
;
答案 3 :(得分:0)
首先,创建一个包含1
到10^5
范围内所有整数的表格:
CREATE TABLE digit
( d INT );
INSERT INTO digit --- without zero
VALUES
(1),(2),(3),(4),(5),
(6),(7),(8),(9) ;
CREATE TABLE number
( n INT PRIMARY KEY );
INSERT INTO number
VALUES
(1) ;
INSERT INTO number --- run this 5 times
SELECT n + (SELECT MAX(n) FROM number)*d
FROM number
CROSS JOIN digit ;
现在,对于某个产品,我们可以运行:
SELECT
@product_id
, MIN(number.n) AS next_available_serial
FROM
number
LEFT JOIN conv AS c
ON c.serial_number_basic = number.n
AND c.product_id = @product_id
WHERE c.serial_number_basic IS NULL
对于所有产品都可以(但我不知道CROSS JOIN
是快还是慢...... ):
SELECT
p.product_id
, MIN(number.n) AS next_available_serial
FROM
( SELECT DISTINCT
product_id
FROM conv
) AS p
CROSS JOIN number
LEFT JOIN conv AS c
ON c.serial_number_basic = number.n
AND c.product_id = p.product_id
WHERE c.serial_number_basic IS NULL
GROUP BY p.product_id