简体   繁体   English

SQL 查询-选择一个月中每一天的第一条和最后一条记录

[英]SQL query - selecting first and last record of each day in a month

Mysql 5.7.30: I have two tables: Mysql 5.7.30:我有两个表:

projects : projectID, timeNeeded项目projectID,timeNeeded

registrations : registrationID, projectID, startDateTime注册registrationID、projectID、startDateTime

What I want to achieve: For the current month (based on startDateTime) I want to know "timeNeeded" by selecting the first and last record for each day in the month.我想要实现的目标:对于当前月份(基于 startDateTime),我想通过选择该月每一天的第一条和最后一条记录来了解“timeNeeded”。 If there's only 1 record for a day, it should still count it twice .如果一天只有1条记录,还是应该算两次

Eg if there's 4 registrations on one day, I only want to include the first and last of those 4.例如,如果一天有 4 个注册,我只想包括这 4 个中的第一个和最后一个。

I'm a little unsure how to get started here, i guess there's multiple ways to achieve this.我有点不确定如何从这里开始,我想有多种方法可以实现这一目标。 Speed isn't important, as long as it's better than my first idea;速度并不重要,只要它比我的第一个想法更好; using multiple queries and PHP to process it.使用多个查询和 PHP 来处理它。

Sample data and wanted result:示例数据和想要的结果:

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  

The tricky part of this requirement is the double rows for the dates that have only 1 registration, this is why I use UNION ALL.此要求的棘手部分是只有 1 个注册的日期的双行,这就是我使用 UNION ALL 的原因。
Aggregation is needed to get the first and last startDateTime of each day and finally joins:需要聚合得到每天的第一个和最后一个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

See the demo .请参阅演示
Results:结果:

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

I would approach this by using union all , once for the first record on each day and once for the last:我会通过使用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;

Note: Your dates are all the same.注意:你们的日期都是一样的。 The name of the column suggests that there might be a time component, but your question doesn't have it.该列的名称表明可能有时间成分,但您的问题没有。 So this uses the registration id to determine the first and last on each day.所以这使用注册 id 来确定每天的第一个和最后一个。

Here is a db<>fiddle. 是一个 db<>fiddle。

Since your table is missing the headers, am writing a bit abstract.由于您的表格缺少标题,因此我写得有点抽象。

select * from registration sort by timestamp_col desc limit 1; select * 来自注册,按 timestamp_col desc 限制排序 1;

and

select * from registration sort by timestamp_col limit 1; select * 来自注册,按 timestamp_col 限制排序 1;

These two queries should give you the first and last registrations.这两个查询应该为您提供第一个和最后一个注册。 In case you have only one registration, then both queries will return you the same record.如果您只有一个注册,那么这两个查询将返回相同的记录。 This will meet your needs.这将满足您的需求。

I have ignored the join with the Project table, assuming you know how to join two tables.我忽略了与 Project 表的连接,假设您知道如何连接两个表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM