MySQL float values jumping around on insert? - sql

So i have a SQL table setup as such
CREATE TABLE IF NOT EXISTS `points` (
`id` int(11) NOT NULL auto_increment,
`lat` float(10,6) NOT NULL,
`lng` float(10,6) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM;
And im inserting stuff like
INSERT INTO `points` (`lat`, `lng`) VALUES ('89.123456','-12.123456');
Gives me a row with lat and lng being 89.123459 and -12.123455
Whats up?

In computers a "float" value is stored as a number times a number squared generally, and some numbers can't be stored exactly as entered.
If you need it exact you should store it as DECIMAL(8,6)

FLOAT data types have rounding effects, because not every fractional base-10 number can be represented in the base-2 format of IEEE 754. For this reason, FLOAT and DOUBLE PRECISION should be considered inexact numeric data types.
Read: "What Every Computer Scientist Should Know About Floating-Point Arithmetic" (http://www.validlab.com/goldberg/paper.pdf)
+1 to #MindStalker's answer -- use NUMERIC or DECIMAL if you need exact numeric data types.

Related

Small number out of DOUBLE range

I created a table on a mariaDB with the following definition. Note the longitude and latitude fields.
Create Table geo_data (
geo_data_id int NOT NULL AUTO_INCREMENT,
place_id int NOT NULL,
longitude DOUBLE(18,18) SIGNED,
latitude DOUBLE(18,18) SIGNED,
Primary Key (geo_data_id),
Foreign Key (place_id) References place (place_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
When I try to insert data into the geo_data table using
Insert into geo_data (place_id, longitude, latitude) Values (1, 1.2, 3.4);
I receive the following error message:
Error: ER_WARN_DATA_OUT_OF_RANGE: Out of range value for column 'longitude' at row 1
I guess I am missing something here, since I don't believe 1.2 could in any way be out of range of a Double(18,18). So what on earth is going on here?
Your column is defined as DOUBLE(18,18). The first number is the scale (the total number of digits in the whole number, including decimals); the second is the precision (the number of decimal positions).
Giving the same value to both the scale and precision means that your value cannot be greater than 1 (all 18 digits are decimals).
You want to decrease the precision to something smaller in order to leave room for non-decimal digits, like: DOUBLE(18, 6), which gives you 12 non-decimal positions.

Why does Diesel fail to migrate a PostgresSQL database when the columns specify a length? [duplicate]

I am experimenting with PostgreSQL coming from SQL using MySQL and I simply wish to create a table with this piece of code which is valid SQL:
CREATE TABLE flat_10
(
pk_flat_id INT(30) DEFAULT 1,
rooms INT(10) UNSIGNED NOT NULL,
room_label CHAR(1) NOT NULL,
PRIMARY KEY (flat_id)
);
I get the error
ERROR: syntax error at or near "("
LINE 3: pk_flat_id integer(30) DEFAULT 1,
I have conducted searches on the web and found no answer and I cant seem to find an answer in the PostgreSQL manual. What am I doing wrong?
I explicitly want to set a limit to the number of digits that can be inserted into the "pk_flat_id" field
I explicitly want to set a limit to the number of digits that can be inserted into the "pk_flat_id" field
Your current table definition does not impose a "size limit" in any way. In MySQL the parameter for the intdata type is only a hint for applications on the display width of the column when displaying it.
You can store the value 2147483647 in an int(1) without any problems.
If you want to limit the values to be stored in an integer column you can use a check constraint:
CREATE TABLE flat_10
(
pk_flat_id bigint DEFAULT 1,
rooms integer NOT NULL,
room_label CHAR(1) NOT NULL,
PRIMARY KEY (flat_id),
constraint valid_number
check (pk_flat_id <= 999999999)
);
The answer is that you use numeric or decimal types. These are documented here.
Note that these types can take an optional precision argument, but you don't want that. So:
CREATE TABLE flat_10
(
pk_flat_id DECIMAL(30) DEFAULT 1,
rooms DECIMAL(10) NOT NULL,
room_label CHAR(1) NOT NULL,
PRIMARY KEY (pk_flat_id)
);
Here is a SQL Fiddle.
I don't think that Postgres supports unsigned decimals. And, it seems like you really want serial types for your keys and the long number of digits is superfluous.
Changing integer to numeric works.
CREATE TABLE flat_10
(
pk_flat_id bigint DEFAULT 1,
rooms numeric NOT NULL,
room_label CHAR(1) NOT NULL,
);

How can I set a size limit for an "int" datatype in PostgreSQL 9.5

I am experimenting with PostgreSQL coming from SQL using MySQL and I simply wish to create a table with this piece of code which is valid SQL:
CREATE TABLE flat_10
(
pk_flat_id INT(30) DEFAULT 1,
rooms INT(10) UNSIGNED NOT NULL,
room_label CHAR(1) NOT NULL,
PRIMARY KEY (flat_id)
);
I get the error
ERROR: syntax error at or near "("
LINE 3: pk_flat_id integer(30) DEFAULT 1,
I have conducted searches on the web and found no answer and I cant seem to find an answer in the PostgreSQL manual. What am I doing wrong?
I explicitly want to set a limit to the number of digits that can be inserted into the "pk_flat_id" field
I explicitly want to set a limit to the number of digits that can be inserted into the "pk_flat_id" field
Your current table definition does not impose a "size limit" in any way. In MySQL the parameter for the intdata type is only a hint for applications on the display width of the column when displaying it.
You can store the value 2147483647 in an int(1) without any problems.
If you want to limit the values to be stored in an integer column you can use a check constraint:
CREATE TABLE flat_10
(
pk_flat_id bigint DEFAULT 1,
rooms integer NOT NULL,
room_label CHAR(1) NOT NULL,
PRIMARY KEY (flat_id),
constraint valid_number
check (pk_flat_id <= 999999999)
);
The answer is that you use numeric or decimal types. These are documented here.
Note that these types can take an optional precision argument, but you don't want that. So:
CREATE TABLE flat_10
(
pk_flat_id DECIMAL(30) DEFAULT 1,
rooms DECIMAL(10) NOT NULL,
room_label CHAR(1) NOT NULL,
PRIMARY KEY (pk_flat_id)
);
Here is a SQL Fiddle.
I don't think that Postgres supports unsigned decimals. And, it seems like you really want serial types for your keys and the long number of digits is superfluous.
Changing integer to numeric works.
CREATE TABLE flat_10
(
pk_flat_id bigint DEFAULT 1,
rooms numeric NOT NULL,
room_label CHAR(1) NOT NULL,
);

Create VARCHAR FOR BIT DATA column

I am trying to create a SQL table in Netbeans 8.0 with one of its columns meant to store a byte[] (so VARBINARY is the type I am looking for). The wizard for the creation of a new table offers me the option of VARCHAR FOR BIT DATA, which should work, but it raises a syntax error when creating the table:
create table "BANK".Accounts
(
id NUMERIC not null,
pin VARCHAR FOR BIT DATA not null,
primary key(id)
)
The error is due to the presence of the word FOR, so I manually change the statement so that it is
create table "BANK".Accounts
(
id NUMERIC not null,
pin "VARCHAR FOR BIT DATA" not null,
primary key(id)
)
but now the problem is that the type does not exist. Any ideas?
Thank you.
Here's the manual page for VARCHAR FOR BIT DATA: http://db.apache.org/derby/docs/10.10/ref/rrefsqlj32714.html
Note the section that says:
Unlike the case for the CHAR FOR BIT DATA type, there is no default length for a VARCHAR FOR BIT DATA type. The maximum size of the length value is 32,672 bytes.
So the problem is that you haven't specified a length.
If your byte array is, say, 256 bytes long, you could specify
pin VARCHAR (256) FOR BIT DATA NOT NULL,
You might also consider using BLOB if that fits your requirements. You can see all the Derby data types here: http://db.apache.org/derby/docs/10.10/ref/crefsqlj31068.html

How do I set the precision and scale in SQL (access)

I am trying to create a table in Access.
I have the following code:
CREATE TABLE Class Enrollement (
OfferNo INTEGER PRIMARY KEY,
StdNo Text(9) NULL,
EnrGrade Decimal(2) Percision(8) scale(4) NULL
);
EnrGrade needs to be a decimal, Precision of 8, Scale of 4, and 2 decimal places.
The last line of code is not correct. How would I do this?
I believe you're looking for:
Where the first value is the precision (number of decimal digits, followed by scale, or numbers after the decimal)
CREATE TABLE ClassEnrollment (
OfferNo INTEGER PRIMARY KEY,
StdNo Text(9) NULL,
EnrGrade Decimal(8, 2) NULL
);
You must enable ANSI-92 Query Mode. After that in your query you can write:
CREATE TABLE Offering (
OfferNo INTEGER PRIMARY KEY,
StdNo Text(9) NULL,
EnrGrade Decimal(8,4) NULL
);
Precision of 8, Scale of 4, and 2 decimal places
These requirements appear contradictory. A decimal column with a precision of 8 and a scale of 4 can store up to 4 decimal places.
Perhaps the intention of the spec is to display at least two decimal places? e.g.
SQL DDL:
CREATE TABLE ClassEnrollement (
OfferNo INTEGER PRIMARY KEY,
StdNo NVARCHAR(9),
EnrGrade DECIMAL(8, 4)
);
SQL DML:
SELECT OfferNo, StdNo,
FORMAT$(ClassEnrollement, '0.00##')
AS ClassEnrollement__formatted
FROM ClassEnrollement;
Or perhaps the extra numeric scale is to enable custom rounding? The DECIMAL type exhibits rounding by trucation, a feature often missed because all other numeric types exhibit bankers' rounding. A rule of thumb is to store an extra place of numeric scale so that the inherent rounding, whatever it is, does not affect the raw value being stored, enabling custom rounding to be applied later. Two extra may simply be over-engineering ;)