Can't insert decimal value with PDO - php

I've been trawling the web for hours now and trying different methods, and I can't work out why PDO can't insert any row where one of the values contains a decimal.
For example, if the value entered into the cost field has no decimal value then it works fine. But anything like with a decimal and it just ignores the whole row.
200 works, even 200.00 works. But things like 39.99 don't.
Here's the code:
$invoice_id = $db->lastInsertId('id');
$item_name = $_POST['item_name'];
$item_qty = $_POST['item_qty'];
$item_cost = $_POST['item_cost'];
$item_vat = $_POST['item_vat'];
for($i = 0; $i < count($item_name); $i++) {
$item_query = $db->prepare("INSERT INTO hm_invoice_items(invoice, item, qty, amount, vat) VALUES(:invoice, :item, :qty, :amount, :vat)");
$item_query->bindParam(":invoice", $invoice_id);
$item_query->bindParam(":item", $item_name[$i]);
$item_query->bindParam(":qty", $item_qty[$i]);
$item_query->bindParam(":amount", $item_cost[$i]);
$item_query->bindParam(":vat", $item_vat[$i]);
if (!$item_query->execute())
{
die(showMessage("There has been a problem adding the invoice items.", "Error!"));
}
}
A var_dump tells me that the insert query is receiving the values, but it does not like dealing with decimals.

There could be an issue with decimal separator.
When debugging such cases it's essential to var_dump() e-ve-ry-thing!
Why don't you var_dump your values for the closer inspection?
Why didn't you play with decimals only, without POST, without other values?
A question titled "Can't insert decimal value with PDO" should contain short reproduceable code with decimal value present to readers and the result.
Judging by indirect measures will do no help for you and - especially - won't bring you help from strangers.
"var_dump your values" means every suspicious value, like
var_dump($item_cost[$i]);
inside your loop
if you get no output - then there is empty value, so, no wonder nothing inserted.
By the way, you're binding apparently decimal item_cost value to apparently integer amount field. Is it a typo?
But again - where is a certain reproduceable proofcode contains one insert query, one hardcoded decimal value and one result? Ugh - and table definition of course.

Try this?
$item_query->bindParam(":amount", floatval($item_cost[$i]));
At least it works for me when I deal with MySQL decimal data type with PDO.

Use the following to display the content of all the values POSTed to your PHP script:
print_r($_POST);

Related

PHP: strings automatically converted to float and gives negative numbers

I have a PHP code that will compute the balance of the quantity but it gives me a negative value as a balance quantity as shown in the image below.
I tried to check the quantities if what's causing the problem and try to var_dump the quantity. after checking using var_dump, it shows that the data type of my quantity is string while my balance quantity is float.
so far, I have my code below:
$query_po_quantity = mysqli_query($new_conn, "SELECT quantity, po_number FROM purchase_order WHERE supplier_name = '$supplier_name' AND category_name = '$category_name' AND activity = '$activity' AND description = '$description'");
$row = mysqli_fetch_assoc($query_po_quantity);
$po_quantity = $row['quantity'];
$po_number = $row['po_number'];
$query_rr_quantity = mysqli_query($new_conn, "SELECT SUM(total_received) AS quantity FROM receiving_reports WHERE po_number = '$po_number' AND category_name = '$category_name' AND activity = '$activity' AND description = '$description'");
$row = mysqli_fetch_assoc($query_rr_quantity);
$rr_quantity = $row['quantity'];
$balance = $po_quantity - $rr_quantity;
$supplier_name = preg_replace('/\\\\/', '', $supplier_name);
echo $po_quantity.' - '.$rr_quantity.' = '.$balance.'<br />';
This is the output:
how can I get the actual balance?
The reason you're getting an incorrect result when calculating 0.42 - 0.420000000000000000004 is due to errors with floating point precision. This is due to the way floating point numbers are stored, and both MySQL and PHP are susceptible to floating point errors if done incorrectly, but they also both have ways to prevent them when you do need highly precise calculations. With floating point types only the approximate value is stored and attempts to treat them as exact values in comparisons may lead to problems.
For PHP, this means you need to use either the arbitrary precision math functions or gmp functions. For MySQL, you need to be storing the numbers using the DECIMAL format with the desired precision you require.
First thing's first, you need to change the data type of your column in MySQL to DECIMAL, not a string. Strings are inappropriate to store numbers. Even if you were using a FLOAT or DOUBLE to store your values
your code may have actually worked, because these values likely would have been rounded.
Next, seeing as the value 0.420000000000000000004 came from a string stored in your database, I'm assuming the error stems from whatever calculations you did using PHP beforehand when you were calculating the value to be inserted. You will need to update this code to use precise math.
Use number_format:
$rr_quantity = number_format($row['quantity'], 2);
Float variable range 1.7E-308 and 1.7E+308 so it's give 15 digits of accuracy. Use number format

Getting different results when adding numbers

