什么是Oracle的NEXT_DAY函数的MySQL替代品?

时间:2017-05-09 12:50:43

标签: mysql sql database oracle

NEXT_DAY("01-SEP-95","FRIDAY")返回下周五的日期,但在MySQL中似乎没有出现此函数。有什么替代方案?

5 个答案:

答案 0 :(得分:0)

在MySQL中,您可以创建用户定义的函数

DELIMITER //
 
  CREATE FUNCTION next_day(start_date DATETIME, weekday CHAR(20))
    RETURNS DATETIME
  BEGIN
    DECLARE start DATETIME;
    DECLARE i INT;
 
    // Select the next date
    SET start = ADDDATE(start_date, 1);
    SET i = 1;
 
    days: LOOP
          -- Compare the day names
        IF SUBSTR(DAYNAME(start), 1, 3) = SUBSTR(weekday, 1, 3) THEN    
       LEAVE days;
        END IF;
 
        // Select the next date
        SET start = ADDDATE(start, 1);
        SET i = i + 1;
 
        -- Not valid weekday specified
        IF i > 7 THEN
       SET start = NULL;
       LEAVE days;
    END IF;
 
     END LOOP days;
 
     RETURN start;
  END;
  //
 
   DELIMITER ;

并将其命名为

SELECT NEXT_DAY("1995-09-01","FRIDAY")

来源:http://www.sqlines.com/mysql/how-to/next_day

答案 1 :(得分:0)

以下是对不同问题的回答:

查找当周星期五的日期: -

SELECT STR_TO_DATE(CONCAT('2017',(SELECT DATE_FORMAT(CURDATE(),'%U')),' Friday'),'%Y %U %W') x;
+------------+
| x          |
+------------+
| 2017-05-12 |
+------------+

上述内容尚未经过验证,但是“仅仅是作为思考的食物”提供。

答案 2 :(得分:0)

SQL Fiddle

MySQL 5.6架构设置

CREATE TABLE your_table ( value DATE );

INSERT INTO your_table ( value )
  SELECT DATE '2017-05-08' FROM DUAL UNION ALL
  SELECT DATE '2017-05-09' FROM DUAL UNION ALL
  SELECT DATE '2017-05-10' FROM DUAL UNION ALL
  SELECT DATE '2017-05-11' FROM DUAL UNION ALL
  SELECT DATE '2017-05-12' FROM DUAL UNION ALL
  SELECT DATE '2017-05-13' FROM DUAL UNION ALL
  SELECT DATE '2017-05-14' FROM DUAL;

查询1

SELECT value,
       ADDDATE(
        value,
         6 - DAYOFWEEK( value )
           + CASE WHEN DAYOFWEEK( value ) < 6 THEN 0 ELSE 7 END
       ) AS next_friday
FROM   your_table

<强> Results

|                 value |           next_friday |
|-----------------------|-----------------------|
| May, 08 2017 00:00:00 | May, 12 2017 00:00:00 |
| May, 09 2017 00:00:00 | May, 12 2017 00:00:00 |
| May, 10 2017 00:00:00 | May, 12 2017 00:00:00 |
| May, 11 2017 00:00:00 | May, 12 2017 00:00:00 |
| May, 12 2017 00:00:00 | May, 19 2017 00:00:00 |
| May, 13 2017 00:00:00 | May, 19 2017 00:00:00 |
| May, 14 2017 00:00:00 | May, 19 2017 00:00:00 |

答案 3 :(得分:0)

简短版本:

利用DAYOFWEEK(),您可以利用数字值创建一个封闭的公式,该公式告诉您要添加多少天。然后,您可以利用DATE_ADD帮助您更改日期。可能有一种更简洁的方法,但是您应该可以利用此功能。

以下是一个Excel公式,可用于验证所有49个用例:=MOD(MOD(Next-Input, 7)+7,7)

一些如何将excel计算转换为SQL的示例:

SELECT (((1-DAYOFWEEK('2018-08-15')) % 7)+7) % 7 AS DaysToAddToGetNextSundayFromWednesday 
FROM dual; -- 4

SELECT DATE_ADD('2018-08-15', INTERVAL (((1-DAYOFWEEK('2018-08-15')) % 7)+7) % 7 DAY) AS NextSundayFromDate 
FROM dual; -- 2018-08-19   

如果您打算经常使用以上内容,则可能需要创建一个函数或存储过程。

长版:

