NOT IN 出乎意料地没有产生任何行

NOT IN yielding no rows, unexpectedly

我在 MariaDB 5.5 中有一个用户定义的函数 udf returns 一个布尔值。

以下给出了我的期望:

select c, count(*)
from (
    select fld, count(*)c
    from tbl
    where udf(fld)
    group by fld
) t
group by c;

+---+----------+
| c | count(*) |
+---+----------+
| 1 |    12345 |
| 2 |     1234 |
| 3 |      123 |
| 4 |       12 |
| 5 |        1 |
+---+----------+
5 rows in set (26.75 sec)

同样,下面给出了数字 12345(来自上面的 table),正如我所期望的:

select anotherfield, count(*)
from tbl
where udf(fld)
and fld in (
    select fld from (
        select fld,count(*)c
        from tbl
        group by fld
        having c=1
    )t
)
group by anotherfield with rollup;

我希望以下内容也会给我 12345:

select anotherfield, count(*)
from tbl
where udf(fld)
and fld not in (
    select fld from (
        select fld,count(*)c
        from tbl
        group by fld
        having c>1
    )t
)
group by anotherfield with rollup;

但是,它没有给我任何行。为什么?

如评论中所述,如果子查询返回的任何行是 NULL,则您不会返回任何行。一种解决方案是明确过滤它们:

where fld not in (select fld 
                  from tbl
                  where fld is not null
                  group by fld
                  having count(*) > 1 
                )

我的首选方法是使用 not exists,因为它具有正确的语义:

where not exists (select 1 
                  from tbl t2
                  group by fld
                  having count(*) > 1 and
                         tbl.fld = t2.fld
                 )

也就是说,更有效的方法通常是在行中找到一些差异,而不是检查 count(*)。也就是说,不是获取 all 具有相同字段的行,它可以在获取第二个时停止:

where not exists (select 1 
                  from tbl t2
                  where tbl.fld = t2.fld and
                        tbl.id <> t2.id -- or some appropriate column
                 )