【问题标题】:MySQL: Calculate Remaining Selling Days in MonthMySQL:计算每月剩余的销售天数
【发布时间】:2016-03-25 22:35:24
【问题描述】:

我有一个每日收入目标计算,说明我每天需要赚取多少收入才能实现每月收入目标:

'Revenue_Goal' / 'Selling_Days'

(注意:“Selling_Days”已经在数据集中。)

我想要完成的是根据过去的天数调整每日目标。我通过以下方式部分完成了这项工作:

('Revenue_Goal' - SUM('Revenue')) / DATEDIFF(MAX('Date'),NOW())

但是,我无法弄清楚的部分只是在调整后的公式中计算销售天数。我需要使用上面的公式(或类似的公式)只计算天数:

  • 周一至周五 = 1 个销售日
  • 星期六 = 0.5 个销售日
  • 星期日 = 0

所以,如果今天是 3/25/16,我的 DATEDIFF 计算将返回 6,但我的目标是让它返回 4.5。

感谢任何帮助!

【问题讨论】:

  • 你的表结构是什么?你得到日期的最大值,那一列是什么?看来您的数据库中已经有了一些东西,了解您已经拥有的东西很重要。我猜你也会遇到银行假期的问题......
  • 'Date' 是获得收入的日期。 MAX('Date') 返回 2016 年 3 月的 31。
  • 我不太明白这与存储在表中的数据有什么关系。

标签: mysql sql datediff date-difference


【解决方案1】:

这是 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;

【讨论】:

    【解决方案2】:

    把它写成一个存储函数是有意义的。我能想到三种方法,每种方法都比前一种方法有所改进(尽管方法 2 可能已经足够好了。)

    方法一:从第一个日期开始,直到第二个日期递增。对于每个日期,调用 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_startdow_end

    如果dow_start &lt; 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 &gt; dow_end,那么那些讨厌的剩余日子就会结束。我相信在这种情况下你可以交换dow_startdow_end(让我们回到前一个案例)。像以前一样计算它,然后从 5.5 中减去答案并加 1。(说明:计算一周中不在 day_startday_end 之间的天数,然后从一周的总数中减去它们。)

    就像我说的那样,我没有编写或测试那个,所以它可能不完全正确。

    如何处理银行假日:如果您将它们放在一个表格中,您可以简单地COUNT 两个日期之间的行数。从你的答案中减去。简单的! (假设银行假期从不在周末。)有些网站列出了各个国家/地区的银行假期,甚至有一个网站会为您生成一个遥远的未来日期列表,从而可以轻松构建假期表。

    【讨论】:

    • 你能详细说明方法1吗?我真的在寻找这样快速而肮脏的东西,因为只有我(作为 MySQL 初学者用户)将使用这些计算和数据集。
    • 当然,很高兴为您提供帮助。我为您编写了前两个方法作为存储函数。
    猜你喜欢
    • 1970-01-01
    • 2014-06-29
    • 2014-06-11
    • 2016-03-26
    • 2021-02-18
    • 2013-06-26
    • 1970-01-01
    • 2010-11-13
    相关资源
    最近更新 更多