Set range of numbers column - mysql

I need to set a column that can only accept integers ranging from 0 to 10 inclusive in SQL. It is for a rating system.
My current method is ratingSore int(2,0) not null
Will this method work, as I will also need to find the average rating using this column
I am afraid that if I try to find the average, it will round to an integer instead of giving me decimals

With MySQL 8.0.16 or higher, you can define a check constraint:
create table sometable (
-- ...
ratingSore int not null check (ratingSore between 0 and 10)
-- ...
)
See: example on dbfiddle
Important: MySQL versions before 8.0.16 supported check constraints in the syntax, but ignored them.

EDIT: as said by Mark, recent versions of MySQL (8.0.16+) support a CHECK constraint.
Regarding the average computation, the int column type only affect the data stored in this column.
When you will ask to compute the average, you will be able to get decimals as this will only be a "result", not stored in the column.

Your syntax is not correct. The int data type does not take two parameters. MySQL allows one, which is for display purposes only -- the parameter does not affect what actually gets stored.
You seem to want a numeric/decimal data type:
ratingSore numeric(2, 0) not null
The "2" says there. are two digits of precision. The "0" says that none of the digits are after the decimal point. Together, these say that the column stores any integer value between 0 and 99 -- which seems to be what you are asking for.

Related

Incorrect decimals appearing in SUM MySQL

