MySQL:select 仅在最接近日期的行具有列值
MySQL: select row only where closest to date has column value
我想 return 5 月 (2019-05) 中 public 的所有行,因此如果某一行被转为草稿(而不是回到 public)五月底之前的任何一点,我都不想要。例如:
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
上述的预期结果是 return post_id 2
,因为它在 5 月底之前的最后一次状态更改是 public
。
post_id 1
5 月底前又回到草稿中,所以不会被收录。
我不确定如何使用正确的连接或子查询来尽可能高效地执行此操作。
我们需要确定是否
- 每个
post_id
的状态在 May
月份之前是 public
(具有 max(date) 的子查询),
- 在
May
、 月内存在状态不等于 public
的任何 post_id
- 然后排除
post_id
满足事项2.
因此,您可以使用:
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 |
+---------+
您似乎想要截至 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'
);
要获得 public,只需添加一个 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 会让我感到惊讶。
我想 return 5 月 (2019-05) 中 public 的所有行,因此如果某一行被转为草稿(而不是回到 public)五月底之前的任何一点,我都不想要。例如:
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
上述的预期结果是 return post_id 2
,因为它在 5 月底之前的最后一次状态更改是 public
。
post_id 1
5 月底前又回到草稿中,所以不会被收录。
我不确定如何使用正确的连接或子查询来尽可能高效地执行此操作。
我们需要确定是否
- 每个
post_id
的状态在May
月份之前是public
(具有 max(date) 的子查询), - 在
May
、 月内存在状态不等于 - 然后排除
post_id
满足事项2.
public
的任何 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 |
+---------+
您似乎想要截至 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'
);
要获得 public,只需添加一个 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 会让我感到惊讶。