【问题标题】:MySQL - Select from a list of numbers those without a counterpart in the id field of a tableMySQL - 从表的 id 字段中没有对应项的数字列表中选择
【发布时间】:2010-09-21 09:04:45
【问题描述】:

我有一个数字列表,比如 {2,4,5,6,7} 我有一个 foos.ID 表,包括 {1,2,3,4,8,9}

我想拿我的数字列表,并在我的表格的 ID 字段中找到没有对应的数字。

实现此目的的一种方法是创建一个表格栏,在 ID 字段中加载 {2,4,5,6,7}。 然后,我会这样做

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

但是,我想完成这个无临时表。

有人对它的发生方式有任何意见吗?

【问题讨论】:

  • 从上面的例子中,你需要得到5和6,对吧?
  • 是的,我正在寻找 5,6,7 - 抱歉,我是想把它放在这里。

标签: mysql set temp database-table


【解决方案1】:

如果你使用 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 中进行的后处理对于获得您想要的结果来说是最少的,并且避免创建临时表可能是值得的。

【讨论】:

    【解决方案2】:

    我遇到了类似的问题。我有一个范围,其中自动递增的主键有一些缺失值,所以首先我发现有多少: 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 表显着更大)。 无论如何,这给了我在总共 7 个缺失的结果中的 5 个结果,而另外两个保证与至少 5 个中的一个相邻。如果您丢失了更大的数字,您可能需要其他方法来查找剩余的丢失。

    【讨论】:

      【解决方案3】:

      这是一个很常见的问题:动态生成关系而不创建表。这个问题的 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,那么构建一个长列表可能会变得很烦人。

      另一种解决方案是保留一个十位数的通用表格,并重复用于多种用途。

      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..99 生成值的内部查询,即使在这种情况下这不是必需的。但是您的列表中的值可能大于 10。关键是,使用一张表num,您可以生成大量数字,而不必求助于每个值一个UNION 的非常长的链。此外,您可以在一处指定所需值的列表,这样更方便和可读。

      【讨论】:

      • 遗憾的是,所使用的数字在大小和范围上是任意的。这排除了你的第二个选择。第一个有点笨拙,但在没有桌子的情况下建立关系并不是这个国家最好的事情。我真的很希望得到一些基于集合的逻辑,但是 mysql 的 SET 似乎很弱。
      • 这个解决方案对我有用。如果您要处理重复值,请使用union all select
      • 8年后这个案子仍然是个问题:)。
      【解决方案4】:

      Alnitak 的(和你的)解决方案应该可以工作,我无法处理只能在 SQL 语言中工作的其他任何事情。

      但问题来了 - 你如何传递值列表?在调用代码中处理这个不是更好吗 - 即请求 ID 并在 colling 代码中比较它,这可能是一种更适合这种操作的语言。

      【讨论】:

        【解决方案5】:

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

        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)
        

        但后来我意识到这与你想要的相反。

        【讨论】:

        • 是的,临时表是要走的路。你说得对——我们读得太快了:)谢谢,我要删除我的帖子。
        • 太糟糕了,我宁愿不创建临时表...不过,这似乎是我最好的选择。谢谢!
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-23
        • 2012-09-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-15
        相关资源
        最近更新 更多