这些年来,我多次遇到这个问题。第一次,我为所有49个案例创建了一个大型案例声明。我发现这使查询变得超大且不干净。我想要一个更清洁,更简单的解决方案,例如封闭式公式。以下是我为确认上述公式所做的计算的详细信息。我使用MySQL 5.7进行了测试,如果您使用的是MySQL 8.5,则该函数似乎是内置的(参考:http://www.sqlines.com/mysql/how-to/next_day)。

注意:Excel不会像MySQL那样返回模数的负结果。这就是为什么我们加7并做另一个模数的原因。

DAYOFWEEK()         
Sun     1       
Mon     2       
Tues    3       
Wed     4       
Thur    5       
Fri     6       
Sat     7       

Input   Next    Expected Days to Add    Formula Result
1       1       0                       0
1       2       1                       1
1       3       2                       2
1       4       3                       3
1       5       4                       4
1       6       5                       5
1       7       6                       6
2       1       6                       6
2       2       0                       0
2       3       1                       1
2       4       2                       2
2       5       3                       3
2       6       4                       4
2       7       5                       5
3       1       5                       5
3       2       6                       6
3       3       0                       0
3       4       1                       1
3       5       2                       2
3       6       3                       3
3       7       4                       4
4       1       4                       4
4       2       5                       5
4       3       6                       6
4       4       0                       0
4       5       1                       1
4       6       2                       2
4       7       3                       3
5       1       3                       3
5       2       4                       4
5       3       5                       5
5       4       6                       6
5       5       0                       0
5       6       1                       1
5       7       2                       2
6       1       2                       2
6       2       3                       3
6       3       4                       4
6       4       5                       5
6       5       6                       6
6       6       0                       0
6       7       1                       1
7       1       1                       1
7       2       2                       2
7       3       3                       3
7       4       4                       4
7       5       5                       5
7       6       6                       6
7       7       0                       0

答案 4 :(得分:0)

我要用另一种方法把帽子戴上戒指:

编辑: 我有点迟来地意识到,所讨论的Oracle函数将字符串作为第二个参数,因此这并不完全符合要求。但是,MySQL已经将0-6定义为星期一-星期日,反正我在道德上反对将字符串用作此类事情的参数。字符串可以来自用户输入,也可以来自更高级别代码中的数字和字符串值之间的另一个映射。为什么不传递整数? :)

CREATE FUNCTION `fnDayOfWeekGetNext`(
        p_date DATE,
        p_weekday TINYINT(3)
        ) RETURNS date
BEGIN

        RETURN DATE_ADD(p_date, INTERVAL p_weekday - WEEKDAY(p_date) + (ROUND(WEEKDAY(p_date) / (p_weekday + WEEKDAY(p_date) + 1)) * 7) DAY);

END

要细分确定INTERVAL值的部分:

方程式的第一部分只是获得指定的工作日与指定日期的工作日之间的偏移量:

p_weekday - WEEKDAY(p_date)

如果p_weekday大于WEEKDAY(p_date),它将返回一个正数,反之亦然。如果它们相同,将返回零。

ROUND()段用于确定相对于指定的日期(p_weekday)在当前一周中是否已发生请求的星期几(p_date)。因此,举例来说...

ROUND(WEEKDAY('2019-01-25') / (6 + WEEKDAY('2019-01-25') + 1))

..返回0,表示本周未发生星期日(6),因为2019-01-25是星期五。同样...

ROUND(WEEKDAY('2019-01-25') / (2 + WEEKDAY('2019-01-25') + 1))

...返回1,因为星期三(2)已经过去。请注意,如果0p_weekday的工作日相同,它将返回p_date

然后将这个值(10)乘以常数7(一周中的天数)。

因此,如果p_weekday在本周已经发生,它将在偏移量p_weekday - WEEKDAY(p_date)上加上7,因为该偏移量为负数,我们希望将来有一个日期。

如果p_weekday在当前一周尚未发生,那么我们可以将偏移量添加到当前日期,因为偏移量将为正数。因此,ROUND(...) * 7部分等于零,本质上被忽略。

我对这种方法的期望是通过数学模拟IF()条件。这将同样有效:

RETURN DATE_ADD(p_date, INTERVAL p_weekday - WEEKDAY(p_date) + IF(p_weekday - WEEKDAY(p_date) < 0, 7, 0) DAY);

出于客观性的考虑,在运行1M迭代中,每个功能的几次基于IF的版本比基于ROUND的版本平均快4.2%。

相关问题