【问题标题】:Filtering out rows that have an identical column过滤掉具有相同列的行
【发布时间】:2019-07-26 18:28:35
【问题描述】:

我有一个复杂的查询,它返回一个表,其中一列有一些重复值,第二列有整数。

以下是数据外观的简单表示:

col1   col2
===========
A      null
A      1
A      1
A      2
A      3

B      2
B      3

C      4

D      null

我的要求是选择col2值为null或按col1分组时最小值的所有行。

因此,我的预期结果是:

col1   col2
===========
A      null
A      1
A      1

B      2

C      4

D      null

换句话说,对于 col1 中的每个不同值,在 col2 中找到相应的最小值,并过滤掉任何非空且大于该值的行。

我尝试进行分组,但当然组合了行。我觉得这里缺少一个有点简单的解决方案。

【问题讨论】:

    标签: mysql sql


    【解决方案1】:

    您可以使用or 和相关子查询:

    select t.*
    from t
    where t.col2 is null or
          t.col2 = (select min(t2.col2) from t t2 where t2.col1 = t.col1);
    

    重复一个复杂的查询很麻烦。您也可以使用窗口函数来做到这一点:

    select col1, col2
    from (select t.*, min(col2) over (partition by col1) as min_col2
          from t
         ) t
    where col2 is null or col2 = min_col2;
    

    【讨论】:

    • 不知道PARTITION BY。太好了,谢谢!
    • 请注意,PARTITION BY 语法需要 MySQL 8.0.2 或更高版本。
    • @BillKarwin 这可以解释为什么我当时不知道它。不幸的是,我们正在使用 5.6。
    • 接受了这一点,即使它不适用于我的特定用例,这是我没有在问题中指定的错。希望它对其他人有用。
    【解决方案2】:

    NOT EXISTS 很容易:

    select t.* from tablename t
    where not exists (
      select 1 from tablename x
      where x.col1 = t.col1 and x.col2 < t.col2
    )  
    

    请参阅demo
    结果:

    | col1 | col2 |
    | ---- | ---- |
    | A    | null |
    | A    | 1    |
    | A    | 1    |
    | B    | 2    |
    | C    | 4    |
    | D    | null |
    

    【讨论】:

    • 虽然不是绝对必要,但为了清楚起见,我添加了别名 x。 +1
    • 虽然这很简洁,但我正在使用的实际查询是从几十个表中提取的,因此我需要能够运行一次查询,然后将其过滤掉。也就是说,我需要用“tablename”替换复杂查询两次。
    猜你喜欢
    • 1970-01-01
    • 2018-10-21
    • 1970-01-01
    • 1970-01-01
    • 2018-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多