我想要实现的是一个存储过程,它返回表中所有缺失id的记录集。 例如:
--------------------
| games |
--------------------
| id | game name |
--------------------
| 1 | first game |
| 2 | second game |
| 5 | fifth game |
| 10 | tenth game |
-------------------
这应该导致:
----------
| result |
----------
| 3 |
| 4 |
| 6 |
| 7 |
| 8 |
| 9 |
----------
请注意,有多个表可以处理,因此我希望只有一个需要维护的存储过程,因此应该动态添加表名。
我在存储过程中找到了关于预处理语句,参数和循环的几个教程,但是我没有让组合工作。
我想要应用的逻辑是:
这是我到目前为止所得到的:
CREATE DEFINER=`root`@`localhost` PROCEDURE `get_missing_ids`(IN in_kind varchar(15), OUT out_result int)
BEGIN
DECLARE highest_id INT;
DECLARE i INT;
DECLARE check_id INT;
SET @highestid = CONCAT("(CALL get_highest_id('", in_kind, "',@id)");
PREPARE stmt1 FROM @highestid;
SET highest_id = (EXECUTE stmt1);
WHILE i < highest_id DO
SET @checkid = CONCAT("SELECT COUNT(*) FROM ", in_kind, " WHERE id = ", i, ")");
PREPARE stmt2 FROM @checkid;
SET check_id = (EXECUTE stmt2);
IF check_id = 0 THEN
SELECT i;
END IF;
END WHILE;
END
谁能解释我如何让这个组合起作用?
答案 0 :(得分:0)
实际上你根本不需要循环。您只需要将源表与包含序列号的临时(或固定)表连接起来并进行比较。
要使其成为获取该表的表名和ID的存储过程,请尝试此存储过程。它适用于我的。
delimiter $$
use `test`$$
drop procedure if exists `FindMissedID`$$
create definer=`root`@`localhost` procedure `FindMissedID`(tableName varchar(100), tableNameID varchar(100))
begin
-- Create temporary table containing number for comparing source table
drop table if exists ListOfNumber;
create temporary table ListOfNumber(
number int,
primary key (number)
)
engine = innodb;
-- Generate some numbers. Make it fit your needs
insert into ListOfNumber
select @row := @row + 1 as row from
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) tens,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) hundreds,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) thousands,
-- etc
(select @row:=0) r;
-- Make a prepared statement
set @SQL = concat("select ListOfNumber.number as MissingID"
, char(10), "from ", tableName
, char(10), "right join ListOfNumber on ", tableName, ".", tableNameID, " = ListOfNumber.number"
, char(10), "where ", tableName, ".", tableNameID, " is null"
, char(10), "order by ListOfNumber.number"
);
-- Execute statement
prepare statement from @SQL;
execute statement;
deallocate prepare statement;
end$$
delimiter ;
试一试。
答案 1 :(得分:0)
使用this中的一些提示,您可以使用单个查询来查找缺少的ID:
DELIMITER //
CREATE PROCEDURE `get_missing_ids`()
BEGIN
SELECT (t1.id + 1) as missing_starts_at,
(SELECT MIN(t3.id) -1
FROM games t3
WHERE t3.id > t1.id
) as missing_ends_at
FROM games t1
WHERE NOT EXISTS (SELECT t2.id
FROM games t2
WHERE t2.id = t1.id + 1)
HAVING missing_ends_at IS NOT NULL;
END//
这将返回范围为:
的行call `get_missing_ids`();
+-------------------+-----------------+
| missing_starts_at | missing_ends_at |
+-------------------+-----------------+
| 3 | 4 |
| 6 | 9 |
+-------------------+-----------------+
现在您可以使用该值。