0

I have the following setup:

> show create table nums;
+-------+--------------------------------------------------------------------+
| Table | Create Table                                                       |
|-------+--------------------------------------------------------------------|
| nums  | CREATE TABLE `nums` (                                              |
|       |   `num` decimal(15,8) DEFAULT NULL                                 |
|       | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+-------+--------------------------------------------------------------------+
$ cat num_file
8.04
$ echo "load data local infile 'num_file' into table nums (@num) 
set num=truncate(@num,8);" | mysql

I would expect that the table would contain 8.04, but instead:

> select * from nums;
+------------+
| num        |
|------------|
| 8.03999999 |
+------------+

Why is this happening, and how can I fix it?

3
  • Let's see the input value. Do you really need to truncate, not round? Do the input values have more than 8 decimal places?
    – Rick James
    Commented Jun 16, 2023 at 21:31
  • @RickJames I tried reducing the problem to its simplest reproducible form, even though the inputs have some more variety than given. The requirement to truncate was given by the client, in cases where the input values have more than 8 decimal places (some inputs do); I agree that round would be a better choice. The example of 8.04 as input is an actual input value.
    – enharmonic
    Commented Jun 19, 2023 at 3:24
  • Can there be negative numbers? How many digits might exist before the decimal place? To follow the letter of the request, you will probably have to use string maniuplation.
    – Rick James
    Commented Jun 19, 2023 at 5:12

1 Answer 1

1

Here are the issues:

  • mysql's load data documentation indicates "LOAD DATA regards all input as strings", so "8.04" is being read as a string, not a numeral
  • truncate() documentation indicates "When the first argument is of any floating-point type or of any non-numeric type, the return type is always DOUBLE"
    • Since a string is a non-numeric type, truncate is returning a DOUBLE, which is an approximated value; as the documentation indicates, "floating-point values are approximate and not stored as exact values".

To solve this, you can cast the input to decimal so truncate() will return a decimal; as the truncate() documentation states, "When the first argument is a DECIMAL value, the return type is also DECIMAL":

set num=truncate(cast(@num as decimal(15,8)),8)
3
  • 1
    I'm pretty sure that will round in the cast, leaving nothing for truncate to do: truncate(cast('8.123456789' as decimal(15,8)),8) --> 8.12345679.
    – Rick James
    Commented Jun 19, 2023 at 5:08
  • @RickJames good catch; what do you think would be a better approach?
    – enharmonic
    Commented Jun 20, 2023 at 12:10
  • Truncation via character manipulation would be messy and risky. Maybe the Customer does not know the technical difference between "truncate" and "round". If these are latitude/longitude values, then 8 decimal places is gross overkill.
    – Rick James
    Commented Jun 20, 2023 at 14:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.