MySQL:仅在最接近日期具有列值的地方选择行

时间:2019-06-29 00:08:54

标签: mysql sql inner-join in-subquery

我想返回所有在5月(2019-05)公开的行,所以如果在5月底之前的任何时候将某行转为草稿(而不是重新公开),我不希望这样做。例如:

id | post_id | status | date
-------------------------
 1 | 1       | draft  | 2019-03-25
 2 | 1       | public | 2019-04-02
 3 | 1       | draft  | 2019-05-25
 4 | 2       | draft  | 2019-03-10
 5 | 2       | public | 2019-04-01
 6 | 2       | draft  | 2019-06-01

上述期望的结果将返回post_id 2,因为其5月底之前的最后状态更改为public

post_id 1已在5月底之前恢复为草稿,因此不会包括在内。

我不确定如何使用正确的联接或子查询来尽可能高效地执行此操作。

2 个答案:

答案 0 :(得分:1)

您似乎想要截至2019-05-31的状态。相关子查询似乎是最简单的解决方案:

select t.*
from t
where t.date = (select max(t2.date)
                from t t2
                where t2.post_id = t.post_id and
                      t2.date <= '2019-05-31'
               );

要获取公开的信息,只需添加一个WHERE条件:

select t.*
from t
where t.date = (select max(t2.date)
                from t t2
                where t2.post_id = t.post_id and
                      t2.date <= '2019-05-31'
               ) and
      t.status = 'public';

为了提高性能,您希望在(post_id, date)上建立索引。

您也可以使用JOIN来表达这一点:

select t.*
from t join
     (select t2.post_id, max(t2.date) as max_date
      from t t2
      where t2.date <= '2019-05-31'
      group by t2.post_id
     ) t2
     on t2.max_date = t.date
where t.status = 'public';

我希望相关的子查询在正确的索引下具有更好的性能。但是,有时MySQL使我感到惊讶。

答案 1 :(得分:0)

我们需要确定是否

  1. 每个post_id的状态为public(带有max(date)的子查询)前的May
  2. 在每月post_id内,任何public的状态不等于May
  3. 然后排除满足该问题2的post_id

因此,您可以使用:

select distinct t1.post_id
  from tab t1
where t1.post_id not in
    (
     select distinct t1.post_id
       from tab t1
       join
       (
        select post_id, max(date) as date
          from tab 
         where '2019-05-01'> date
         group by post_id ) t2
         on t1.post_id = t2.post_id 
      where t1.status != 'public' 
        and t1.date < '2019-06-01' 
        and t1.date > '2019-04-30'
);

+---------+
| POST_ID |
+---------+
|    2    |
+---------+

Demo