从存储函数

时间:2017-02-09 18:08:38

标签: mysql sql sql-function

我正在尝试编写一个存储函数,该函数采用正确的ISO格式(yyyy-mm-dd)字符串,并从中减去一定数量的工作日。基于this question here我已经尝试了接受的答案以及一些答案,这些答案的方式不同,但是,他们都只是在说如何编写纯粹的SQL,而且没有一个函数的例子。

我现在拥有的是:

delimiter //
CREATE DEFINER=`root`@`localhost` FUNCTION `WEEKDATE_SUB` (days TINYINT, date_val VARCHAR(16))
RETURNS DATE DETERMINISTIC
BEGIN
    DECLARE SUBVAL INT;
    DECLARE dow INT;
    CASE
            WHEN dow=1 THEN SET SUBVAL = (days +(FLOOR((days-0.5)/5)+1)*2 - 1);
            WHEN dow=2 THEN SET SUBVAL = (days +(FLOOR((days-0.5)/5)+1)*2);
            WHEN dow=3 THEN SET SUBVAL = (days-1 +(FLOOR(((days-1)-0.5)/5)+1)*2 + 1);
            WHEN dow=4 THEN SET SUBVAL = (days-2 +(FLOOR(((days-2)-0.5)/5)+1)*2 + 2);
            WHEN dow=5 THEN SET SUBVAL = (days-3 +(FLOOR(((days-3)-0.5)/5)+1)*2 + 3);
            WHEN dow=6 THEN SET SUBVAL = (days-4 +(FLOOR(((days-4)-0.5)/5)+1)*2 + 4);
            WHEN dow=7 THEN SET SUBVAL = (days-5 +(FLOOR(((days-5)-0.5)/5)+1)*2 + 5);
    END CASE
    RETURN DATE_SUB(date_val, INTERVAL SUBVAL DAY);
END;//

当我尝试添加它时,我得到一个模糊的错误(因为mysql喜欢提供):     您的SQL语法有错误;检查与您的MariaDB服务器版本对应的手册,以便在< RETURN DATE_SUB(date_val,INTERVAL SUBVAL DAY)附近使用正确的语法;     END'在第14行

我已经尝试了几种关于返回的变体,包括尝试为Date sub定义变量并返回它,但它几乎是相同的错误。

在一个函数之外,我知道这个有效,所以看起来我应该能够返回它。

SELECT DATE_SUB("2016-01-01", INTERVAL 4 DAY);

3 个答案:

答案 0 :(得分:1)

文档建议您需要END CASE,而不是END

此外,如果使用CASE expr WHEN value2 THEN .... WHEN value2 THEN ... END CASE版本,存储的函数可能会执行得更快,因为它不必重复DAYOFWEEK函数调用7次。

答案 1 :(得分:1)

你也可以使用这样的东西

delimiter //
CREATE DEFINER=`root`@`localhost` FUNCTION `WEEKDATE_SUB` (date_val VARCHAR(10), days TINYINT)
RETURNS VARCHAR(10) DETERMINISTIC
BEGIN
    RETURN  date_val - INTERVAL
            FLOOR(days/5)*7 + 
            IF(DAYOFWEEK(date_val)-1 <= days - FLOOR(days/5)*5
              , (days - FLOOR(days/5)*5)+2
              , days - FLOOR(days/5)*5
           ) DAY;
END;//

<强>样品

mysql> SELECT WEEKDATE_SUB('2017-02-06',1);
+------------------------------+
| WEEKDATE_SUB('2017-02-06',1) |
+------------------------------+
| 2017-02-03                   |
+------------------------------+
1 row in set (0,00 sec)

mysql> SELECT WEEKDATE_SUB('2017-02-07',1);
+------------------------------+
| WEEKDATE_SUB('2017-02-07',1) |
+------------------------------+
| 2017-02-06                   |
+------------------------------+
1 row in set (0,00 sec)

mysql> SELECT WEEKDATE_SUB('2017-02-07',2);
+------------------------------+
| WEEKDATE_SUB('2017-02-07',2) |
+------------------------------+
| 2017-02-03                   |
+------------------------------+
1 row in set (0,00 sec)

mysql>

答案 2 :(得分:0)

这是我最终需要这个工作。注意,;以及对我如何使用CASE声明的更改。

delimiter //
CREATE DEFINER=`root`@`localhost` FUNCTION `WEEKDATE_SUB` (date_val VARCHAR(10), days TINYINT)
RETURNS VARCHAR(10) DETERMINISTIC
BEGIN
    DECLARE SUBVAL INT;
    DECLARE dow INT;
    SET dow = DAYOFWEEK(date_val);
    CASE dow
            WHEN 1 THEN SET SUBVAL = (days   +(FLOOR((days-0.5)/5)+1)*2 - 1);
            WHEN 2 THEN SET SUBVAL = (days   +(FLOOR((days-0.5)/5)+1)*2);
            WHEN 3 THEN SET SUBVAL = (days-1 +(FLOOR(((days-1)-0.5)/5)+1)*2 + 1);
            WHEN 4 THEN SET SUBVAL = (days-2 +(FLOOR(((days-2)-0.5)/5)+1)*2 + 2);
            WHEN 5 THEN SET SUBVAL = (days-3 +(FLOOR(((days-3)-0.5)/5)+1)*2 + 3);
            WHEN 6 THEN SET SUBVAL = (days-4 +(FLOOR(((days-4)-0.5)/5)+1)*2 + 4);
            WHEN 7 THEN SET SUBVAL = (days-5 +(FLOOR(((days-5)-0.5)/5)+1)*2 + 5);
            ELSE SET SUBVAL = days;
    END CASE;
    RETURN DATE_SUB(date_val, INTERVAL SUBVAL DAY);
END;//