我有一个表可能会存储数十万个整数:
desc id_key_table;
+----------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+-------+
| id_key | int(16) | NO | PRI | NULL | |
+----------------+--------------+------+-----+---------+-------+
从程序中,我有一大堆整数。我想看看上面哪个整数不在上面的id_key列中。
到目前为止,我已经提出了以下方法:
1)遍历每个整数并执行:
select count(*) count from id_key_table where id_key = :id_key
当count为0时,表中缺少id_key。
这似乎是一种可怕的,可怕的方式。
2)创建一个临时表,将每个值插入临时表,并对这两个表执行JOIN。
create temporary table id_key_table_temp (id_key int(16) primary key );
insert into id_key_table_temp values (1),(2),(3),...,(500),(501);
select temp.id_key
from id_key_table_temp temp left join id_key_table as main
on temp.id_key = main.id_key
where main.killID is null;
drop table id_key_table_temp;
这似乎是最好的方法,但是,我确信有一个更好的方法,我还没有想到。我宁愿不必创建临时表并使用一个查询来确定缺少哪些整数。
对此类搜索是否有正确的查询?
(MySQL的)
答案 0 :(得分:4)
在问题中给出的第二个例子中使用你的代码,我创建了两个存储过程(SP):1 SP加载素数的样本表作为键,另一个SP找到缺失的整数。
这是第一个SP:
DELIMITER $$
DROP PROCEDURE IF EXISTS `test`.`CreateSampleTable` $$
CREATE PROCEDURE `test`.`CreateSampleTable` (maxinttoload INT)
BEGIN
DECLARE X,OKTOUSE,MAXLOOP INT;
DROP TABLE IF EXISTS test.id_key_table;
CREATE TABLE test.id_key_table (id_key INT(16)) ENGINE=MyISAM;
SET X=2;
WHILE X <= maxinttoload DO
INSERT INTO test.id_key_table VALUES (X);
SET X = X + 1;
END WHILE;
ALTER TABLE test.id_key_table ADD PRIMARY KEY (id_key);
SET MAXLOOP = FLOOR(SQRT(maxinttoload));
SET X = 2;
WHILE X <= MAXLOOP DO
DELETE FROM test.id_key_table WHERE MOD(id_key,X) = 0 AND id_key > X;
SELECT MIN(id_key) INTO OKTOUSE FROM test.id_key_table WHERE id_key > X;
SET X = OKTOUSE;
END WHILE;
OPTIMIZE TABLE test.id_key_table;
SELECT * FROM test.id_key_table;
END $$
DELIMITER ;
这是第二个SP:
DELIMITER $$
DROP PROCEDURE IF EXISTS `test`.`GetMissingIntegers` $$
CREATE PROCEDURE `test`.`GetMissingIntegers` (maxinttoload INT)
BEGIN
DECLARE X INT;
DROP TABLE IF EXISTS test.id_key_table_temp;
CREATE TEMPORARY TABLE test.id_key_table_temp (id_key INT(16)) ENGINE=MyISAM;
SET X=1;
WHILE X <= maxinttoload DO
INSERT INTO test.id_key_table_temp VALUES (X);
SET X = X + 1;
END WHILE;
ALTER TABLE test.id_key_table_temp ADD PRIMARY KEY (id_key);
SELECT temp.id_key FROM test.id_key_table_temp temp
LEFT JOIN test.id_key_table main USING (id_key)
WHERE main.id_key IS NULL;
END $$
DELIMITER ;
以下是使用数字25创建素数的第一个SP的样本运行:
mysql> CALL test.CreateSampleTable(25);
+-------------------+----------+----------+----------+
| Table | Op | Msg_type | Msg_text |
+-------------------+----------+----------+----------+
| test.id_key_table | optimize | status | OK |
+-------------------+----------+----------+----------+
1 row in set (0.16 sec)
+--------+
| id_key |
+--------+
| 2 |
| 3 |
| 5 |
| 7 |
| 11 |
| 13 |
| 17 |
| 19 |
| 23 |
+--------+
9 rows in set (0.17 sec)
mysql>
以下是使用25作为完整列表进行比较的第二个SP的运行:
mysql> CALL test.GetMissingIntegers(25);
+--------+
| id_key |
+--------+
| 1 |
| 4 |
| 6 |
| 8 |
| 9 |
| 10 |
| 12 |
| 14 |
| 15 |
| 16 |
| 18 |
| 20 |
| 21 |
| 22 |
| 24 |
| 25 |
+--------+
16 rows in set (0.03 sec)
Query OK, 0 rows affected (0.05 sec)
mysql>
虽然这个解决方案适用于小样本,但大名单成为一个主要问题。您可能希望保留临时表(不要反复使用CREATE TEMPORARY TABLE,只使用一次CREATE TABLE),永久地加载数字1 .. MAX(id_key)并通过id_key_table上的触发器填充该永久临时表。
只是一个问题,因为我很好奇:您是否这样做是为了查看表中的auto_increment键是否可以重复使用?