MySQL -从一个数字列表中选择那些在表的id字段中没有对应的数字

dxpyg8gm  于 2023-04-29  发布在  Mysql
关注(0)|答案(6)|浏览(129)

我有一个数字列表,比如{2,4,5,6,7}我有一个表,foos,有foos。(一)(二)(三)(四)(一)(三)(四)(四)(五)(五)(五)(六)(五)(六)(六)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(八)(
我想拿我的号码列表,在我的表的ID字段中找到那些没有对应的号码。
实现这一点的一种方法是创建一个表格栏,在ID字段中加载{2,4,5,6,7}。那我会做的

SELECT bars.* FROM bars LEFT JOIN foos ON bars.ID = foos.ID WHERE foos.ID IS NULL

但是,我想在没有临时表的情况下完成此操作。
有谁能告诉我这是怎么发生的吗?

gupuwyp2

gupuwyp21#

这是一个非常常见的问题:在不创建表的情况下动态地生成关系。这个问题的SQL解决方案非常笨拙。使用派生表的一个示例:

SELECT n.id
FROM
  (SELECT 2 AS id 
   UNION SELECT 3 
   UNION SELECT 4 
   UNION SELECT 5 
   UNION SELECT 6 
   UNION SELECT 7) AS n
  LEFT OUTER JOIN foos USING (id)
WHERE foos.id IS NULL;

但这并不能很好地扩展,因为您可能有很多值而不是只有六个。构建一个每个值需要一个UNION的长列表可能会变得令人厌烦。
另一种解决方案是在手边保存一个包含10位数字的通用表,并将其重复用于多种用途。

CREATE TABLE num (i int);
INSERT INTO num (i) VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9);

SELECT n.id
FROM 
  (SELECT n1.i + n10.i*10 AS id
   FROM num AS n1 CROSS JOIN num AS n10
   WHERE n1.i + n10.i*10 IN (2, 3, 4, 5, 6, 7)) AS n
  LEFT OUTER JOIN foos USING (id)
WHERE foos.id IS NULL;

我展示了从0生成值的内部查询。0.99虽然这案子不需要这个但列表中的值可能大于10。关键是,使用一个表num,您可以生成大量数字,而不必求助于每个值一个UNION的非常长的链。此外,您可以在一个地方指定所需值的列表,这更方便和可读。

3pvhb19x

3pvhb19x2#

我找不到一个不使用临时表的解决方案来解决你的问题,但是使用子选择而不是连接来执行查询的另一种方法是:

SELECT bars.* FROM bars WHERE bars.ID NOT IN (SELECT ID FROM foos)

就像我最初写的其他海报一样:

SELECT * FROM foos WHERE foos.ID NOT IN (2, 4, 5, 6, 7)

但后来我意识到这会产生与你想要的相反的结果。

nnsrf1az

nnsrf1az3#

如果您使用PHP,您可以在不创建任何临时表的情况下完成此工作。

SELECT ID FROM foos WHERE foos.ID IN (2, 4, 5, 6, 7)

您可以使用PHP的array_diff()函数将其转换为所需的结果。如果你的列表(2,4,5,6,7)在一个名为$list的数组中,而上面查询的结果在一个数组$result中,那么

$no_counterparts = array_diff($list, $result);

...将返回列表中的所有数字,而数据库表中没有对应的数字。虽然这个解决方案不会在查询中执行整个操作,但是在PHP中需要做的后期处理很少,以获得所需的结果,并且避免创建临时表可能是值得的。

vbopmzt1

vbopmzt14#

我也遇到过类似的问题。我有一个自动递增的主键有一些缺失值的范围,所以首先我找到了有多少个:select count(*) from node where nid > 1962。将这个数字与最大值进行比较,我发现缺少这个数字。然后我运行了这个查询:select n2.nid from node n1 right join node n2 on n1.nid = (n2.nid - 1) where n1.nid is null and n2.nid > 1962这将查找非连续缺失记录的数量。它不会显示连续的,我不完全确定如何做到这一点,除了更改ON子句以允许更大的范围(这将使JOIN表大大增加)。在任何情况下,这给了我五个结果的总数七失踪,和其他两个保证旁边的至少一个五。如果你有一个更大的数字丢失,你可能需要一些其他的方法来找到其余的失踪。

mftmpeh8

mftmpeh85#

Alnitak的(和你的)解决方案应该工作,我不能对任何其他只能在SQL语言中工作的东西。
但问题来了--如何传递值列表?在调用代码- i中处理这个不是更好吗?e.请求ID并在冷却代码中比较它,冷却代码可以是更适合于这种操作的语言。

vxf3dgd4

vxf3dgd46#

碰巧来到这里寻找答案。之前的文章是MySQL 8。由于MySQL从版本8开始就有value语句。0.19,这个问题可以非常优雅地使用value语句沿着CTE来解决,CTE也是MySQL 8之后的版本。0

步骤1:合并CTE和value语句创建一组行,其中的值需要与表进行比较(这里的表是foo)。

with MyValues(val) as
(
  values row(2),row(4),row(5),row(6),row(7)
)

第二步:将CTE与表foo进行外连接,并使用foo从外连接后的CTE中过滤空值行

WITH myvalues(val)
     AS (VALUES ROW(2), ROW(4), ROW(5), ROW(6), ROW(7))
SELECT f.id
FROM   foo f
       LEFT OUTER JOIN myvalues m
                    ON f.id = m.val
WHERE  m.val IS NULL;

小径

mysql> WITH myvalues(val)
    ->      AS (VALUES ROW(2), ROW(4), ROW(5), ROW(6), ROW(7))
    -> SELECT f.id
    -> FROM   foo f
    ->        LEFT OUTER JOIN myvalues m
    ->                     ON f.id = m.val
    -> WHERE  m.val IS NULL;
+------+
| id   |
+------+
|    1 |
|    3 |
|    8 |
|    9 |
+------+
4 rows in set (0.00 sec)

或使用IN子句

mysql> WITH myvalues(val)
    ->      AS (VALUES ROW(2), ROW(4), ROW(5), ROW(6), ROW(7))
    -> SELECT f.id
    -> FROM   foo f
    -> WHERE  id NOT IN (SELECT val
    ->                   FROM   myvalues);
+------+
| id   |
+------+
|    1 |
|    3 |
|    8 |
|    9 |
+------+
4 rows in set (0.00 sec)

相关问题