从一组值中,如何找到未存储在表列中的值?

Cli*_*ton 5 mysql

我有一个表,它可能会存储数十万个整数:

desc id_key_table;

+----------------+--------------+------+-----+---------+-------+
| Field          | Type         | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+-------+
| id_key         | int(16)      | NO   | PRI | NULL    |       |
+----------------+--------------+------+-----+---------+-------+
Run Code Online (Sandbox Code Playgroud)

从程序中,我有一大组整数。我想看看这些整数中哪些不在上面的 id_key 列中。

到目前为止,我提出了以下方法:

1) 遍历每个整数并执行:

select count(*) count from id_key_table where id_key = :id_key
Run Code Online (Sandbox Code Playgroud)

当 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;
Run Code Online (Sandbox Code Playgroud)

这似乎是最好的方法,但是,我确信还有更好的方法我还没有想到。我宁愿不必创建临时表并使用一个查询来确定缺少哪些整数。

这种类型的搜索有正确的查询吗?

(MySQL)

Rol*_*DBA 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 ;
Run Code Online (Sandbox Code Playgroud)

这是第二个 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 ;
Run Code Online (Sandbox Code Playgroud)

以下是使用数字 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>
Run Code Online (Sandbox Code Playgroud)

这是第二个 SP 的运行情况,使用 25 作为完整列表进行比较:

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>
Run Code Online (Sandbox Code Playgroud)

虽然这个解决方案对于小样本来说是可以的,但大列表却成为一个令人头疼的问题。您可能希望保持临时表(不要一遍又一遍地使用 CREATE TEMPORARY TABLE,只使用 CREATE TABLE 一次)永久加载数字 1 .. MAX(id_key) 并通过 id_key_table 上的触发器填充该永久临时表。

只是一个问题,因为我很好奇:您这样做是为了查看表中的 auto_increment 键是否可以重用???