【问题标题】:MySQL: Get the minimum record for a user on a given dayMySQL:获取用户在给定日期的最少记录
【发布时间】:2015-04-27 17:25:30
【问题描述】:

我有一张活动表,每个活动都有负责人。每天可能有多个此类事件,但我需要在给定日期为每个用户的 first 查询记录。

例如,如果我有以下事件表:

+----------+-------------+---------------------+
| event_id | director_id | event_start         |
+----------+-------------+---------------------+
|        1 |         111 | 2015-04-27 10:00:00 |
+----------+-------------+---------------------+
|        2 |         222 | 2015-04-27 11:00:00 |
+----------+-------------+---------------------+
|        3 |         333 | 2015-04-27 12:00:00 |
+----------+-------------+---------------------+
|        4 |         111 | 2015-04-27 13:00:00 |
+----------+-------------+---------------------+
|        5 |         222 | 2015-04-27 09:00:00 |
+----------+-------------+---------------------+

我希望返回以下内容:

+----------+-------------+---------------------+
| event_id | director_id | event_start         |
+----------+-------------+---------------------+
|        1 |         111 | 2015-04-27 10:00:00 |
+----------+-------------+---------------------+
|        5 |         222 | 2015-04-27 09:00:00 |
+----------+-------------+---------------------+
|        3 |         333 | 2015-04-27 12:00:00 |
+----------+-------------+---------------------+

我认为像下面这样的查询会起作用,但事实证明 MySQL 不支持 WHERE 子句中的 MIN (simple SQL query giving Invalid use of group function):

SELECT
        event_id, director_id, MIN(event_start) AS event_start 
    FROM events 
    WHERE MIN(event_start) >= '2015-04-27 00:00:00' 
        AND MIN(event_start) < '2015-04-28 00:00:00'
    GROUP BY director_id;

我怎样才能以最有效的方式做到这一点?我的events 表可能很容易有 10,000-100,000 条记录。

【问题讨论】:

  • 你为什么不用WHERE event_start = '2015-04-27 00:00:00'?因为value &gt;= 1 AND value &lt; 2 的结果是value = 1!?
  • @C4ud3x 事件可以在任何给定时间开始。第一次不一定会在午夜开始。
  • 哦,对不起。有时间本身是肯定的哈哈。只是在寻找日期。
  • 应该在 event_id 5、director_id 222 在您所需的输出中有一个 2015-04-27 09:00:00 的 event_start 吗?

标签: mysql


【解决方案1】:

您可以通过与您类似的查询获得每天的最短活动时间:

SELECT director_id, date(event_start) as dte, MIN(event_start) AS event_start 
FROM events e
GROUP BY director_id, date(event_start);

然后您可以将其用作子查询以从行中获取所有其他信息:

select e.*
from events e join
     (SELECT e.director_id, date(e.event_start) as dte, MIN(e.event_start) AS event_start 
      FROM events e
      GROUP BY e.director_id, date(e.event_start)
     ) ee
     on e.event_start = ee.event_start -- note, this has both the date and time;

如果要将结果限制为一天,可以将where 子句放在子查询中。

【讨论】:

    【解决方案2】:

    您不能在查询的 where 子句中使用 group by / 聚合函数。做你想做的一种方法是像这样使用左连接:

    select e1.*
      from events e1
        left join events e2
          on e1.director_id = e2.director_id
            and e1.event_start > e2.event_start
            and date(e1.event_start) = date(e2.event_start)
      where e2.director_id is null
    

    fiddle here

    如果您有跨 (director_id, event_start) 的索引,则性能可能会提高

    您还可以通过更改and date(e1.event_start) = date(e2.event_start) 来进一步限制结果大小以检查特定日期。

    【讨论】:

    • 老派。很好,但我们不再这样做了。性能是杀手锏。
    • 老实说,我不能说我曾经将它与子查询连接进行比较——它只是具有更好的美感!
    【解决方案3】:

    你可以试试这个:

    SELECT
      e1.* 
    FROM events AS e1
      INNER JOIN ( SELECT director_id, MIN(event_start) AS `eventStart` 
                   FROM `events` GROUP BY director_id ) AS e2
      ON e1.director_id = e2.director_id
      AND e1.event_start = e2.eventStart
    WHERE e2.eventStart >= '2015-04-27 00:00:00' 
      AND e2.eventStart < '2015-04-28 00:00:00';
    

    这里是sqlfiddle

    【讨论】:

    • 没有。您不能按director_id分组,然后在您的选择字段中任意包含event_id。
    猜你喜欢
    • 2015-02-05
    • 2014-03-10
    • 1970-01-01
    • 2013-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-04
    • 2019-11-28
    相关资源
    最近更新 更多