根据两列的不同组合选择最近的行

时间:2018-02-28 22:17:41

标签: mysql sql greatest-n-per-group

我正在写一个cronjob,它在我的数据库中的flags表上运行分析,结构如下:

| id | item | def | time_flagged | time_resolved | status  |
+----+------+-----+--------------+---------------+---------+
| 1  | 1    | foo | 1519338608   | 1519620669    | MISSED  |
| 2  | 1    | bar | 1519338608   | (NULL)        | OPEN    |
| 3  | 2    | bar | 1519338608   | 1519620669    | IGNORED |
| 4  | 1    | foo | 1519620700   | (NULL)        | OPEN    |

对于每个不同的def,对于每个唯一price,我想获得最新的"行(IFNULL(`time_resolved`, `time_flagged`) AS `time`)。如果给定的def-item组合不存在这样的行,那就没问题;我只是不想要给定def-item组合的任何重复项。

对于上述数据集,我想选择:

| def | item | time       | status  |
+-----+------+------------+---------+
| foo | 1    | 1519620700 | OPEN    |
| bar | 1    | 1519338608 | OPEN    |
| bar | 2    | 1519620669 | IGNORED |

第1行不包括在内,因为它已被覆盖"按行4,因为两行具有相同的def-item组合,后者具有更新的time

数据集将包含几十个不同的def,几百个不同的item,以及非常大量的flag,只会随着时间的推移而增加。 / p>

我该怎么做呢?我看到greatest-n-per-group标签充斥着类似的问题,但我没有看到任何涉及我需要的具体情况"嵌套分组"跨两列。

4 个答案:

答案 0 :(得分:2)

你可以尝试:

select distinct def, item, IFNULL(time_resolved, time_flagged) AS time, status from flags A where IFNULL(time_resolved, time_flagged) = (select MAX(IFNULL(time_resolved, time_flagged)) from flags B where A.item = B.item and A.def = B.def )

我知道这不是最好的方法,但它可能适合你

答案 1 :(得分:1)

根据您的mySQL版本,您可以使用窗口函数:

SELECT def, item, time, status
FROM (
  SELECT 
    def, 
    item,
    time,
    status,
    RANK() OVER(PARTITION BY def, item ORDER BY COALESCE(time_resolved, time_flagged) DESC) MyRank  -- Rank each (def, item) combination by "time"
  FROM MyTable
) src
WHERE MyRank = 1 -- Only return top-ranked (i.e. most recent) rows per (def, item) grouping

如果你有一个(def,item)组合,那么" time"值,然后将RANK()更改为ROW_NUMBER。这样可以保证每个分组只能获得一行。

答案 2 :(得分:1)

你的意思是'每个独特的Def和每个独特的项目'?如果是这样,多列的组似乎可以工作(显示为临时表t)连接回原始表以获取其余数据:

select 
    table.def,
    table.item,
    table.time,
    status
from
table
join (select
    def,
    item,
    max(time) time
from table
group by def, item) t
on 
    table.def=t.def and
    table.item=t.item and
    table.time=t.time

答案 3 :(得分:1)

select table.def, table.item, a.time, table.status 
from table 
join (select
      def, item, MAX(COALESCE(time_r, time_f)) as time
      from temp
      group by def, item) a 
on temp.def = a.def and
   temp.item = a.item and 
   COALESCE(temp.time_r, temp.time_f) = a.time