SELECT,返回任何行中没有出现的值列表

时间:2012-04-04 14:42:23

标签: mysql

查询:

select id from users where id in (1,2,3,4,5)

如果users表包含id 1,2,3,则返回1,2和3.我想要一个返回4和5的查询。换句话说,我不希望查询返回任何表中存在的行,我想给它一个数字列表,并从该列表中获取出现在表中的值。

(更新以澄清几个不适用的答案之后的问题)

5 个答案:

答案 0 :(得分:18)

如果您不想(明确地)使用临时表,则可以使用:

SELECT id FROM (
  (SELECT 1 AS id) UNION ALL
  (SELECT 2 AS id) UNION ALL
  (SELECT 3 AS id) UNION ALL
  (SELECT 4 AS id) UNION ALL
  (SELECT 5 AS id)
) AS list
LEFT JOIN users USING (id)
WHERE users.id IS NULL

然而,它非常难看,很长,如果ID列表很长,我怀疑它会如何表现。

答案 1 :(得分:14)

鉴于这些数字是一个固定的列表。我能想到的最快的方法是有一个测试表,填充这些数字并做

未经测试的选择声明 - 但您将遵循原则。

select test.number 
from test 
left join 
    users 
on 
    test.number = users.id 
where test.number <> users.id

然后你会收回所有没有匹配的user.id的数字,所以可以填补这些漏洞..

答案 2 :(得分:14)

有相同的需求,并在BugFinder的会话中使用临时表建立答案。这样它在我完成查询后会自动被销毁,所以我不必处理房屋清理,因为我会经常运行这种类型的查询。

创建临时表:

CREATE TEMPORARY TABLE tmp_table (id INT UNSIGNED);

使用您要检查的值填充tmp_table:

INSERT INTO tmp_table (id) values (1),(2),(3),(4),(5);

创建并填充表后,像使用任何常规表一样运行查询:

SELECT tmp_table.id
  FROM tmp_table
  LEFT JOIN users u
  ON tmp_table.id = u.id
  WHERE u.id IS NULL;

This info on MySQL Temporary Tables was also useful

答案 3 :(得分:2)

另一种选择是使用包含所有可能ID的另一个表,然后从那里进行选择:

mysql> describe ids;
+-------+-----------------+------+-----+---------+-------+
| Field | Type            | Null | Key | Default | Extra |
+-------+-----------------+------+-----+---------+-------+
| id    | int(5) unsigned | NO   |     | 0       |       |
+-------+-----------------+------+-----+---------+-------+
1 row in set (0.05 sec)

mysql> select * from ids;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  4 |
|  5 |
+----+
5 rows in set (0.00 sec)

mysql> select * from users;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
+----+
3 rows in set (0.00 sec)


mysql> select id from ids where id not in (select id from users);
+----+
| id |
+----+
|  4 |
|  5 |
+----+
2 rows in set (0.04 sec)

添加了副作用 - 允许您通过插入ids表来扩展结果列表

答案 4 :(得分:0)

select missing.id
  from
(select ELT(@indx, 1,2,3,4,5) as id, @indx:=@indx+1
  from (select @indx:=1) init,
    users
  where ELT(@indx, 1,2,3,4,5) is not null
) missing
  left join users u using(id)
where u.id is null;

你在这里有:

  • ELT与变量@indx一起允许您将列表“转置”为列。
  • (select @indx:=1)需要将indx初始化为1
  • 需要在内部选择中使用
  • users表,以便MySQL可以迭代(因此列表的大小不能超过users表中的行数,如果是这样的话,你可以使用任何其他表都足够大而不是内部用户,表本身无关紧要只是要有一些东西可以迭代,所以只有它的大小才重要。)
  • 嵌套选择中的
  • ELT(@indx, 1,2,3,4,5) is not null条件是在索引超过列表大小时停止迭代。

其余的很简单 - left join并检查null