简体   繁体   English

分组多个日期范围进行查询

[英]Query with grouping my multiple date ranges

I need to query data with count and sum by multiple date ranges and I am looking for a faster query than what I am doing now. 我需要使用多个日期范围的计数和总和来查询数据,并且我正在寻找比现在更快的查询。
I have a transaction table with a date and amount. 我有一个带有日期和金额的交易表。 I need to present a table with a count of transactions and total amount by date ranges of today, yesterday, this week, last week, this month, last month. 我需要提供一个表格,其中包含今天,昨天,本周,上周,本月和上个月的交易计数和总额(按日期范围)。 Currently I am doing sub queries, is there a better way? 目前,我正在执行子查询,有没有更好的方法?

select  
(select count(date) from transactions where date between ({{today}})) as count_today,  
(select sum(amount) from transactions where date between ({{today}})) as amount_today,  
(select count(date) from transactions where date between ({{yesterday}})) as count_yesterday,  
(select sum(amount) from transactions where date between ({{yesterday}})) as amount_yesterday,  
(select count(date) from transactions where date between ({{thisweek}})) as count_thisweek,  
(select sum(amount) from transactions where date between ({{thisweek}})) as amount_thisweek,  
etc...

Is there a better way? 有没有更好的办法?

although you have a marked solution, I have another that will probably simplify your query even further using MySQL variables so you don't have to mis-type / calculate dates and such... 尽管您有一个明显的解决方案,但我有另一个可能会使用MySQL变量进一步简化您的查询,因此您不必输错日期/计算日期等等。

Instead of declaring variables up front, you can do them inline as a select statement, then use them as if they were columns in another table. 不必预先声明变量,您可以将它们作为select语句内联地进行,然后将它们当作其他表中的列使用。 Since it is created as a single row, there is no Cartesian result. 由于它是作为单行创建的,因此没有笛卡尔结果。 First the query, then I'll describe the computations on it. 首先查询,然后我将描述它的计算。

select
      sum( if( t.date >= @today AND t.date < @tomorrow, 1, 0 )) as TodayCnt,
      sum( if( t.date >= @today AND t.date < @tomorrow, amount, 0 )) as TodayAmt,
      sum( if( t.date >= @yesterday AND t.date < @today, 1, 0 )) as YesterdayCnt,
      sum( if( t.date >= @yesterday AND t.date < @today, amount, 0 )) as YesterdayAmt,
      sum( if( t.date >= @FirstOfWeek AND t.date < @EndOfWeek, 1, 0 )) as WeekCnt,
      sum( if( t.date >= @FirstOfWeek AND t.date < @EndOfWeek, amount, 0 )) as WeekAmt
   from
      transations t,
   ( select @today := curdate(),
               @yesterday := date_add( @today, interval -1 day ),
               @tomorrow := date_add( @today, interval 1 day ),
               @FirstOfWeek := date_add( @today, interval +1 - dayofweek( @today) day ),
               @EndOfWeek := date_add( @FirstOfWeek, interval 7 day ),
               @minDate := least( @yesterday, @FirstOfWeek ) ) sqlvars
   where
          t.date >= @minDate
      AND t.date < @EndOfWeek

Now, the dates. 现在,日期。 Since the @variables are prepared in sequence, you can think of it as an inline program to set the variables. 由于@variables是按顺序准备的,因此您可以将其视为设置变量的内联程序。 Since they are a pre-query, they are done first and available for the duration of the rest of the query as previously stated. 由于它们是预查询,因此它们是首先完成的,并且在其余查询期间都可用,如前所述。 So to start, I am working with whatever "curdate()" is which gets the date portion only without respect to time. 因此,首先,我将使用任何“ curdate()”来获取日期部分,而不考虑时间。 From that, subtract 1 day (add -1) to get the beginning of yesterday. 从中减去1天(加-1)得到昨天的开始。 Add 1 day to get Tomorrow. 加1天即可获得明天。 Then, the first of the week is whatever the current date is +1 - the actual day of week (you will see shortly). 然后,每周的第一天就是当前日期+1-实际的星期几(很快就会看到)。 Add 7 days from the first of the week to get the end of the week. 从一周的第一天开始增加7天,直到一周结束。 Finally, get whichever date is the LEAST between a yesterday (which COULD exist at the end of the prior week), OR the beginning of the week. 最后,获取以昨天(可能在前一周的末尾存在)或一周的开始之间的最小日期为准。

Now look at today for example... Feb 23rd.
Sun  Mon  Tue  Wed  Thu  Fri  Sat  Sun
21   22   23   24   25   26   27   28

Today = 23
Yesterday = 22
Tomorrow = 24
First of week = 23 + 1 = 24 - 3rd day of week = 21st
End of Week = 21st + 7 days = 28th.

Why am I doing a cutoff of the dates stripping times? 为什么我要删除日期剥离时间? To simplify the SUM() condition for >= AND <. 为了简化> = AND <的SUM()条件。 If I stated some date = today, what if your transactions were time-stamped. 如果我说某日期=今天,如果您的交易带有时间戳,该怎么办。 Then you would have to extract the date portion only to qualify. 然后,您仅需提取日期部分才有资格。 By this approach, I can say that "Today" count and amount is any date >= Feb 23 at 12am midnight AND < Feb 24th 12 am midnight. 通过这种方法,我可以说“今天”计数和金额是> = 2月23日午夜12点和<2月24日午夜12点的任何日期。 This is all time inclusive Feb 23rd up to 11:59:59pm hence LESS than Feb 24th (tomorrow). 这是2月23日至11:59:59 pm之间的所有时间,因此比2月24日(明天)少。

Similar consideration for yesterday is all inclusive UP TO but not including whatever "today" is. 昨天的类似考虑是包容性的,直到但不包括“今天”。 Similarly for the week range. 每周范围也是如此。

Finally the WHERE clause is looking for the earliest date as the range so it does not have to run through the entire database of transactions to the end. 最后,WHERE子句正在寻找最早的日期作为范围,因此它不必遍历整个事务数据库一直到最后。

Lastly, if you ever wanted the counts and totals for a prior week / period, whatever, you could just extrapolate and change 最后,如果您希望获得前一周/期间的计数和总计,则可以推断和更改

 @today := '2015-01-24'

and the computations will be AS IF the query was run ON THAT DATE. 如果查询在该日期运行,则计算将为AS。

Similar if you cared to alter such as for a month, you could compute the first of the month to the first of a following month for MONTHLY totals. 与之类似,如果您希望进行一个月的更改,则可以计算MONTHLY总计的月份的第一个月到下个月的第一个月。

Hope you enjoy this flexible solution to you. 希望您喜欢这个灵活的解决方案。

Yes, you can use aggregate functions on conditional expressions, like so: 是的,您可以在条件表达式上使用聚合函数,如下所示:

SELECT SUM(IF(date between ({{today}})), 1, 0) AS count_today
, SUM(IF(date between ({{today}})), amount, 0) AS amount_today
, ...

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

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