GREATEST() 和 LEAST() 函数无法在 MySQL 5.7 的存储过程中使用 TIME 变量

GREATEST() & LEAST() functions not working with TIME variables in stored procedure in MySQL 5.7

我有一个MySQL存储过程来计算员工的工作时间、加班时间等。在某些特殊情况下,我需要计算两个时间段(员工的工作时间和公司的工作时间)之间的重叠,并且我是在 TIME 类型的变量上使用 GREATEST() 和 LEAST() 函数完成的。

存储过程在 MySQL 5.5 中产生了正确的结果,但是当我升级到 MySQL 5.7 时行为发生了变化。实际上,如果我将变量类型更改为 VARCHAR(),它可以在 MySQL 5.7 中工作,但它所处理的数据来自 table TIME 类型的字段。

下面是演示问题的过程的简化形式。

DROP procedure IF EXISTS `timetest`;

DELIMITER $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `timetest`()
BEGIN
  DECLARE working_from, working_to, open_from, open_to TIME;

  -- This data actually comes from table column of type TIME
  SET working_from = '08:00:00';
  SET working_to = '16:00:00';
  SET open_from = '07:00:00';
  SET open_to = '14:00:00';

  IF open_from IS NOT NULL AND open_to IS NOT NULL THEN
    SET working_from = GREATEST(working_from, open_from);
    SET working_to = LEAST(working_to, open_to);
  END IF;

  SELECT working_from, working_to;

END$$

DELIMITER ;

在 MySQL 5.5:

mysql> call timetest();
+--------------+------------+
| working_from | working_to |
+--------------+------------+
| 08:00:00     | 14:00:00   |
+--------------+------------+
1 row in set (0.00 sec)

在 MySQL 5.7:

mysql> call timetest();
+--------------+------------+
| working_from | working_to |
+--------------+------------+
| 07:00:00     | 14:00:00   |
+--------------+------------+
1 row in set (0,00 sec)

看起来 GREATEST 没有将值检测为 TIME 值。您可以使用 CAST(column_name AS TIME):

解决此问题
DELIMITER $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `timetest`()
BEGIN
  DECLARE working_from, working_to, open_from, open_to TIME;

  -- This data actually comes from table column of type TIME
  SET working_from = '08:00:00';
  SET working_to = '16:00:00';
  SET open_from = '07:00:00';
  SET open_to = '14:00:00';

  IF open_from IS NOT NULL AND open_to IS NOT NULL THEN
    SET working_from = CAST(GREATEST(working_from, open_from) AS TIME);
    SET working_to = CAST(LEAST(working_to, open_to) AS TIME);
  END IF;

  SELECT working_from, working_to;

END$$

DELIMITER ;

demo on dbfiddle.uk


这看起来像是 MySQL 5.7 (see this bug report) 上的错误:

CREATE  PROCEDURE `test_greatest`()
BEGIN
  DECLARE time_1 TIME;
  DECLARE time_2 TIME;
  DECLARE time_3 TIME;
  DECLARE result TIME;

  SET time_1 = '08:00:00';
  SET time_2 = '07:00:00';
  SET time_3 = '06:00:00';

  -- always returns the last parameter.
  SET result = GREATEST(time_1, time_2, time_3); -- result is 06:00:00
  SET result = GREATEST(time_1, time_3, time_2); -- result is 07:00:00
  SET result = GREATEST(time_2, time_3, time_1); -- result is 08:00:00

  -- using a CAST on first parameter the GREATEST is working.
  SET result = GREATEST(CAST(time_1 AS TIME), time_2, time_3); -- result is 08:00:00
  SET result = GREATEST(time_1, CAST(time_2 AS TIME), time_3); -- result is 06:00:00
  SET result = GREATEST(time_1, time_2, CAST(time_3 AS TIME)); -- result is 06:00:00

  -- using CAST on the whole GREATEST is working.
  SET result = CAST(GREATEST(time_1, time_2, time_3) AS TIME); -- result is 08:00:00

  SELECT result;
END

此示例总是 returns GREATEST 的最后一个参数 (time_3)。