关于mysql:尝试使用DATEADD并且获取函数不存在错误

Trying to use DATEADD and getting function does not exist error

我有表TableName,其中包含大约5,000行。 它由product_idScheduleTime组成。

我想用这个表做的是替换ScheduleTime的每个值,无论它当前是什么。 每个记录的新值ScheduleTime应设置为前一个记录之后20分钟的提名值,但有以下异常。 如果提名者ScheduleTime发生在22:30:00之后或05:00:00之前(即,为时已晚或太早),则应将其设置为下一个可用的日期时间。

我应该能够指定ScheduleTime的第一个新值。

这是我目前使用的查询...

1
2
3
4
UPDATE TableName
SET ScheduleTime = DATEADD( MI, ScheduleTime, 20 )
WHERE CAST( ScheduleTime AS TIME ) >= '22:30:00'
   OR CAST( ScheduleTime AS TIME ) < '05:00:00';

但是它产生了这个错误信息......

1
#1305 - FUNCTION DatabaseName.DATEADD does not exist

此查询可用于创建我拥有的表...

1
2
3
4
5
CREATE TABLE IF NOT EXISTS TableName
(
    product_id VARCHAR( 255 ) NOT NULL,
    ScheduleTime DATETIME NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

我使用以下示例数据填充上表...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
INSERT INTO TableName ( product_id,
                        ScheduleTime )
VALUES ( '01', '2017-05-07 22:00:59' ),
       ( '02', '2017-05-07 09:09:59' ),
       ( '03', '2017-05-07 09:59:59' ),
       ( '04', '2017-05-07 09:49:59' ),
       ( '05', '2017-05-07 23:09:59' ),
       ( '06', '2017-05-07 23:09:59' ),
       ( '07', '2017-05-07 23:09:59' ),
       ( '08', '2017-05-07 23:09:59' ),
       ( '09', '2017-05-07 23:09:59' ),
       ( '10', '2017-05-07 23:09:59' ),
       ( '11', '2017-05-07 23:09:59' ),
       ( '12', '2017-05-07 23:09:59' ),
       ( '13', '2017-05-07 23:09:59' ),
       ( '14', '2017-05-07 23:09:59' ),
       ( '15', '2017-05-07 23:09:59' ),
       ( '16', '2017-05-07 23:09:59' ),
       ( '17', '2017-05-07 23:09:59' ),
       ( '18', '2017-05-07 23:09:59' ),
       ( '19', '2017-05-07 23:09:59' ),
       ( '20', '2017-05-07 23:09:59' );


请尝试以下......

1
2
3
4
5
6
7
8
9
10
11
12
SET @workingScheduleTime := ( SELECT DATE_ADD( '2017-05-06 22:00:59', INTERVAL -20 MINUTE ) );
UPDATE TableName
JOIN ( SELECT product_id,
              CASE
                  WHEN TIME( DATE_ADD( @workingScheduleTime, INTERVAL 20 MINUTE ) ) NOT BETWEEN '05:00:01' and '22:29:59' THEN
                      @workingScheduleTime := DATE_ADD( TIMESTAMP( DATE( @workingScheduleTime ), '05:00:01' ), INTERVAL 1 DAY )
                  ELSE
                      @workingScheduleTime := DATE_ADD( @workingScheduleTime, INTERVAL 20 MINUTE )
              END AS ScheduleTime
       FROM TableName
     ) AS redatedList ON TableName.product_id = redatedList.product_id
SET TableName.ScheduleTime = redatedList.ScheduleTime;

此解决方案通过循环遍历每个记录并将20 minutes添加到给予前一记录的ScheduleTime字段的值来工作。它还允许指定ScheduleTime的初始值。因此,我们需要在初始值之前以ScheduleTime的工作值20 minutes开始,这样循环的第一次迭代将返回我们的初始值。因此我的解决方案从声明开始......

1
SET @workingScheduleTime := ( SELECT DATE_ADD( '2017-05-06 22:00:59', INTERVAL -20 MINUTE ) );

在我们的工作值初始化的情况下,我使用基于Eric的解决方案基于SELECT查询在MySQL-UPDATE查询中使用SELECT语句实现了UPDATETableName。声明如下......

1
2
3
4
5
6
7
8
9
10
11
UPDATE TableName
JOIN ( SELECT product_id,
              CASE
                  WHEN TIME( DATE_ADD( @workingScheduleTime, INTERVAL 20 MINUTE ) ) NOT BETWEEN '05:00:01' and '22:29:59' THEN
                      @workingScheduleTime := DATE_ADD( TIMESTAMP( DATE( @workingScheduleTime ), '05:00:01' ), INTERVAL 1 DAY )
                  ELSE
                      @workingScheduleTime := DATE_ADD( @workingScheduleTime, INTERVAL 20 MINUTE )
              END AS ScheduleTime
       FROM TableName
     ) AS redatedList ON TableName.product_id = redatedList.product_id
SET TableName.ScheduleTime = redatedList.ScheduleTime;

此语句首先在TableName的一个实例之间执行INNER JOIN,并根据其共享值product_id执行以下子查询的结果...

1
2
3
4
5
6
7
8
SELECT product_id,
       CASE
           WHEN TIME( DATE_ADD( @workingScheduleTime, INTERVAL 20 MINUTE ) ) NOT BETWEEN '05:00:01' and '22:29:59' THEN
               @workingScheduleTime := DATE_ADD( TIMESTAMP( DATE( @workingScheduleTime ), '05:00:01' ), INTERVAL 1 DAY )
           ELSE
               @workingScheduleTime := DATE_ADD( @workingScheduleTime, INTERVAL 20 MINUTE )
           END AS ScheduleTime
FROM TableName

此子查询为TableName中的每个记录选择product_id的值,然后检查工作值的下一个值是否会在提问者禁止的时间范围内发生,因为太晚/太早。如果确实如此,则CASE语句选择下一个可接受的时间(第二天05:00:01)。如果被提名者的价值落在可接受的时间范围内,则由CASE声明选择。工作值已更新

然后选择CASE语句选择的值作为子查询的新值ScheduleTime

如上所述,子查询的结果然后以这样的方式连接到TableName,即TableName的每个现有记录实际上都附加了它的新值。 SET语句使用此新建立的关系将ScheduleTime的每个现有值更改为其对应的新值。

此答案针对使用问题中的CREATE语句创建的数据集进行了测试,并使用以下脚本填充...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
INSERT INTO TableName ( product_id,
                        ScheduleTime )
VALUES ( '01', '2017-05-07 22:00:59' ),
       ( '02', '2017-05-07 09:09:59' ),
       ( '03', '2017-05-07 09:59:59' ),
       ( '04', '2017-05-07 09:49:59' ),
       ( '05', '2017-05-07 23:09:59' ),
       ( '06', '2017-05-07 23:09:59' ),
       ( '07', '2017-05-07 23:09:59' ),
       ( '08', '2017-05-07 23:09:59' ),
       ( '09', '2017-05-07 23:09:59' ),
       ( '10', '2017-05-07 23:09:59' ),
       ( '11', '2017-05-07 23:09:59' ),
       ( '12', '2017-05-07 23:09:59' ),
       ( '13', '2017-05-07 23:09:59' ),
       ( '14', '2017-05-07 23:09:59' ),
       ( '15', '2017-05-07 23:09:59' ),
       ( '16', '2017-05-07 23:09:59' ),
       ( '17', '2017-05-07 23:09:59' ),
       ( '18', '2017-05-07 23:09:59' ),
       ( '19', '2017-05-07 23:09:59' ),
       ( '20', '2017-05-07 23:09:59' );

我的代码的结果已被提问者确认为合适。

进一步阅读

https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#operator_between(在MySQL的BETWEENNOT BETWEEN运算符上)

https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date(在MySQL的DATE()函数上)

https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-add(在MySQL的DATE_ADD()函数上)

https://dev.mysql.com/doc/refman/5.7/en/set-statement.html(在MySQL的SET语句中)

https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_time(在MySQL的TIME()函数上)

https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timestamp(在MySQL的TIMESTAMP()函数上)

https://dev.mysql.com/doc/refman/5.7/en/update.html(在MySQL的UPDATE语句中)