为列截断的数据

dol*_*oug 6 mysql stored-procedures

DECLARE float_one, float_two, my_result NUMERIC(7,2)    
my_result = CONVERT(float_one/float_two, DECIMAL(7,2));
Run Code Online (Sandbox Code Playgroud)

在这个mysql查询中,我在一个存储过程中做这种类型的操作,但是Linux环境phpmyadmin抛出如下警告:

注意:#1265 第 5 行“float_one”列的数据被截断

有谁知道我该如何解决这个问题?

CREATE TABLE IF NOT EXISTS `float_sample` (
      `id` int(11) NOT NULL auto_increment,
      `first_number` float(10,3) default NULL,
      `second_number` float(10,3) default NULL,
      PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;

INSERT INTO `float_sample` (`id`, `first_number`, `second_number`) 
VALUES    (1, 2.900, 1.900),    (2, 3.100, 22.100);
Run Code Online (Sandbox Code Playgroud)

和程序

DELIMITER $$
DROP PROCEDURE IF EXISTS float_test$$
CREATE PROCEDURE float_test(IN my_ID INT)  

BEGIN
DECLARE first_float, second_float DECIMAL(10,3);

DECLARE done INT DEFAULT 0;

DECLARE myCursor CURSOR FOR 
        SELECT `first_number`, `second_number`
        FROM `float_sample`
        WHERE `id` = my_ID;

DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

OPEN myCursor;
my_loop:LOOP
    FETCH myCursor INTO first_float, second_float;

    IF done = 1 THEN
        LEAVE my_loop;
    END IF;

END LOOP my_loop;
CLOSE myCursor;

-- SELECT first_float, second_float;
END;$$
DELIMITER ;
Run Code Online (Sandbox Code Playgroud)

结果

1 70 10:41:36    CALL mytests.float_test(1) 0 row(s) affected, 2 warning(s):
1265 Data truncated for column 'first_float' at row 2
1265 Data truncated for column 'second_float' at row 2  0.032 sec
Run Code Online (Sandbox Code Playgroud)

Rol*_*DBA 4

转换时 float_one 的值是多少???

请注意 Windows 中 MySQL 5.5.12 的示例

mysql> select convert(20000,decimal(7,2));
+-----------------------------+
| convert(20000,decimal(7,2)) |
+-----------------------------+
|                    20000.00 |
+-----------------------------+
1 row in set (0.00 sec)

mysql> select convert(200000,decimal(7,2));
+------------------------------+
| convert(200000,decimal(7,2)) |
+------------------------------+
|                     99999.99 |
+------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql> show warnings;
+---------+------+-----------------------------------------------------------------------+
| Level   | Code | Message                                                               |
+---------+------+-----------------------------------------------------------------------+
| Warning | 1264 | Out of range value for column 'convert(200000,decimal(7,2))' at row 1 |
+---------+------+-----------------------------------------------------------------------+

1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

如果 float_one 中的数字大于 99999.99,则数据可能会被截断。也许,mysql在执行除法之前将float_one和float_two分别转换为DECIMAL(7,2)。尝试使用 DECIMAL(10,2) 或更大的值来容纳较大的值。

更新 2011-07-25 15:05 美国东部时间

这里肯定存在截断问题

根据MySQL参考手册第442页第2,3段

DECIMAL 和 NUMERIC 值存储为字符串,而不是二进制浮点数,以便保留这些数字的小数精度。值的每一位都使用一个字符、小数点(如果比例 > 0)和 - 符号(对于负数)。如果小数位数为 0,则 DECIMAL 和 NUMERIC 值不包含小数点或小数部分。

DECIMAL 和 NUMERIC 的最大范围与 DOUBLE 相同,但给定的 DECIMAL 或 NUMERIC 列的实际范围可能受到给定列的精度和小数位数的限制,当为此类列分配一个后面有更多数字的值时如果小数点超出了指定比例所允许的范围,则该值将四舍五入到该比例。当为 DECIMAL 或 NUMERIC 列分配的值的大小超过指定(或默认)精度和小数位所隐含的范围时,MySQL 存储表示该范围的相应端点的值。

您需要适应更大的精度和/或规模。

这是一个例子来说明为什么

我使用您的 DECMIAL 和 NUMERIC 规范编写了这个存储过程。

DELIMITER $$

DROP PROCEDURE IF EXISTS `test`.`NumTest` $$
CREATE PROCEDURE `test`.`NumTest` (num1 NUMERIC(7,2), num2 NUMERIC(7,2))
BEGIN

  DECLARE float_one,float_two,my_result NUMERIC(7,2);
  DECLARE f1,f2 DOUBLE(7,2);

  SET f1 = num1;
  SET f2 = num2;

  SET float_one = num1;
  SET float_two = num2;

  SELECT f1 / f2;
  SELECT float_one / float_two;
  SELECT CONVERT(float_one / float_two,DECIMAL(7,2));
  SET my_result = CONVERT(float_one / float_two,DECIMAL(7,2));
  SELECT my_result;

END $$

DELIMITER ;
Run Code Online (Sandbox Code Playgroud)

我在此测试中使用了两个值:290.0 和 14.5。

在调用NumTest存储过程之前,我手动计算了290.0 / 14.5

mysql> select 290.0 / 14.5;
+--------------+
| 290.0 / 14.5 |
+--------------+
|     20.00000 |
+--------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

我将每个数字除以 100、10000 和 1000000,然后再试一次

mysql> select 2.9 / .145;
+------------+
| 2.9 / .145 |
+------------+
|   20.00000 |
+------------+
1 row in set (0.00 sec)

mysql> select .029 / .00145;
+---------------+
| .029 / .00145 |
+---------------+
|    20.0000000 |
+---------------+
1 row in set (0.00 sec)

mysql> select .00029 / .0000145;
+-------------------+
| .00029 / .0000145 |
+-------------------+
|      20.000000000 |
+-------------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

到目前为止,一切都很好 !!!现在介绍存储过程。

mysql> call numtest(290.0,14.5);
+-----------+
| f1 / f2   |
+-----------+
| 20.000000 |
+-----------+
1 row in set (0.00 sec)

+-----------------------+
| float_one / float_two |
+-----------------------+
|             20.000000 |
+-----------------------+
1 row in set (0.00 sec)

+---------------------------------------------+
| CONVERT(float_one / float_two,DECIMAL(7,2)) |
+---------------------------------------------+
|                                       20.00 |
+---------------------------------------------+
1 row in set (0.00 sec)

+-----------+
| my_result |
+-----------+
|     20.00 |
+-----------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

所以我原来的两个数字工作正常。让我们将它们除以 100,然后再试一次。

mysql> call numtest(2.9,0.145);
+-----------+
| f1 / f2   |
+-----------+
| 19.333333 |
+-----------+
1 row in set (0.00 sec)

+-----------------------+
| float_one / float_two |
+-----------------------+
|             19.333333 |
+-----------------------+
1 row in set (0.00 sec)

+---------------------------------------------+
| CONVERT(float_one / float_two,DECIMAL(7,2)) |
+---------------------------------------------+
|                                       19.33 |
+---------------------------------------------+
1 row in set (0.00 sec)

+-----------+
| my_result |
+-----------+
|     19.33 |
+-----------+
1 row in set (0.00 sec)

Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> show warnings;
+-------+------+-------------------------------------------+
| Level | Code | Message                                   |
+-------+------+-------------------------------------------+
| Note  | 1265 | Data truncated for column 'num2' at row 2 |
+-------+------+-------------------------------------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

等等,我们失去了一些精度。发生了什么 ???这怎么发生的 ???您需要容纳更多的十进制数字 (> 2)

更新 2011-07-25 17:37 美国东部时间

我在存储过程中用 (10,7) 替换 (7,2) 并恢复了正确的精度

mysql> call numtest(2.9,0.145);
+----------------+
| f1 / f2        |
+----------------+
| 20.00000000000 |
+----------------+
1 row in set (0.00 sec)

+-----------------------+
| float_one / float_two |
+-----------------------+
|        20.00000000000 |
+-----------------------+
1 row in set (0.01 sec)

+----------------------------------------------+
| CONVERT(float_one / float_two,DECIMAL(10,7)) |
+----------------------------------------------+
|                                   20.0000000 |
+----------------------------------------------+
1 row in set (0.03 sec)

+------------+
| my_result  |
+------------+
| 20.0000000 |
+------------+
1 row in set (0.05 sec)

Query OK, 0 rows affected (0.06 sec)

mysql>
Run Code Online (Sandbox Code Playgroud)