I have some phone numbers (validated such that all containing only integers, no - or + in them) as strings in a text file.
I am doing a simple mysql update on a mysql table which has phone number column as int(12). Note that I convert each phone number extracted from the text file to integer using intval().
The problem that I am facing is that instead of the numbers being inserted I just get 2147483647 to be inserted in each column. I guess I am making a small silly mistake somewhere, but still I can't figure it out. Can anyone explain what mistake am I making?
EDIT: Here is my the piece of code I am using (It does not give any sql error):
$sql="UPDATE ".$table." SET mobile = ".intval($smob).", phone = ".intval($sphone)." WHERE roll='".$sroll."'";
mysql_query($sql, $con) or die(mysql_error());
Excerpt from intval() manual:
The maximum value depends on the system. 32 bit systems have a maximum signed integer range of -2147483648 to 2147483647. So for example on such a system, intval('1000000000000') will return 2147483647. The maximum signed integer value for 64 bit systems is 9223372036854775807.
What you are getting is a maximum number for signed integer on a 32bit machine.
I would strongly advise you to not use this function for phone number conversions. One of the simple reasons is that my mobile number is 11 digit number (without leading + or double zero for international access), and I believe there are some countries that have even more digits.
Why you would need to store phone numbers as int's? Since most likely you are not doing some calculations and statistics on who might have a biggest phone number among your clients, and this data is probably used only for invoicing or a contact info, you could just leave that as a string.
Phone numbers are not integers, and should not be stored using an integer type.
The observed behaviour happens because the values you are trying to store are outside the range accepted by the column type. I recommend putting MySQL into strict mode - this forces it to return errors when inserted data, etc. cannot be stored, instead of silently trying to do whatever is the least bad thing without failing.
Related
I want to show the following numbers with php, but output is strange:
echo 3333333333333333333333333333333; // -----------> 3.3333333333333E+30
echo 0.000025; // -----------> 2.5E-5
I havent asked it to convert. Why it does that? How should I force it to get/set the values exactly as I ask it? (p.s. I've heard of sprint_f or number_format functions, but I don't like them, because i have to know the formatting and length in advance.)
What is more, when I try to save large numbers in Database, there is saved a number: 2147483647 (i found that was the max. integer value). I changed the column type from int to varchar(100) but still same truncation happens.
Look at your precision setting in php.ini
http://php.net/manual/en/ini.core.php
It's the setting that says how PHP will output numbers
When you are using such extreme numbers (both negative or positive) the accuracy of the number system in php comes in to play.
Floating point is not accurate for numbers like that, I would suggest using one of the ones listed here
http://php.net/manual/en/refs.math.php
bc is designed for decimals
Well, I will answer my own topic.
1) The first problem is that PHP truncates LARGE and smallest values... However, I solved that casting values to strings (with double quotes).
2) The second problem was a bit strange...
When I first created that MySQL, I made that column as INT(11) and then changed column to Varchar(100) (exactly as all my other columns were Varchar(100) and they could save that value well).
However, that column was truncating values again. Then I recreated the table, but changed the COLUMN name and then IT WORKED WELL! I think, MySQL cached the column type (or surely something like that happened) !
I'm new to PHP and MySql.
From my register.php form request for a telephone number, most numbers are captured and displayed correctly in phpMyAdmin but some are displaying the same incorrect number: 2147483647.
Any ideas what would might cause this for some accounts and not others?
Sorry if that's not very well phrased.
Change the type of the database column that stores the phone numbers to varchar. A telephone number, for all practical programming purposes, is not a number but a string.
2147483647 is the maximum number an integer can be in MySQL, so if you try for example to store a phone number like 3147483647 as an integer, it is set to that maximum value because it is above 2147483647.
A phone number like 1147483647 will be stored correctly, because it is below.
This phenomenon is called integer overflow.
I have copied this table from Wikipedia into a PostgreSQL database. The column Cultivated land (km2) became a column of type real. Then I use the PHP command
echo rtrim(rtrim(sprintf('%.10F',$v),'0'),'.');
to display the numbers ($v) in a table (both integers and float), but some values lose precision. For instance, the value from United States, 1669302, becomes 1669300, what is strange, since I expected 10 decimal digits of precision. I thought I have lost the precision when saving into a real column, but converting the column to double precision makes the difference (02) appear again, so it was there somewhere.
I don't think I need double precision, so how can I display the real value correctly? Keep in mind that some columns have decimal places, while some others are bigint, and they also should be displayed correctly.
The problem seems to originate from the way PHP returns results. The values are not returned as the corresponding data type, but rather formatted as a string using PostgreSQL default formatting. This formatting, is different for real and double precision types hence you are seeing different results when you convert the column types of your table. The reason you are seeing this specific result is that PostgreSQL guarantees 6 decimal places for real types and 15 decimal places for double precision.
Setting extra_float_digits
The manual states
Note: The extra_float_digits setting controls the number of extra significant digits included when a floating point value is converted to text for output. With the default value of 0, the output is the same on every platform supported by PostgreSQL. Increasing it will produce output that more accurately represents the stored value, but may be unportable.
Therefore, a simple solution to your problem is to increase extra_float_digits before issuing your SELECT-query:
pg_query($connection, "set extra_float_digits = 3");
Alternatively, you can also specify this change when connecting to your database by adding options to your connection string as follows:
$connection = pg_connect("host=localhost port=5432 dbname=test user=php password=pass connect_timeout=5 options='-c extra_float_digits=3'");
Another option would be to set this flag in the postgresql.conf configuration file of the PostgreSQL server if you have access to the server and want to change the option globally.
Casting the values
A different solution would be to have PostgreSQL return a different string to the PHP backend. This can be achieved by casting your columns to types with different default formatting which avoids cutting off some of the digits. In your case you could either cast to integer or double precision, i.e. instead of using
select cultivated_land from table
you could use
select cultivated_land::integer from table
or
select cultivated_land::double precision from table
Changing data types
Looking at the data you specified, I noticed that all numerical values except those columns specifying percentages contain integers, hence the usage of the integer data type is more suitable in this case. It can fit all the integer values of this table (the maximum being 149,000,000, therefore bigint is not required), requires the same storage size as real (4 bytes) and implies the default formatting of integers that you are looking for.
Update: Background on PostgreSQL-PHP interface and floating point representation
As mentioned above the way the PostgreSQL-PHP interface works is that all values sent from PostgreSQL to PHP are formatted as a string in some type-dependent way. Neither any of the pg_fetch_* functions nor pg_copy_to will provide raw values and all of these functions convert the values to strings in the same manner. As far as I am aware the current PHP interface will not provide you with anything different from a string (which, in my opinion, is not the best interface design).
The reason 18.22 is returned as 18.2199993 can be found in how PostgreSQL converts float4 to strings. You can check the code of how PostgreSQL is internally using float4out and find this relevant line that does the string-conversion:
snprintf(ascii, MAXFLOATWIDTH + 1, "%.*g", ndig, num);
num is the float4-number to be printed as a string. Note however that C will promote the float-variable to a double-variable when calling snprintf. This conversion to double precision results in the value 18.219999313354492 which is why you end up seeing 18.2199993 (you can check this here and will also find some details on floating point number representation on this site).
The takeaway message is that all your float4 values will be converted using this function and the only parameter you can influence is ndig by varying extra_float_digits, however no single value for this variable will suffice all your needs in representing the values as you want them. So as long as you keep using float4 as your data type and use the current PHP-interface to obtain the data you will run into these problems.
I therefore still recommend choosing different data types for your columns. If you think you have a requirement for decimal numbers you might want to investigate decimal data types where you can specify precision and scale as required for your application. If you would like to stick with floating point numbers I suggest rounding the values in PHP before displaying them to the user.
So, I've created a datatable that asks for a users Mobile Provider (varchar), phonenumber, and pin. The table seems to work well except that when a user inputs a phone number the original number converts to 2147483647. I've spent sometime looking around and I learned that this is because I've gone beyond the 32-bit limit on my table. In order to fix this, I need to make my integer limit larger than 10 (what I originally had) in MYSQL database.
I've changed the MYSQL table using PhpMyAdmin; however, I am still getting the same problem. Is this because I need to now change something on the Yii-end?
I know that I could use CRUD to contstruct a new MVC relationship - but I've already added in quite a few functions to the Model and the Controller. Is there a way with Yii to change my database in piecemeal way? I.e. without having to use Crud?
The fact that telephone directory numbers (DNs) resemble integers notwithstanding, using a integer of any width to store a DN is very bad practice indeed.
That's because, as you have discovered, DNs that get manipulated as if they were integers sometimes become corrupted.
Using a 32-bit number to store a North American Dialing Plan number (Canada, Caribbean, US) is just flat incorrect. Partway through the 429 area code, your numbers will be corrupted even if you manage to use an unsigned integer.
Use varchar(20) and you'll be fine.
Here's something to think about: ITU-T recommendation E.123 for representing telephone numbers. http://en.wikipedia.org/wiki/E.123
INT is still a 32-bit number, the (10) in INT(10) is an artificial cap that's mostly useful for saying how far ZEROFILL should fill to.
Try BIGINT(10), as this will allow all 10-digit numbers, even those higher than 231-1
I try to store the PHP floating point value 63.59072952118762 into a double precision column in postgres. Postgres stores the value as 63.59073. Does anyone know why? 8 byte should be more than enough for that value. I've tried with the data type numeric, which works when specifying the precision, but that shouldn't really be necessary.
Update: The same problem is present when trying to store 63.5907295, so the suggestion that something happens with the double before it's getting stored seems realistic.
Update II (partly solved): The line where I assign the double parameter looks like this:
$stmt->bindParam(4, $this->latitude);
The thing I didn't know is that PDO defaults its param type to string. I changed it to PDO::PARAM INT in lack of a better alternative (PARAM DOUBLE was not an option), and got 10 digits precision in the double stored in postgres (some progress, at least). I've checked that the numeric type works well, so it seems that numeric is the way to go when using PDO and doubles that has to have a precision of more than 10 decimals.
Anyways, as someone has mentioned, I don't know if it's a must for me to have this kind of precision, but I think the problem in itself deserved to be investigated.
How do you determine what PostgreSQL is storing?
How do you send the data to PostgreSQL?
How do you get the data back again?
How do you display it?
What type is the column in the database?
There are many, many places on the path between PHP and PostgreSQL where there could be confusion about how to represent the data.
It is important to explain how data is inserted into the DBMS. Using a literal value in the INSERT statement leads to a different set of problems from using bound parameters. If you wrote the value out in the SQL:
INSERT INTO SomeTable(SomeColumn) VALUES(63.xxxxxxxxx);
and the data was truncated, you'd have a problem down in PostgreSQL. If you bind the variable, you have to be sure to understand what PHP and the PDO PostgresSQL modules do with the value - is it sent as a double, or as a string, and which code deals with the conversion, and so on.
You run into analogous issues with Perl + DBI + DBD::YourDBMS (DBD::Pg in your case).
Consider using the DECIMAL/NUMERIC type if you need that much precision
PostgreSQL accepts float(1) to float(24) as selecting the real type, while float(25) to float(53) select double precision.
On most platforms PG, the real type has a range of at least 1E-37 to 1E+37 with a precision of at least 6 decimal digits. The double precision type typically has a range of around 1E-307 to 1E+308 with a precision of at least 15 digits (REF)
Which one do you use?