I have the following SQL query.
SELECT SUM(final_insurance_total) as total
FROM `leads`
GROUP BY leads.status
I have a single row of data in the lead table with a value for final_insurance_total of 458796. The data type for final_insurance_total is float.
For some reason, MySQL is summing a single row as "458796.375".
If I change the query to
SELECT (final_insurance_total) as total
FROM `leads`
GROUP BY leads.status
the correct value is returned. What in the world is going on?
The FLOAT and DOUBLE types in MySQL (as well as in other databases and programming language runtimes) are represented in a special way, which leads to the values stored being approximations, not exact values. See MySQL docs, as well as general information on floating-point arithmetics.
In order to store and operate with exact values, use the type DECIMAL (see https://dev.mysql.com/doc/refman/5.1/en/precision-math-decimal-characteristics.html).
EDIT: I have run some tests, and while floating-point precision errors are quite common, this particular one looks to be specific to the implementation of SUM() in MySQL. In other words, it is a bug that has been there for a long time. In any case, you should use DECIMAL as your field type.
FLOAT does not guarantee precision where any calculation is made. If you use a simple SELECT, no calculation is made, so you get the original value. But if you use SUM(), even with one row, at least one addition is executed (0 + current_value).
Do you really need FLOAT? For example, if you have 2 decimal digits, you could use INT and multiply all values by 100 before all INSERTs. When SELECTing results, you will divide by 100.
If the user is not a sysadmin and cannot change the datatype of the field such as FLOAT, the user can use CAST to produce the desired output.

Can I use NUMERIC instead of BIGINT?

I have an old database table with column, which type is BIGINT. There's a lot of stored procedures and views that use that table and that column.
For some reason I need to change the type of that column to NUMERIC(38,0).
Is it safe to do it? Should I cast in any stored procedure and view existing BIGINT to NUMERIC(38,0)?
According to me numeric data type is identical with decimal which represents a fixed precision number, which will scale numeric data from -10^38 +1 through 10^38 –1
I don't think that the number types you mention are using fixed precision number and therefore BIGINT is probably the most efficient way to store the number especially if you want to perform some computation in your application.
I don't see really any use for computation with those number and therefore you may even use a string of appropriate length which requires more space in the database but you may be able to allow grouping characters in the numbers.
using BIGINT datatype instead of string you can create efficient indexes.
As you write you're already using numeric datatype and therefore if you upgrade to SQL 2008R2 / 2012 you should consider switching to BIGINT as you don't need fraction in your number. The BIGINT data type is intended for use when integer values might exceed the range that is supported by the int data type.
EDIT:
You can change the data type from BIGINT to NUMERIC(38,0) but be ensure that a Arthimetic overflow error shouldn't occur while converting.
Yes, it is.
According to this table on MSDN an numeric(38,0) has an higher capacity than a bigint.
I calculated the maximum values based on the numbers in the matrix:
9223372036854775808 (bigint, 2^63-1, 8 bytes)
1000000000000000000000000000000000000000 (numeric(38,0), 10^38–1, 17 bytes)

Mysql zerofill length different from default field length

I am using MySQL and InnoDB.
I need to store a numeric id which length can vary but needs to be at least 10. For instance:
0000000001
11111111111 are both correct values.
Currently, I my column has the following attributes: bigint(10), unsigned zerofill. This works: if I try to insert "1" then "0000000001" is actually inserted, and if I insert a bigger number (with length>10) it also works.
So, in the end, what is the purpose of the length attribute in the field definition? I thought it was the maximum length, but apparently it is not the case...? Or is my current implementation going to crash eventually?
The length attribute is just a hint for MySQL how to format select query results in the command line client. Nothing more. It has no effect on the datatype actually. An int is an int with 4 bytes, no matter what length you specify. Same of course for bigint, but with 8 bytes.

MySQL Join/Comparison on a DATETIME column (<5.6.4 and > 5.6.4)

Suppose i have two tables like so:
Events
ID (PK int autoInc), Time (datetime), Caption (varchar)
Position
ID (PK int autoinc), Time (datetime), Easting (float), Northing (float)
Is it safe to, for example, list all the events and their position if I am using the Time field as my joining criteria? I.e.:
SELECT E.*,P.* FROM Events E JOIN Position P ON E.Time = P.Time
OR, even just simply comparing a datetime value (taking into consideration that the parameterized value may contain the fractional seconds part - which MySQL has always accepted) e.g.
SELECT E.* FROM Events E WHERE E.Time = #Time
I understand MySQL (before version 5.6.4) only stores datetime fields WITHOUT milliseconds. So I would assume this query would function OK. However as of version 5.6.4, I have read MySQL can now store milliseconds with the datetime field.
Assuming datetime values are inserted using functions such as NOW(), the milliseconds are truncated (<5.6.4) which I would assume allow the above query to work. However, with version 5.6.4 and later, this could potentially NOT work. I am, and only ever will be interested in second accuracy.
If anyone could answer the following questions would be greatly appreciated:
In General, how does MySQL compare datetime fields against one another (consider
the above query).
Is the above query fine, and does it make use of indexes on the time
fields? (MySQL < 5.6.4)
Is there any way to exclude milliseconds? I.e. when inserting and in
conditional joins/selects etc? (MySQL > 5.6.4)
Will the join query above work? (MySQL > 5.6.4)
EDIT
I know i can cast the datetimes, thanks for those that answered, but i'm trying to tackle the root of the problem here (the fact that the storage type/definition has been changed) and i DO NOT want to use functions in my queries. This negates all my work of optimizing queries applying indexes etc, not to mention having to rewrite all my queries.
EDIT2
Can anyone out there suggest a reason NOT to join on a DATETIME field using second accuracy?
It seems that MySQL developers didn't want to break backward compatibility, so to use milliseconds, you explicitely have to change your tables, sql, etc. to use this feature:
http://dev.mysql.com/doc/refman/5.6/en/date-and-time-functions.html#function_now
NOW([fsp])
As of MySQL 5.6.4, if the fsp argument is given to specify a
fractional seconds precision from 0 to 6,the return value includes a
fractional seconds part of that many digits. Before 5.6.4, any
argument is ignored.
http://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html
MySQL 5.6.4 and up expands fractional seconds support for TIME,
DATETIME, and TIMESTAMP values, with up to microseconds (6 digits)
precision:
To define a column that includes a fractional seconds part, use the
syntax type_name(fsp), where type_name is TIME, DATETIME, or
TIMESTAMP, and fsp is the fractional seconds precision. For example:
CREATE TABLE t1 (t TIME(3), dt DATETIME(6)); The fsp value, if given, must be in the range 0 to 6. A value of 0 signifies that there is no fractional part. If omitted, the default precision is 0. (This differs from the standard SQL default of 6, for compatibility with previous MySQL versions.)
Try this query . For question 3 and 4 this will work fine. Still it is not a good practice to use time field for joins
SELECT E.*,P.* FROM Events E JOIN Position P ON date(E.Time) = date(P.Time)
Although i have given you a solution but you will be restricted to insert the same time in different tables. Then you will be able to compare but it is quite difficult because at the same time you can not run two insert queries. So you will have to do some menuall work for this. If you want to read more read this article.
http://billauer.co.il/blog/2009/03/mysql-datetime-epoch-unix-time/

Mysql column with null values - what are the space requirements?

I have a table with quite a lot entries.
I need an additional column with an integer value or null.
The thing is that only very few rows will have that field populated.
So i wonder whether its better to create a seperate table where i link the entries in an 1:1 relation.
I know one integer entry takes 4 bytes in mysql/myisam. If I have the column set to allow null values, and only 100 of 100 000 rows have the field populated, will the rest still consume 4 bytes for every null value?
Or is mysql intelligent enough to set the value where it is populated and just regard everything as null, where nothing is set?
This depends on the ROW_FORMAT value you give when you create your table.
Before version 5.0.3, the default format is set to "REDUNDANT" : any fixed-length field will use the same space, even if it's value is NULL.
Starting with version 5.0.3, the value is set to "COMPACT" : NULL values will never use any space in your database.
You can do an ALTER TABLE to be sure to use the correct format :
ALTER TABLE ... ROW_FORMAT=COMPACT
More details here :
http://dev.mysql.com/doc/refman/5.1/en/data-size.html
As far as my understanding goes, once you declare a field as int, 4 bytes will be set aside for it. So, for 100,000 rows you are looking at ~ 400 KB of space.
If space is a constraint, then separate table will be better. On the other hand, if performance is a criteria, then you'll have to take into account how many times that field is queried and whether it is checked for existence or non-existence. In either case, you'll need a join. If you want to check whether the field is set you can use inner join, which will be slower than single table query. If you want to check for non-existence, you'll need left/right outer join which will be slower than inner join.
It will use bitfields to store nulls so it may need less than one byte. But, even if it did - who cares, unless you are using 3.5" floppies to store your backend in ;-)
NULL in MySQL (Performance & Storage)