MySQL过程检查下一个空闲值

时间:2018-12-30 18:11:34

标签: mysql sql

我应该如何编写基于输入检查下一个空闲数字(字符串)的过程。 该过程应具有2个输入值,第一个是用户输入(数字),第二个是字符串中最大字符数。

这是我尝试编写的过程:

CREATE DEFINER=`root`@`localhost` PROCEDURE `getfreenum`(IN num CHAR(20), IN maxval CHAR(20))
begin

set @compare := (num + num *10);

set @maxId := (select sifra from artikli where sifra >=  @compare order by sifra asc limit 1);

while @compare = @maxId do
    set @compare := @compare + 1;
    set @maxId = (select sifra from artikli where sifra >=  @compare order by sifra asc limit 1);
end while;

select @compare;
end

此过程将在输入后找到下一个可用值,但该数字不包括我的输入,这意味着如果我调用过程Call getfreenum(1,5)会得到值779,但我应该得到下一个5个字符的值其中包括输入数字1

因此,如果从10000到100042之间(包括100042)取所有内容,则Call getfreenum(1,5)过程应返回10043,并且Call getfreenum(11,5)应该检查其余3个字符并返回11000。如果从11000取所有内容,则返回11600。到11599。即使我输入了4个字符,它也应该像每次输入一样工作:Call getfreenum(1234,5)过程应检查12340、12341、12342,如果12349是空闲的,则应返回该值,但不返回值这会更改输入数字,也就是说,如果我调用Call getfreenum(1234,5),并且一切都包括“ 123459”在内,那么函数应该为所有错误返回NULL或某个固定值。

2 个答案:

答案 0 :(得分:2)

  

功能用于将商品编号分配给商店中的商品。有时,对于某些物品,最大位数为3,有时为5。某些物品的起始数字为:假设香烟为“ 1254”。和“ 12”是奢侈品的起始编号。收银员在分配物料编号时更容易使用此逻辑。对我来说,这更复杂:) @Schwern – 3分钟前堆叠

这可以通过更好的模式设计更好地解决。

认识到“ 1254”实际上是两个部分。有类别ID 12和项目ID54。您无需将“ 1254”存储在这两个文件中。

create table item_categories(
    id integer primary key auto_increment,
    shop_id_padding integer not null default 5,
    name text not null
);
create table items (
    id integer primary key auto_increment,
    name text not null,
    category_id integer not null,
    foreign key(category_id) references item_categories(id)
);

显式的item_categories表为我们提供了参照完整性,一个存储类别名称的位置以及要使用的填充量。

现在,您可以让auto_increment来完成它的工作。

insert into item_categories (id, name, shop_id_padding) values (12, "cigarettes", 2);
insert into items (name, category_id) values ("Coffin Nails", 12);
insert into items (name, category_id) values ("Death Sticks", 12);

select * from items;
+----+--------------+-------------+
| id | name         | category_id |
+----+--------------+-------------+
|  1 | Coffin Nails |          12 |
|  2 | Death Sticks |          12 |
+----+--------------+-------------+

使用concat构造商店ID。根据类别填充ID。

select concat(i.category_id, lpad(i.id, cat.shop_id_padding, '0')) as shop_id
from items i
join item_categories cat on i.category_id = cat.id;
+---------+
| shop_id |
+---------+
| 1201    |
| 1202    |
+---------+

答案 1 :(得分:1)

您可以使用sifra和相关子查询来获得sifra + 1不存在的所有NOT EXISTS的集合。

num * power(10, maxval - floor(log10(num)) - 1)为您提供了最小数量,例如21000(代表21、5和num * power(10, maxval - floor(log10(num)) - 1) + power(10, maxval - floor(log10(num)) - 1))比最大数量多一个,例如22000 for 21,5。相应地将sifra + 1与之比较。

最后,您必须确保请求的位数不超过给定前缀的位数。即floor(log10(num)) < maxval必须得到满足。

要确保至少存在最小数量的前任num * power(10, maxval - floor(log10(num)) - 1) - 1,请使用UNION ALL将其添加到基本集中。

就像您可以只用SELECT来计算数字一样,没有任何循环(可能相对较慢)。

CREATE PROCEDURE getfreenum
                 (IN num integer,
                  IN maxval integer)
BEGIN
  SELECT CASE
           WHEN NOT EXISTS (SELECT *
                                   FROM artikli t2
                                   WHERE t2.sifra = num * power(10, maxval - floor(log10(num)) - 1)) THEN
             num * power(10, maxval - floor(log10(num)) - 1)
           ELSE
             min(t1.sifra) + 1
         END sifra
         FROM artikli t1
         WHERE floor(log10(num)) < maxval
               AND EXISTS (SELECT *
                                  FROM artikli t2
                                  WHERE sifra = num * power(10, maxval - floor(log10(num)) - 1))
               AND NOT EXISTS (SELECT *
                                      FROM artikli t2
                                      WHERE t2.sifra = t1.sifra + 1)
               AND t1.sifra >= num * power(10, maxval - floor(log10(num)) - 1) - 1
               AND t1.sifra < num * power(10, maxval - floor(log10(num)) - 1) + power(10, maxval - floor(log10(num)) - 1) - 1;
END;

DB Fiddle

如果要处理数字,则应使用适当的类型,而不要使用char