MySql IN 子句,试图匹配元组的 IN 列表

Posted

技术标签:

【中文标题】MySql IN 子句,试图匹配元组的 IN 列表【英文标题】:MySql IN clauses, trying to match IN list of tuples 【发布时间】:2014-09-17 10:32:23 【问题描述】:

我正在尝试根据三列的匹配来选择重复记录。三元组的列表可能很长(1000 个),所以我想简明扼要。

当我有一个大小为 10(已知重复)的列表时,它只匹配 2 个(看似随机的)而错过了其他 8 个。我希望返回 10 条记录,但只看到 2 条。

我已经把它缩小到这个问题:

这将返回一条记录。预期 2:

select * 
from ali
where (accountOid, dt, x) in
(
  (64, '2014-03-01', 10000.0), 
  (64, '2014-04-23', -122.91)
)

按预期返回两条记录:

select * 
from ali
where (accountOid, dt, x) in ( (64, '2014-03-01', 10000.0) )
or (accountOid, dt, x) in ( (64, '2014-04-23', -122.91) )

知道为什么第一个查询只返回一条记录吗?

【问题讨论】:

我无法在我的机器上重现该问题(mysql 5.6.14)。你会做一个小提琴吗? 您能否编辑您的问题并描述列的数据类型 (SHOW CREATE TABLE ali)?如果您对列x 使用FLOATDOUBLE,则可能会导致相等比较失败,因为精确值以意想不到的方式四舍五入。还请具体说明您使用的 MySQL 版本。 你能贴出你正在使用的代码吗?我将它复制到一个表中,起初它看起来像是一个操作数值,但这是我缺少括号集的错。像 Vatev 我无法重现问题 不知道如何让它成为一个小提琴。我已将查询更改为使用: (a,b,c) = (...) or (a,b,c) = () or (a,b,c) = () ... 不理想我知道,但它有效。当我有更多时间时,我会发布代码。感谢您的关注。 google for sql fiddle (sqlfiddle.com),它是一个发布和测试 SQL 的平台。或者只是在这里发布您的表创建语句。 【参考方案1】:

我建议您不要为此使用 IN(),而是使用 where exists 查询,例如:

CREATE TABLE inlist
    (`id` int, `accountOid` int, `dt` datetime, `x` decimal(18,4))
;

INSERT INTO inlist
    (`id`, `accountOid`, `dt`, `x`)
VALUES
    (1, 64, '2014-03-01 00:00:00', 10000.0),
    (2, 64, '2014-04-23 00:00:00', -122.91)
;

select *
from ali
where exists ( select null
               from inlist
               where ali.accountOid = inlist.accountOid
               and ali.dt = inlist.dt
               and ali.x = inlist.x
             )
;

我能够重现一个问题(比较 http://sqlfiddle.com/#!2/7d2658/6 到 http://sqlfiddle.com/#!2/fe851/1 两者都是 MySQL 5.5.3),如果 x 列是数字并且值是负数,则使用 IN() 不匹配,但当任一数字时匹配或十进制使用表格和存在的地方。

也许不是一个决定性的测试,但我个人无论如何都不会使用 IN() 。

为什么不这样确定重复项?

select
        accountOid
      , dt
      , x
from ali
group by
        accountOid
      , dt
      , x
having
        count(*) > 1

然后将其用作 where exists 条件中的派生表:

select *
from ali
where exists (
               select null
               from (
                      select
                              accountOid
                            , dt
                            , x
                      from ali
                      group by
                              accountOid
                            , dt
                            , x
                      having
                              count(*) > 1
                     ) as inlist
               where ali.accountOid = inlist.accountOid
               and ali.dt = inlist.dt
               and ali.x = inlist.x
             )

请参阅http://sqlfiddle.com/#!2/ede292/1 以了解上面的查询

【讨论】:

inner join syntax would seem simpler 给我。我也希望连接同样有效,尽管根据 SQL Fiddle 的说法,查询计划确实不同,我不太擅长解释这些。 是的,好点,使用同一个派生表的内连接也是一种选择。 sqlfiddle 的执行计划通常没有那么重要,因为没有索引并且数据规模太小 - 但两种方法没有太大区别。

以上是关于MySql IN 子句,试图匹配元组的 IN 列表的主要内容,如果未能解决你的问题,请参考以下文章

在运算符中使用以匹配元组中的项目

python列表和元组的方法

在 SQL“IN”子句中使用元组

Oracle In(匹配)子句

Oracle In(匹配)子句

SQL,试图摆脱大 IN 子句