【问题标题】:SQL query - selecting first and last record of each day in a monthSQL查询 - 选择一个月中每一天的第一条和最后一条记录
【发布时间】:2020-07-29 09:15:32
【问题描述】:

Mysql 5.7.30:我有两个表:

项目:projectID、timeNeeded

注册:registrationID、projectID、startDateTime

我想要实现的目标: 对于当前月份(基于 startDateTime),我想通过选择当月每一天的第一条和最后一条记录来了​​解“timeNeeded”。 如果一天只有 1 条记录,还是应该算两次。

例如,如果一天有 4 个注册,我只想包括这 4 个中的第一个和最后一个。

我有点不确定如何从这里开始,我想有多种方法可以实现这一点。速度不重要,只要比我的第一个想法好;使用多个查询和 PHP 来处理它。

样本数据和想要的结果:

Project table:      
project1    50  
project2    20  
project3    30  
        
Registation table:      (hour:minute hidden)
reg1    project1    2020-07-01
reg2    project1    2020-07-01
reg3    project3    2020-07-02
reg4    project3    2020-07-02
reg5    project2    2020-07-02
reg6    project2    2020-07-02
reg7    project3    2020-07-03
reg8    project1    2020-07-04
reg9    project3    2020-07-05
reg10   project2    2020-07-05
        
        
Result (projects.timeNeeded for first and last of each day):        
reg1    50  
reg2    50  
reg3    30  
reg6    20  
reg7    30  
reg7    30  
reg8    50  
reg8    50  
reg9    30  
reg10   20  

【问题讨论】:

  • 请提供样本数据和期望的结果。
  • @GordonLinoff 我已经添加了示例。
  • 你的MySql是什么版本的?
  • @forpas Mysql 版本 5.7.30
  • timeNeeded for 'reg6' 在结果中应该是 20。

标签: mysql sql


【解决方案1】:

这个要求的棘手部分是只有 1 个注册的日期的双行,这就是我使用 UNION ALL 的原因。
需要聚合获取每天的第一个和最后一个startDateTime,最后加入:

select r.registrationID, p.timeNeeded
from (
  select registrationID, projectID, startDateTime 
  from Registration
  union all
  select max(registrationID), max(projectID), max(startDateTime) 
  from Registration
  group by date(startDateTime)
  having count(*) = 1
) r
inner join ( 
  select date(startDateTime) date, 
         min(startDateTime) min_date,
         max(startDateTime) max_date
  from Registration
  where date_format(startDateTime, "%Y-%m") = date_format(current_date, "%Y-%m")
  group by date
) t on r.startDateTime in (t.min_date, t.max_date) 
inner join Project p on p.projectID = r.projectID
order by r.startDateTime

请参阅demo。
结果:

| registrationID | timeNeeded |
| -------------- | ---------- |
| reg1           | 50         |
| reg2           | 50         |
| reg3           | 30         |
| reg6           | 20         |
| reg7           | 30         |
| reg7           | 30         |
| reg8           | 50         |
| reg8           | 50         |
| reg9           | 30         |
| reg10          | 20         |

【讨论】:

  • 非常感谢,这比我预期的要复杂!我确定您的查询是正确的,但是在我在实际项目中实施它之后,在只有两个注册的情况下,我得到了同一日期的 4 条记录。 (在本例中,reg9 和 reg10 将出现 4 次)。我有点不确定在 Union all 之后 select 的目的?
  • 你有重复的 startDateTimes 吗?
  • 不应有重复的 startDatetimes。我想它可能会为每个 registrations.projectID 选择 2?
  • 你能在小提琴中重现这个问题吗?
【解决方案2】:

我会使用union all 来解决这个问题,每天第一条记录一次,最后一次记录:

select r.*, p.timeneeded
from Registration r join
     Project p
     on r.projectid = p.projectid
where extract(year_month from r.startDateTime) = extract(year_month from now()) and
      r.registrationID = (select r2.registrationID
                          from Registration r2
                          where date(r2.startDateTime) = date(r.startDatetime)
                          order by r2.registrationID 
                          limit 1
                         )
union all
select r.*, p.timeneeded
from Registration r join
     Project p
     on r.projectid = p.projectid
where extract(year_month from r.startDateTime) = extract(year_month from now()) and
      r.registrationID = (select r2.registrationID
                          from Registration r2
                          where date(r2.startDateTime) = date(r.startDatetime)
                          order by r2.registrationID desc
                          limit 1
                         )
order by registrationID;

注意:您的日期都是一样的。该列的名称表明可能存在时间分量,但您的问题没有。因此,这使用注册 id 来确定每天的第一个和最后一个。

Here 是一个 dbfiddle。

【讨论】:

  • 我写道 hh:mm 是隐藏的,但我想我应该更清楚地说明:是的,它需要使用 startDatetime 字段来确定哪一天是第一天/最后一天。我试图用 startDatetime 替换 order by,但这一天产生了 4 条记录...
【解决方案3】:

由于您的表格缺少标题,所以我写的有点抽象。

select * from registration sort by timestamp_col desc limit 1;

和

select * from registration sort by timestamp_col limit 1;

这两个查询应该为您提供第一次和最后一次注册。如果您只有一个注册,那么两个查询都会返回相同的记录。这将满足您的需求。

我忽略了与 Project 表的连接,假设您知道如何连接两个表。

【讨论】:

  • 谢谢,但这与我自己做的差不多。我想知道的是如何在这个月的所有日子里做到这一点,并结合结果。是联合全部还是选择子查询来执行此操作?
  • 当子查询的结果在主查询中使用时,您通常会使用子查询。在您的情况下,联合很好,因为您不依赖于主查询的子查询结果。 .
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-30
相关资源
最近更新 更多