【问题标题】:Display the MAX date for each record in a WHERE IN clause SQL在 WHERE IN 子句 SQL 中显示每条记录的 MAX 日期
【发布时间】:2019-11-09 12:33:00
【问题描述】:

使用 MySQL,我有一个名为subscriptions 的表,如下所示

name,   renewal_date,    national_id
---------------------------------------
ted,     1/2/2010,        A1111R
ben,     1/3/2010,        A145E1
bob,      8/4/2009,       A11C11
kate,     2/2/2010,       A111E1
ted,     12/2/2011,       A1111R
bob,     12/2/2014,       A11C11
ben,     12/2/2016,       A145E1

etc..

该表有大约 150000 条记录。每个人可以有多个订阅。我想为给我查询的列表中的每条记录显示最大/最新renewal_date。这是我的sql语句:

select d.name, d.renewal_date, d.national_id
from subscriptions d
where renewal_date= (select max(d1.renewal_date) 
                     from subscriptions d1 
                     where d1.national_id = d.national_id IN ('A1111R','A11C11', 'A145E1' ....));

当我在 phpmyadmin 中运行查询时,它似乎并没有结束执行,即使 IN 子句中的记录很少。

最好的方法是什么?我还应该说我还不是 SQL 专家 :-) 在此先感谢

【问题讨论】:

  • 对于 MySQL,最好知道您正在使用的版本。最近发生了重要的变化。在 MySQL 8 中,有些事情比以前的版本更容易实现。
  • 表中的同名可以有两个不同的national_id吗?如果是这样,您是想要姓名一个结果行还是每个姓名和national_id 一个结果行?
  • 谢谢@ThorstenKettner。 MySQL 版本是 5.7.25。不,表中的同名不能有两个不同的national_id。
  • 那么是时候修复数据库设计了。一张供有国民身份证的人使用,一张供订阅者使用。

标签: mysql sql phpmyadmin


【解决方案1】:

假设给定人的姓名和国家 ID 不变,您可以只使用聚合:

select d.name, max(d.renewal_date), d.national_id
from subscriptions d
where d.national_id in ( . . . )
group by d.name, d.national_id;

如果您想要行上的所有列,最有效的方法通常是具有正确索引的相关子查询:

select s.*
from subscriptions s
where s.national_id in ( . . . ) and
      s.renewal_date = (select max(s2.renewal_date)
                        from subscriptions s2
                        where s2.national_id = s.nation_id
                       );

正确的索引是(national_id, renewal_date)。实际上,在许多情况下,这可能比 group by 查询更快。

【讨论】:

  • 非常感谢@gordon-linoff 的出色回答和快速响应。第二个例子对我有用。最后,如果我想删除我显示的那些续订日期,我将如何从select 转换为deletedelete s.renewal_date from... 之类的东西?
  • @adamvanbart:要删除这些行,只需将 select s.* 更改为 delete。还是您想更新行并只删除(即设为 null)它们的日期?
  • 谢谢@gordonlinoff。我不想删除整行,只删除renewal_date
  • 然后把select s.* from subscriptions s改成update subscriptions s set renewal_date = null
  • 谢谢@ThorstenKettner。但是 MySQL 会抛出一个错误:#1093 - You can't specify target table 's' for update in FROM clause
【解决方案2】:

您需要每个名称的最大续订日期。如果是这样,那么您需要做的就是聚合:

select name, max(renewal_date)
from subscriptions
group by name
order by name;

我不知道,national_id 是如何进入 Play 的。一个人的national_id 真的可以从一个订阅更改为另一个订阅吗?还是您的数据库设计存在缺陷?

你可能想要这个:

select name, national_id, max(renewal_date)
from subscriptions
group by name, national_id
order by name, national_id;

或者这个:

select name, max(renewal_date), any_value(national_id)
from subscriptions
group by name
order by name;

或者这个:

select *
from subscriptions
where (name, renewal_date) in
(
  select name, max(renewal_date)
  from subscriptions
  group by name
)
order by name;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-10
    • 1970-01-01
    • 1970-01-01
    • 2011-04-21
    • 1970-01-01
    • 2012-06-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多