it-swarm.it

Dati troncati per colonna

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

In questa query mysql, eseguo questo tipo di operazione in una procedura memorizzata, ma l'ambiente Linux phpmyadmin genera il seguente avviso:

Nota: # 1265 Dati troncati per la colonna 'float_one' alla riga 5

Qualcuno ha un'idea di come posso risolvere questo problema?

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

e la procedura

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 ;

e il risultato

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

Qual è il valore di float_one al momento della conversione ???

Nota questo esempio da MySQL 5.5.12 in Windows

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)

È possibile che i dati siano stati troncati se un numero maggiore di 99999,99 era in float_one. Forse mysql stava convertendo float_one e float_two in DECIMAL (7,2) singolarmente prima di eseguire la divisione. Prova a utilizzare DECIMAL (10,2) o superiore per contenere valori di grandi dimensioni.

AGGIORNAMENTO 2011-07-25 15:05 EDT

Ci sono problemi di troncamento definito in corso qui

Secondo Manuale di riferimento MySQL Pagina 442 Paragrafi 2,

I valori DECIMAL e NUMERIC vengono memorizzati come stringhe, anziché come numeri binari in virgola mobile, al fine di preservare la precisione decimale di tali numeri. Viene utilizzato un carattere per ogni cifra del valore, il punto deciaml (se scala> 0) e il segno - (per i numeri negativi). Se la scala è 0, i valori DECIMAL e NUMERIC non contengono punti decimali o parti frazionarie.

L'intervallo massimo di DECIMAL e NUMERIC è lo stesso di DOUBLE, ma l'intervallo effettivo per la determinata colonna DECIMAL o NUMERIC può essere limitato dalla precisione e dalla scala per una colonna di dati, quando a tale colonna viene assegnato un valore con più cifre che seguono il punto decimale di quello consentito dalla scala specificata, il valore viene arrotondato a quella scala. Quando a una colonna DECIMALE o NUMERICA viene assegnato un valore la cui grandezza supera l'intervallo implicito dalla precisione e dalla scala specificate (o predefinite), MySQL memorizza il valore che rappresenta l'endpoint corrispondente di quell'intervallo.

È necessario soddisfare una precisione e/o una scala maggiori.

Ecco un esempio del perché

Ho scritto questa procedura memorizzata usando le vostre specifiche per DECMIAL e 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 ;

Ho usato due valori: 290.0 e 14.5 per questo test.

Prima di chiamare la procedura memorizzata NumTest, ho calcolato manualmente 290.0/14.5

mysql> select 290.0 / 14.5;
+--------------+
| 290.0 / 14.5 |
+--------------+
|     20.00000 |
+--------------+
1 row in set (0.00 sec)

Ho diviso ogni numero per 100, 10000 e 1000000 e ho riprovato

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)

Fin qui tutto bene !!! Ora per la procedura memorizzata.

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)

Quindi i miei due numeri originali funzionano bene. Dividiamoli per 100 e riproviamo.

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)

ASPETTA, abbiamo perso un po 'di precisione. Quello che è successo ??? Come è successo ??? Devi inserire più cifre decimali (> 2)

AGGIORNAMENTO 2011-07-25 17:37 EDT

Ho sostituito (7,2) con (10,7) nella procedura memorizzata e ho recuperato la precisione corretta

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

Da quello che posso vedere la tua procedura memorizzata scorre semplicemente attraverso le righe - non "salva i dati" da nessuna parte e hai commentato select:

- SELEZIONA first_float, second_float;

Sì, ricevi avvisi quando i campi float(10,3) vengono convertiti in decimal(10,3). Che si tratti di un problema o meno dipende da cosa si desidera fare con i campi.

È solo un esempio del codice reale? Potrebbe essere necessario pubblicare qualche altro ...