web-dev-qa-db-ja.com

列のデータが切り捨てられました

DECLARE float_one, float_two, my_result NUMERIC(7,2)    
my_result = CONVERT(float_one/float_two, DECIMAL(7,2));

この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);

と手順

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 ;

そしてその結果

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
6
dole doug

変換時の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)

Float_oneに99999.99より大きい数値があった場合、データが切り捨てられた可能性があります。おそらく、mysqlは除算を実行する前に、float_oneとfloat_twoを個別にDECIMAL(7,2)に変換していました。大きな値に対応するには、DECIMAL(10,2)以上を使用してください。

UPDATE 2011-07-25 15:05 EDT

ここで起こっている明確な切り捨て問題があります

MySQLリファレンスマニュアルページ442段落2,3 によると

DECIMALおよびNUMERIC値は、これらの数値の10進精度を保持するために、2進浮動小数点数としてではなく、文字列として格納されます。値の各桁、deciamlポイント(scale> 0の場合)、および-記号(負の数の場合)に1文字が使用されます。スケールが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 ;

このテストでは、2つの値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)

各数値を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)

ここまでは順調ですね !!!次に、ストアドプロシージャについて説明します。

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)

したがって、私の元の2つの数値は正常に機能します。それらを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)

待って、我々はいくつかの精度を失った。どうした ???どうしてそうなった ???より多くの十進数字(> 2)に対応する必要がある

UPDATE 2011-07-25 17:37 EDT

ストアドプロシージャで(7,2)を(10,7)に置き換え、適切な精度を取得しました

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>
3
RolandoMySQLDBA

私が見ることができるものから、あなたのストアドプロシージャは行をループするだけです-それはどこにも「データを保存」せず、selectをコメントアウトしました:

-SELECT first_float、second_float;

はい、float(10,3)フィールドがdecimal(10,3)に変換されると警告が表示されます。それらが問題であるかどうかは、フィールドで何をしたいかによって異なります。

これは実際のコードのサンプルですか?さらに投稿する必要があるかもしれません...