2016-12-02 34 views
0

我想实现的是一个存储过程,它返回一个表中所有缺少的id的记录集。 例如:MySQL存储过程的变量表名和检索丢失的记录

-------------------- 
| games   | 
-------------------- 
| id | game name | 
-------------------- 
| 1 | first game | 
| 2 | second game | 
| 5 | fifth game | 
| 10 | tenth game | 
------------------- 

这将导致:

---------- 
| result | 
---------- 
| 3  | 
| 4  | 
| 6  | 
| 7  | 
| 8  | 
| 9  | 
---------- 

注意这里是可以处理多个表,所以我想只有一个需要维护的存储过程,所以表名应该动态添加。

我在存储过程中发现了几个关于预准备语句,参数和循环的教程,但是我没有得到该组合的工作方式。

我心里有应用的逻辑是:

  1. 表中获得的最高ID
  2. 遍历表,并检查迭代器存在的ID
  3. 如果不是,添加到结果集,并返回结果循环完成

此设置后是我走到这一步:

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 

谁能解释我如何让这个组合工作?

+1

你有什么到目前为止 – Drew

+0

我投票关闭这一问题作为题外话,因为这里是我的规格,所以请做 – Drew

+0

@Drew,我补充说,我现在有足够 – stijnpiron

回答

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 ; 

试试看。

+0

这会越来越近,但我想找到缺失的ID直到最高ID从该表中检查,我有另一个存储过程:get_highest_id(in_tablename,out_highestid)。 那会怎么样呢? – stijnpiron

+0

顺便说一句,你为什么要找到最高的ID?我试过这个SP,它显示了我的表中所有缺少的ID,只需确保临时表的最大数量高于表的最大ID。如果这不足以解决您的问题,您可否详细说明一下? – Hermanto

+0

原因如下:目前,一张表可能有300条记录,但在一年内4000(例如),这意味着此时最大的id是例如320(缺少20条记录)en一年4100人(有100人失踪)。我想要列出在此时间点范围内从零到最大ID的所有缺失数字。如果我可以让自己清楚,我不想知道并输入最大ID的长度,当我检查丢失的ID时 – stijnpiron

0

使用一些技巧从this,您可以使用单个查询来寻找失踪的IDS:

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 | 
+-------------------+-----------------+ 

现在你可以使用该值。