总结每周收入,包括空记录

时间:2014-12-26 21:45:01

标签: mysql sql subquery

我正在尝试总结一个时间管理系统(PHP / MySQL)的每周收入,但这个SQL查询遇到了很多麻烦。基本上,我需要返回过去8周的收入总和,包括没有收入的几周记录,但是当我在WHERE子句中添加任何内容以将其缩小到特定类型的任务时,我无法使其工作。此查询涉及三个表:

tbltask存储有关任务的信息,包括记录任务的日期,用户执行的任务,应该花费多少时间,以及任务是否可以计费(有些不可计费,应从收入中排除计算)...

task_id   task_name        time_est   billable   date_logged   user_id
----------------------------------------------------------------------
223       some task        120        0          2014-12-19    1
224       a billable task  45         1          2014-12-19    2
225       also billable    90         1          2014-12-20    1

tbluser存储用户信息,因此我需要加入它以获得每小时的付费...

user_id   payrate   
--------------------
1         50
2         75          

日历只是一个包含各种日期的表格,因此我可以加入它并为没有记录的日期生成结果。

datefield 
--------------------
2013-01-01
2013-01-02
2013-01-03
[...]
2025-12-31

以下是我到目前为止的情况,在相关日期之前的8周内,按周(从星期一开始)总计每个人的收入。这似乎按预期工作,但计算所有任务而不仅仅是可计费任务。如果这几周没有记录任何任务,我会将返回的记录返回0作为total_earned,这很重要,因为即使没有记录时间,我也需要过去8周的记录。

SELECT FROM_DAYS(TO_DAYS(datefield) - MOD(TO_DAYS(datefield)-2, 7)) AS first_day, 
SUM( IFNULL( time_est /60 * payrate, 0 ) ) AS total_earned
FROM calendar
LEFT JOIN tbltask ON tbltask.date_logged = calendar.datefield
LEFT JOIN tbluser ON tbltask.user_id = tbluser .user_id
WHERE datefield <=  '2014-12-26'
GROUP BY FROM_DAYS(TO_DAYS(datefield) - MOD(TO_DAYS(datefield)-2, 7)) 
ORDER BY FROM_DAYS(TO_DAYS(datefield) - MOD(TO_DAYS(datefield)-2, 7)) DESC 
LIMIT 8

但是,我只需要为可计费任务(可计费= 1)的收入加起来。一旦我添加了这个,我就不再需要几周没有日志,所以返回的记录中有几周缺失。

SELECT FROM_DAYS(TO_DAYS(datefield) - MOD(TO_DAYS(datefield)-2, 7)) AS first_day, 
SUM( IFNULL( time_est /60 * payrate, 0 ) ) AS total_earned
FROM calendar
LEFT JOIN tbltask ON tbltask.date_logged = calendar.datefield
LEFT JOIN tbluser ON tbltask.user_id = tbluser .user_id
WHERE datefield <=  '2014-12-26' AND billable = 1 
GROUP BY FROM_DAYS(TO_DAYS(datefield) - MOD(TO_DAYS(datefield)-2, 7)) 
ORDER BY FROM_DAYS(TO_DAYS(datefield) - MOD(TO_DAYS(datefield)-2, 7)) DESC 
LIMIT 8

我理解为什么这个结果有意义(因为在那几周内没有完成任务= 1个任务,因此没有返回记录),但我不能为我的生活弄清楚如何重写查询以获取我想要的是。我还想编写查询来获取特定用户的收入而不是所有用户的总收入(user_id = 1),但当然这给我带来了同样的问题。我想我可能需要使用子查询?

有人能指出我正确的方向吗?


解决方案:

如果其他人最终在类似的东西上挣扎,我使用了Terary的IF()建议来在SUM计算中移动billable = 1和user_id = 1逻辑,而不是将它放在WHERE子句中。这解决了我的问题,因为它返回所有空周,总收入为0而不是没有记录的那些周。我确信还有其他方法可以做到这一点,但这确实有效。这是结果查询:

SELECT FROM_DAYS(TO_DAYS(datefield) - MOD(TO_DAYS(datefield)-2, 7)) AS first_day, 
SUM(IF(billable=1 AND user_id=1, time_est /60 * payrate, 0)) AS total_earned
FROM calendar
LEFT JOIN tbltask ON tbltask.date_logged = calendar.datefield
LEFT JOIN tbluser ON tbltask.user_id = tbluser .user_id
WHERE datefield <=  '2014-12-26' AND billable = 1 
GROUP BY FROM_DAYS(TO_DAYS(datefield) - MOD(TO_DAYS(datefield)-2, 7)) 
ORDER BY FROM_DAYS(TO_DAYS(datefield) - MOD(TO_DAYS(datefield)-2, 7)) DESC 
LIMIT 8

1 个答案:

答案 0 :(得分:0)

请原谅我没有创建运行查询的表。所以我无法调试你拥有的东西。

然而, 一个) 您可以创建tbltasks.wkyear,它将消除您对其中一个表的需求。 这可以通过触发器插入存储(可能是默认值?)。或者只是写下这件事。

B)嗯,我想我不确定你的目标? 我想我现在有一半的线索。

我认为SELECT IF(billiable = 1,50,0)是你的朋友。 http://dev.mysql.com/doc/refman/5.0/en/control-flow-functions.html

http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_yearweek  SELECT YEARWEEK('1987-01-01');          - &GT; 198653