I'm currently doing some simple addition of decimal numbers in PHP (currency), but for some reason I can add the same numbers twice and get different results.
What I'm doing is getting some rows from a MySQL table in PHP, adding the total for each receipt and storing the result in another MySQL table as decimal(10,2):
<?php
foreach($query_result as $row) {
$total_receipts = $total_receipts + $row['total'];
//my locale requires commas as decimal separators and points for thousands:
echo number_format($total_receipts,2,",",".");
}
?>
The strange thing is I can do the same operation twice on the exact same rows and get two different results, with regard to the decimal point. For example, when I add the following numbers:
3621.94
1230.29
1025.00
1025.00
The first time the correct value of 6902.23 was inserted in the DB. When I ran it the second time, the value inserted in the DB was 6.90.
For some reason, the second time around it decided to move the decimal point.
I'm not using number_format() to insert in to the DB , I'm storing $total_receipts without modifications.
In this particular example the error appeared in the second try, but sometimes it can show up the first time and the second time be correct.Sometimes I cannot even replicate the bug.
What am I doing wrong? I've been reading about bcmath, but I'm not sure if I should be using it for this simple addition.
Please use number_format() to insert into DB:
<?php
$total_receipts = 0; //Always initialize vars
foreach($query_result as $row) {
$total_receipts += $row['total'];
//this way to insert into DB
echo number_format($total_receipts, 2, ".", "");
}
?>

Inserting PHP float/decimal values into MySQL

It's a pretty simple question to be honest. I've been looking for a while now on Google for a solution but nothing seems to work. I have the following field in my database:
decimal(2,1)
I have two variables in PHP (which come from values inserted into a form via POST) I want to add together and then insert into this field.
$sql2 = $link->prepare("INSERT INTO league_stats (match_id, rating)
VALUES (?, ?)");
$sql->bind_param("ii", $match_id, $rating);
$match_id = $_SESSION["match_id"];
$rtg1 = $_POST[$rating_1"];
$rtg2 = $_POST[$rating_2"] / 10;
$rating = $rtg1 + $rtg2;
For example, rtg1 would be 7 and rtg2 would be 3 divided by 10 so it comes out as 0.3. I then add these two numbers together to make 7.3. When I go to insert it into the database, it always displays the second digit as 0. So instead of 7.3 it would come out as 7.0. I've tried many different methods but I always get the exact same result.
I even assigned $rating to a raw value just to test if there was something wrong with my variables:
$rating = 7.5
Still comes out as 7.0.
Could somebody please provide an example of how to correctly insert a float type PHP variable into MySQL? And also maybe explain how to correctly add two float values together? Thanks!
You are telling php to cast $match_id and $rating to integer. You should use:
$sql->bind_param("id", $match_id, $rating);
instead of
$sql->bind_param("ii", ...

How to compare (min & max) Float values with MySQL?

I've a database with lon and lat geo location data.
Both are saved as float / decimal attribute in the mysql table.
Now I want to compare this stuff like:
(u.user_location_lat <= ".$lat_max." AND u.user_location_lat >= ".$lat_min.") AND
(u.user_location_long <= ".$long_max." AND u.user_location_long >=".$long_min.")
But it does not show any result (and it should!) - but also no error.
How to EASILY solve this (I actually don't want to work with spatial indexes - at least I do not understand how to do)?
Thanks.
I recommend you verify what that statement looks like, after you do the variable substitution.
That is, echo or vardump the contents of the variable containing the SQL text, before you prepare/execute the SQL statement.
There doesn't appear to be anything wrong with the form of the predicates. (These could be written using equivalent BETWEEN comparators, but it's not a problem what you have written.)
It's possible you have the min and max values swapped, or have the longitude and latitude swapped. If that's not the issue, then I suspect that the variables being substituted may be represented in scientific notation, rather than as decimal values.
e.g. the SQL text gets generated
... u.lat <= 1.241E+2 ...
rather than
... u.lat <= 124.1 ...
In the former case, MySQL is going to evaluate that literal as decimal value of 1.241.
(There's a corner case issue when the bounding box crosses the +180/-180 boundary, but I don't see that's likely a problem for most of your values, that's going to be an exceptional case, which you would probably need to setup special test case to actually have happen.)
In order to debug this, you need the actual SQL text that's being sent to the database to be prepared/executed.
(There's not enough information in your question to identify the actual problem.)
Q: How do I get the actual SQL text?
A: Construct your SQL statement as a string into a variable; and then var_dump that variable for debugging:
$sqltext = "SELECT ... WHERE u.lat <= ". $lat_max . " AND u.lat ... ";
var_dump($sqltext);
$stmt = mysqli_prepare($db, $sqltext);

updating a large number in MySQL larger than 100 trillion with PHP is unreliable

When I send a value to MySQL in PHP like this:
$mysqli->query("update bank set cash = $cash");
It works fine for smaller numbers, but anything 100 trillion or larger yields unexpected results. Sometimes it updates the number in increments of 100, and sometimes not at all.
A prepared statement also has different, but unreliable results once the number gets larger than a couple billion:
$stmt->prepare("update bank set cash = ?");
$stmt->bind_param('i',$new_cash_amt);
$stmt->execute();
Use double quotes.
use or die(mysql_error()); to see you bug.
Stop using mysql* function, will be deprecated soon.
Fix:
$amount = 17;
$mysqli->query("
update player_stats
set cash = cash + $amount
where username = 'cheater2'
") or die(mysql_error());
You're using single quotes, which wont parse a php variable. It's looking for cash=cash+$amount as a string, not a variable holding data.
I'm answering my own question here.
It turns out that when you pass values like this:
$huge_number = 100000000000012345;
echo "The huge_number is: $huge_number";
It will print the following:
The huge_number is: 1.0000000000001E+17
The precise value is lost in this conversion. That is why the value increments in multiples of 100 sometimes, and not at all at other times.
As with the prepared statement, any values larger than a 32bit integer (since I put an 'i' as the type in the bound parameter) will get truncated and altered unexpectedly. I should have passed the new value as a 'd', like so:
$stmt->bind_param('d',$new_cash_amt); //This works correctly

Categories