【问题标题】:Select values from a list that are not in a table从列表中选择不在表格中的值
【发布时间】:2015-09-09 01:17:03
【问题描述】:

我有一个 id 列表:

(1, 2, 3, 6, 7)

还有一张桌子:

id | anothercolumn
------------------
 1 | NULL
 2 | foo
 4 | bar
 5 | NULL
 6 | NULL

我想从我的列表中检索不是我的表的 id 的值。

预期结果:

3, 7

不带 FROM 的选择

我尝试过这样的事情:

SELECT i
WHERE i IN (1, 2, 3, 6, 7)
AND i NOT IN (SELECT id FROM mytable);

但这不是一个有效的 MySQL 查询(FROM 是必需的)。

联合

也有这种可能:

SELECT i
FROM (
    SELECT 1 AS i
    UNION SELECT 2
    UNION SELECT 3
    UNION SELECT 6
    UNION SELECT 7 ) AS mylistofids
LEFT JOIN mytable
ON mytable.id = i
WHERE mytable.id IS NULL;

这行得通,但是如果我的 id 列表变大,查询很快就会变大......

临时表

我还可以为我的 id 列表创建一个临时表:

CREATE TEMPORARY TABLE mylistofids (
    i INT
);

INSERT INTO mylistofids (i) VALUES (1), (2), (3), (6), (7);

然后在LEFT JOIN中使用它:

SELECT i
FROM mylistofids
LEFT JOIN mytable
ON mytable.id = i
WHERE mytable.id IS NULL;

这也有效,但就我而言,我无权创建表(临时或非临时)。

您是否找到了以最好的方式解决此问题的方法?

【问题讨论】:

  • 如果没有临时表,您可能必须在调用代码中解决它。一旦列表变大,DBMS 将达到 IN 语句的限制。此外 IN 语句不会向结果添加新键,因此 SELECT without FROM(即使使用 FROM)总是会失败。 UNION 版本可以工作,但对于较大的数字会很慢。

标签: mysql


【解决方案1】:

临时表是最好的解决方案,但如果不可能,那么您可以通过选择常量并将它们联合在一起来伪造临时表。

使用此解决方案,您可以执行以下操作:-

SELECT i
FROM 
(
    SELECT 1 AS i UNION SELECT 2 UNION SELECT 3 UNION SELECT 6 UNION SELECT 7
) AS mylistofids 
LEFT JOIN mytable
ON mytable.id = i
WHERE mytable.id IS NULL;

您还可以通过交叉连接数字范围来生成大量数字(假设您正在处理整数 id)。然后只需选择 IN 子句中的那些:-

SELECT i
FROM 
(
    SELECT units.i + tens.i * 10 + hundreds.i * 100 + thousands.i * 1000 + tensthousands.i * 10000 AS i
    FROM (SELECT 1 AS i UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 0 ) AS units
    CROSS JOIN (SELECT 1 AS i UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 0 ) AS tens
    CROSS JOIN (SELECT 1 AS i UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 0 ) AS hundreds
    CROSS JOIN (SELECT 1 AS i UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 0 ) AS thousands
    CROSS JOIN (SELECT 1 AS i UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 0 ) AS tensthousands
) AS mylistofids 
LEFT JOIN mytable
ON mytable.id = i
WHERE mylistofids.i IN (1, 2, 3, 6, 7)
AND mytable.id IS NULL;

【讨论】:

  • 与第一位没有区别,但您可以将其扩展为使用第二个解决方案。
  • 我怀疑表现很糟糕,但在大列表的情况下是个好主意(而不是逐个合并列表中的每个项目)!明天我会尝试对这个解决方案进行基准测试。
  • 我怀疑你是对的,但如果你很厚脸皮并且有一个包含连续 id 字段序列的现有表,你可以使用它!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-11
  • 2020-02-11
  • 1970-01-01
  • 2022-12-22
相关资源
最近更新 更多