0

我的函数有两个变量(“日期”,从“日期”中减去的月数)。

这是我的功能:

create function a_testbed.PrevMonth (
in_date         date,
in_mn_count     int)
RETURNS int
BEGIN
/* local variable declaration */
declare v_date         int(255);
declare v_date_format  varchar(10);
declare v_date_sub     varchar(10);

set v_date_format := DATE_FORMAT(v_date, '%Y-%m');
set v_date_sub := DATE_FORMAT(curdate(), '%Y-%m');

if (in_date is null) then
  set v_date := v_date_sub;
elseif (in_mn_count is null or in_mn_count < 0) then
  set in_mn_count := 0;
else
  set v_date := v_date_sub;
end if;
RETURN v_date_format;
END;
#

不断收到错误:

ERROR 1265 (01000) Data Truncated for column 'v_date' at row 1

有什么想法吗?
谢谢!

4

3 回答 3

2

您的功能有很多问题:

  1. 您可以set v_date_format := DATE_FORMAT(v_date, '%Y-%m');,但这是在您将值分配给 之前v_date

  2. 后来你分配了set v_date := v_date_sub;,但v_date在那之后你再也没有使用过,那有什么意义呢?

  3. 您分配set in_mn_count := 0;,但也从不使用此变量。

  4. 最后你做到了RETURN v_date_format;v_date_format是 a VARCHAR,但函数被声明为 return INT。而且这个字符串的内容是 形式的YYYY-MM,所以看起来不像是整数。

我不确定这些是否会导致Data truncated错误,但是当功能如此损坏时,这似乎并不重要。

于 2013-07-19T04:12:49.410 回答
0

我不相信“ INT(255)”是有效的数据类型。

我知道 255 只是一个显示宽度属性。INT 数据类型定义值的范围,显示宽度不影响值的范围。但我只是从未见过大于 11 的 INT 上的长度修饰符。(10 表示无符号整数)(?)

作为测试,您可以尝试指定INT(11),或仅指定INT.

更有问题的可能是这个具有数据类型INT的变量作为第一个参数传递给DATE_FORMAT函数。但第一个参数DATE_FORMAT需要是 aDATEDATETIME( TIMESTAMPiirc)。可能有一些从 INT 到 DATE 的隐式转换,但我认为没有。


我不明白为什么你需要一个函数来从 DATE 中减去几个月。MySQL 具有内置函数和执行此操作的简单表达式。

例如:

dateexpr + INTERVAL -6 个月

返回从 中减去 6 个月的 DATE(或 DATETIME)值dateexpr。如果您需要“向下舍入”到本月的第一天,或者转换为仅包含 'yyyy-mm' 的字符串,则可以分别执行 aDATE_FORMAT(dateexpr,'%Y-%m-01')或 a SUBSTRING(dateexpr,1,7)


审查

CREATE FUNCTION a_testbed.PrevMonth (
in_date         date,
in_mn_count     int)

看起来不错,两个输入参数,一个 DATE 和一个 INT。(函数参数始终是 IN 参数。)

RETURNS int

有点奇怪的是,一个名为的函数PrevMonth接受一个 DATE 参数,但返回一个 INT,而不是一个 DATE,但这不是错误。

BEGIN
/* local variable declaration */
DECLARE v_date         INT(255);

255 的显示宽度很奇怪。以前从未在 INT 上看到过这种情况。

DECLARE v_date_format  VARCHAR(10);
DECLARE v_date_sub     VARCHAR(10);

两根弦,看起来不错。

SET v_date_format := DATE_FORMAT(v_date, '%Y-%m');
                                 ^^^^^^

但是v_date是 INT,而不是 DATE 或 DATETIME。而且它没有初始化,所以它是NULL。如果这不会引发异常,那么我们希望v_date_format为 NULL。(我怀疑你想在in_date这里指定代替v_date。)

SET v_date_sub := DATE_FORMAT(curdate(), '%Y-%m');

这应该得到 7 个字符,例如“2013-07”。所以那里没有问题。

IF (in_date IS NULL) THEN
    SET v_date := v_date_sub;

这是in_date参数的用法。检查它是否为空。如果是,则分配与我们分配给 v_date_sub 相同的 7 个字符。知道了。

ELSEIF (in_mn_count IS NULL OR in_mn_count < 0) THEN
    SET in_mn_count := 0;

为 IN 参数赋值是否有效?(这可能是有效的,但很奇怪。通常我们不会为参数赋值,除非它们是 OUT 或 INOUT 参数。我们通常为过程变量(有时是 MySQL 用户变量)赋值。)

为什么这取决于 in_date 是否为空(前面的 IF)。似乎我们都想在任何一种情况下检查这个参数。

ELSE
  SET v_date := v_date_sub;

这不是第一个指定的相同操作IF吗?看起来这里的逻辑是“如果 in_date 不为 null 并且 ifnull(in_mn_count,-1)<0”我们做一件事,否则我们做其他事情。我们要么尝试为 IN 参数分配值,要么将当前的 YYYY-MM 分配给 v_date。

END IF;

到目前为止,in_date 参数的唯一用途是检查它是否为 NULL。in_mn_count 参数的唯一用途是尝试将零分配给它,如果它为空或小于零。

RETURN v_date_format;

我们唯一一次分配任何东西v_date_format是在函数的开头,当我们从 DATE_FORMAT 函数分配返回值时,传入一个 NULL 值(作为 INT 而不是 DATE。)那么所有其他代码应该是什么正在做?

END

是的,请结束。这个函数有很多错误,它让我很头疼。所以,请,是的,END。让它停下来。

于 2013-07-19T03:51:54.190 回答
0

您将 varchar 分配给 intset v_date := v_date_sub; 更改此:

declare v_date         varchar(10);
于 2013-07-19T03:58:17.437 回答