群友的一个小问题,大意如下。我手中目前已知有若干ID列表,如[1,2,3,4,5]的ID,需要到某张表中查询出表中不存在的ID。

好像有点绕,实际列举数据说明下,比如此刻表中有ID为[2,4,5,6,7]的数据,那么最终查询出来的结果应当为[1,3],因为[1,3]在我们已知的列表[1,2,3,4,5]中,但是不在数据库的表[2,4,5,6,7]中,而[6,7]因为不在[1,2,3,4,5]中,所以也不符合要求。

其实这个问题很好解的,最直观的来说我们先拿[1,2,3,4,5],到表中查询[2,4,5,6,7]用in语句得到[2,4,5]的结果,之后再拿[1,2,3,4,5]到[2,4,5]的结果集中用not in语句就可以得到[1,3]。

但,问题不是这里,而是[1,2,3,4,5]不是一个结果集,而是入参,所以我们这里我们需要用到MYSQL的临时表。而如果[1,2,3,4,5]是在一张表里的结果的话,那么我们就可以换另一个思路了,用临时表[1,2,3,4,5]LEFT JOIN目标表使用id关联,并保留当前的[1,2,3,4,5]的列和目标表的ID列,关联后的结果如果目标ID列为空的数据可以再做一次过滤剔除。

那么我们的语句就可以这么写

CREATE TEMPORARY TABLE IF NOT EXISTS TMP_TABLE
(
    ID INT(10) NOT NULL
);
TRUNCATE TABLE TMP_TABLE;
INSERT INTO TMP_TABLE (`ID`)
VALUES (1),(2),(3),(4),(5);
SELECT ID
FROM (
         SELECT A.ID, B.ID AS BID
         FROM TMP_TABLE AS A
                  LEFT JOIN TABLE_C AS B
                            ON A.ID = B.ID
     ) AS C
WHERE C.BID IS NULL;

需要注意的是只有在当前连接情况下, TEMPORARY 表才是可见的。当连接关闭时, TEMPORARY 表被自动取消。这意味着两个不同的连接可以使用相同的临时表名称,同时两个临时表不会互相冲突,也不与原有的同名的非临时表冲突。(原有的表被隐藏,直到临时表被取消时为止。)必须拥有 CREATE TEMPORARY TABLES 权限,才能创建临时表。可以通过指定 ENGINE|TYPE = MEMORY; 来指定创建内存临时表。https://www.xp.cn/b.php/110742.html

但是如果说你的账户没有权限创建临时表,那么还有个办法

SELECT ID
FROM (
         SELECT A.ID, B.ID AS BID
         FROM (
                  SELECT 1 AS `ID`
                  UNION
                  SELECT 2 AS `ID`
                  UNION
                  SELECT 3 AS `ID`
                  UNION
                  SELECT 4 AS `ID`
                  UNION
                  SELECT 5 AS `ID`
              ) AS A
                  LEFT JOIN TABLE_C AS B
                            ON A.ID = B.ID
     ) AS C
WHERE C.BID IS NULL;

就是把所有的参数UNION起来当做一个结果集,只是如果如果参数比较多的话,就看起来一堆UNION语句,看起来有点难受