2016-12-02 27 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 | 
+-------------------+-----------------+ 

現在你可以使用該值。