我有一个每日收入目标计算,说明我每天需要多少收入来实现每月收入目标:
'Revenue_Goal' / 'Selling_Days'
(注意:' Selling_Days'已经是数据集中的一个整体。)
我想要完成的是根据已经过了多少天来获得调整后的每日目标。我部分完成了这个:
('Revenue_Goal' - SUM('Revenue')) / DATEDIFF(MAX('Date'),NOW())
然而,我无法弄清楚的部分只是计算调整公式中的卖出天数。我需要使用上面的公式(或类似的东西),只计算几天:
所以,如果今天是3/25/16,我的DATEDIFF计算将返回6,但我的目标是让它返回4.5。
感谢任何帮助!
答案 0 :(得分:2)
这是计算此方法的n种方法之一
SELECT
SUM(
ELT( DAYOFWEEK(CONCAT( DATE_FORMAT(now(), '%Y-%m-'),nr)),
'0','1','1','1','1','1','0.5') ) calc_days
FROM (
SELECT d2.a*10+d1.a AS nr FROM (
SELECT 0 a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4
UNION ALL SELECT
5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS d1
CROSS JOIN (
SELECT 0 a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 ) AS d2
) AS x
WHERE nr BETWEEN DAY(NOW()) AND DAY(LAST_DAY(NOW()))
ORDER BY nr;
答案 1 :(得分:1)
将此作为存储函数编写是有意义的。我可以想到三种方法,每种方法都有所改进(虽然方法2可能已经足够了。)
方法1:从第一个日期开始,递增到第二个日期。对于每个日期,请调用DAYOFWEEK()。如果星期天然后加0,如果星期六加0.5,否则加1。
DROP FUNCTION IF EXISTS `count_days_goal`;
DELIMITER $$
CREATE FUNCTION `count_days_goal`(start_date DATE, end_date DATE) RETURNS FLOAT
DETERMINISTIC
BEGIN
DECLARE sell_days FLOAT;
DECLARE dow INT;
SET sell_days = 0.0;
WHILE start_date <= end_date DO
SET dow = DAYOFWEEK(start_date);
IF (dow > 1) THEN
IF (dow = 7) THEN SET sell_days = sell_days + 0.5;
ELSE SET sell_days = sell_days + 1.0;
END IF;
END IF;
SET start_date = start_date + INTERVAL 1 DAY;
END WHILE;
RETURN (sell_days);
END$$
DELIMITER ;
一些测试(注意我的实施包括计算天数的最后一天):
select count_days_goal(DATE('2016-03-21'), DATE('2016-03-27'));
select count_days_goal(DATE('2016-03-01'), DATE('2016-03-27'));
这很简单,但效率低下。这些日子越来越远,需要更长的时间。请注意,一个电话仍然会比一个眨眼更快,但对大多数开发人员来说,它会略微冒犯。幸运的是,我们可以做得更好。
方法2:每个完整的一周是5.5个销售日。因此,将日期之间的天数除以7,忽略剩余的片刻,将倍数除以5.5。
示例:32天是(4周+4天),这是22个销售日加上4个剩余时间。
剩下的就是事情变得棘手的地方。这4天可能包括星期六,或者他们可能不会。最简单的解决方案是在过去几天使用方法1。它永远不会超过6天,所以它很快。
所以现在代码看起来像这样:
DROP FUNCTION IF EXISTS `count_days_goal`;
DELIMITER $$
CREATE FUNCTION `count_days_goal`(start_date DATE, end_date DATE) RETURNS FLOAT
DETERMINISTIC
BEGIN
DECLARE sell_days FLOAT;
DECLARE dow INT;
DECLARE whole_weeks INT;
SET whole_weeks = FLOOR(DATEDIFF(end_date, start_date)/7);
SET start_date = start_date + (7 * whole_weeks);
SET sell_days = whole_weeks * 5.5;
WHILE start_date <= end_date DO
SET dow = DAYOFWEEK(start_date);
IF (dow > 1) THEN
IF (dow = 7) THEN SET sell_days = sell_days + 0.5;
ELSE SET sell_days = sell_days + 1.0;
END IF;
END IF;
SET start_date = start_date + INTERVAL 1 DAY;
END WHILE;
RETURN (sell_days);
END$$
DELIMITER ;
方法3:您也可以使用方法2,但完全摆脱循环。要了解它是如何完成的,在您面前制作日历会很有帮助。 (我没有打算实施这个;方法2非常好。)
不是循环,而是在第一个和最后一个日期调用DAYOFWEEK
。我们称之为dow_start
和dow_end
。
如果dow_start < dow_end
然后那些讨厌的剩余日子都在一周之内,那么他们就不会在周六回到周日。所以你需要做的就是:
SET answer = DATEDIFF(dow_end, dow_start) + 1;
IF dow_start = 1 (i.e. Sunday) THEN subtract 1 from answer
IF dow_end is 7 (i.e. Saturday) THEN subtract 0.5 from answer
如果dow_start > dow_end
那么那些讨厌的剩余日子就会好转。我相信在这种情况下你可以交换dow_start
和dow_end
(让我们回到上一个案例)。像以前一样计算它,但是然后从5.5中减去答案并添加1.(说明:计算不在{{1}}和day_start
之间的星期几,然后从一周中减去它们总)
就像我说我没有写或测试那个,所以它可能不完全正确。
如何处理银行假期:如果您将它们放在一个表格中,您只需day_end
两个日期之间的行数。从你的答案中减去那个。简单! (假设银行假期永远不会在周末。)有些网站列出了各个国家的银行假期,甚至可以为将来生成日期列表的网站,这样可以轻松构建假期表。