Query update issue - mysql

I m just confuse in this Query and i don't know how to solve this if you have any idea about this please help me or helps are definitely appreciated
I have table structure like this and test column contain 3 value
UPDATE `test` SET test = test -3
when i execute this Query the result will be show like this
UPDATE `test` SET test = test -4
But when i execute this query the result will not proper save in test column like this
0 result required or i don't need any subtract value also

Apparently you are using the BIGINT UNSIGNED data type. If you want to store negative numbers, you need to change it to a regular signed BIGINT (Also be sure to set it to NULL or NOT NULL as required):
ALTER TABLE test
MODIFY COLUMN test BIGINT;
UPDATE: If you actually want to store 0 instead of -4 in your example, you can do so using the GREATEST() function like this:
UPDATE `test` SET test = GREATEST(CAST(test AS SIGNED) - 4,0)

The problem is most likely due to the fact that your bigint is unsigned.
Per the documentation, an unsigned bigint is
A large integer. The signed range is -9223372036854775808 to
9223372036854775807. The unsigned range is 0 to 18446744073709551615.
Notice the unsigned range and how it is your number - 3 (4 comes from getting from 0 to xxx15 I believe)
So, you should only need to update your column to be a bigint that is not unsigned (signed) and this should work.
ALTER TABLE test MODIFY COLUMN test BIGINT SIGNED;
UPDATE
If you want to keep the BIGINT UNSIGNED so that you cannot have negative numbers, then you could write a trigger to force a 0, or you could just make your query something like this:
UPDATE test
SET test = CASE WHEN test >= value THEN test-value ELSE 0 END
Basically, if the value attempting to be subtracts is more than the current value, then just set the value to 0, otherwise perform the subtraction.

As per this question: MySQL: bigint Vs int
bigint's maximum value is 18,446,744,073,709,551,615
You're wrapping around to the highest value when you subtract from 0, since your bigint is unsigned.

Related

Should I input 2 digit numbers in TINYINT?

I need a column that can store values from -1 (negative 1) to +15 (positive 15).
I am using a TINYINT(2) column at the moment and it works just fine.
I need to know if this is ideal and safe to use because I read online that TINYINT should ONLY be used for binary value such as 1 and 0.
MySQL TINYINT has a storage of 1 byte.
Unsigned value in range 0 to 255 or signed value of range -128 to 127 can be stored.
Also note that 2 in TINYINT(2) does not limit the length of your value to 2 digits. more info in this link - What is the size of column of int(11) in mysql in bytes?
TINYINT will store your value perfectly fine; however it will not guarantee that it will be correct (exactly in that range). Please note that (2) is just related to padding when selecting via the command line and it has nothing to do with the limit. Normally you do not need it at all. TINYINT (signed) will store values from -128 to 127 regardless if you add (n) at the end of it or not.
If you want to make sure that the value is always exactly in the range between -1 and 15, you have two options:
Using CHECK constraint over the existing TINYINT (recommended solution):
CREATE TABLE tiexample(
val TINYINT NOT NULL,
CONSTRAINT val_range CHECK(val>=-1 AND val<=15)
);
INSERT INTO tiexample(val) VALUES(122);
ERROR 4025 (23000): CONSTRAINT `val_range` failed for `test`.`tiexample`
INSERT INTO tiexample(val) VALUES(12);
Query OK, 1 row affected (0.001 sec)
Listing all values as ENUM:
CREATE TABLE tiexample(
val ENUM("-1","0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15") NOT NULL,
CONSTRAINT val_range CHECK(val<>"")
);
INSERT INTO tiexample(val) VALUES("122");
ERROR 4025 (23000): CONSTRAINT `val_range` failed for `test`.`tiexample`
INSERT INTO tiexample(val) VALUES("12");
Query OK, 1 row affected (0.001 sec)
Note that using this method you must insert the values with quotes (like "8", not just 8). Also first it may seem strange that we use CHECK constraint here but it is needed because by default inserting invalid value on ENUM field will insert an empty string in the table (not NULL - it's an empty string). You can get around that issue and skip the CHECK constraint if you use this sql mode before inserting into the table:
SET SQL_MODE = 'Traditional';
Personally I would not struggle with the ENUM type. It is more suitable for different use-cases.
Footnote: CHECK constraints are available and working only in MySQL MySQL 8.0.16+ and MariaDB 10.2.1+. Prior versions accept the constraint but never use it (it will ignore them).

MySQL BIGINT UNSIGNED value is out of range

I have multiple triggers on my database which is updating a statistics table. This table has a BIGINT UNSIGNED column, but on updating the table, I sometimes catch the error: BIGINT UNSIGNED value out of range. I guess the value that is being inserted results in a smaller value then 0, but that seems very strange behavior in my opinion, given the IF check in my statements.
The statement I use:
UPDATE TABLE SET FileSize=774982 WHERE ID=10;
The trigger causing the problem is defined as:
IF (OLD.FileSize <> NEW.FileSize) THEN
INSERT INTO Statistics VALUES('FileSize', 0, 0, 0)
ON DUPLICATE KEY UPDATE Value = IF((Value - OLD.FileSize) < 0, 0, Value - OLD.FileSize);
INSERT INTO Statistics VALUES('FileSize', 0, 0, NEW.FileSize)
ON DUPLICATE KEY UPDATE Value = Value + NEW.FileSize;
END IF
As you can see, I only update the statistics table if the FileSize has really changed (OLD.FileSize <> NEW.FileSize). Besides, I have also added a check to make sure I don't get values below 0 with IF((Value - OLD.FileSize) < 0, 0, Value - OLD.FileSize). Though, the value get's an out of range error and it seems very unlikely that it goes out the upper bound of the BIGINT UNSIGNED, given the fact that the following update statements work? The Error is not always triggered it seems...?
The trigger consists of two statements as you can see. The simple explanation is that the first statement removes the old file size form the statistics table and the second statement is adding the new file size to the table. (This calculates the difference and updates the statistics table correctly)
So, I don't understand how I can get the error: Database error: BIGINT UNSIGNED value is out of range in '(DB.Statistics.Value - OLD.FileSize)' (error code: 1690, State: 22003)
The new and old file sizes are 244662 and 774982 respectively (in bytes)
When you subtract an UNSIGNED value, the result is also UNSIGNED, which means it can't be negative. You're getting the error when you try to calculate Value - OLD.FileSize in the IF() condition.
Instead of subtracting, use a comparison.
INSERT INTO Statistics VALUES('FileSize', 0, 0, 0)
ON DUPLICATE KEY UPDATE Value = IF(Value < OLD.FileSize, 0, Value - OLD.FileSize);

MySQL Variable Returning Incorrect Value

The Issue
I have a stored proc in a DB server that's bringing back a value of 5064803 when that record does not exist and the value should be 5064800 as per the query that builds the value of the variable.
I'm not sure if this is an issue with the value being of the FLOAT data type and the value in the record of the table ending in a double-zero or what but I cannot figure it out easily.
The table data types match those from the sensors that are set but this particular value from this sensor never actually gets set to a data type and it's usually always either a 1-8 digit INT with no decimal but I'd like to keep the data types the same as the correlated sensor just in case.
I've broke down the proc and I'm able to recreate the problem easily so I will post the detail below for those that may be able to help me figure out the issue and any workaround, etc.
The SQL Data
Create Table
delimiter $$
CREATE TABLE `number` (
`TimeInt` varchar(10) NOT NULL,
`TimeStr` datetime NOT NULL,
`IsInitValue` int(11) NOT NULL,
`Value` float NOT NULL,
`IQuality` int(11) NOT NULL,
UNIQUE KEY `uk_Times` (`TimeInt`,`TimeStr`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8$$
Insert Data
INSERT INTO `Number` (`TimeInt`,`TimeStr`,`IsInitValue`,`Value`,`IQuality`) VALUES ('1502618950','2017-08-13 10:09:10',1,5064800,0);
INSERT INTO `Number` (`TimeInt`,`TimeStr`,`IsInitValue`,`Value`,`IQuality`) VALUES ('1502618796','2017-08-13 10:06:36',0,5064800,3);
INSERT INTO `Number` (`TimeInt`,`TimeStr`,`IsInitValue`,`Value`,`IQuality`) VALUES ('1502617167','2017-08-13 09:39:27',1,5063310,0);
INSERT INTO `Number` (`TimeInt`,`TimeStr`,`IsInitValue`,`Value`,`IQuality`) VALUES ('1502613355','2017-08-13 08:35:55',0,5063310,3);
INSERT INTO `Number` (`TimeInt`,`TimeStr`,`IsInitValue`,`Value`,`IQuality`) VALUES ('1502612814','2017-08-13 08:26:54',1,0,0);
INSERT INTO `Number` (`TimeInt`,`TimeStr`,`IsInitValue`,`Value`,`IQuality`) VALUES ('1502609015','2017-08-13 07:23:35',0,0,3);
The SQL Query Breakdown
SET #bStartTime = '2017-08-13 09:24:16';
SET #bEndTime = '2017-08-13 10:06:31';
SET #LastNumber = (SELECT Value FROM Number ORDER BY TimeStr DESC LIMIT 1);
SET #NowNumber = (SELECT Value FROM Number WHERE TimeStr BETWEEN #bStartTime AND #bEndTime ORDER BY TimeStr DESC LIMIT 1);
SELECT #NowNumber;
SELECT #LastNumber;
Recreating the Issue
So based on The SQL Query Breakdown above, once all the data is in the table and then I run the queries within the SELECT queries alone within the #NowNumber and/or #LastNumber variables, I get the correct result of 5064800. However, if I run the entire SET statements for both of those to have it set the query and then just do a SELECT of those variable, it brings back the wrong result of 5064803.
So for example if I run SELECT Value FROM Number ORDER BY TimeStr DESC LIMIT 1 then the correct value is returned. If I run SET #LastNumber = (SELECT Value FROM Number ORDER BY TimeStr DESC LIMIT 1); and then run SELECT #LastNumber; I get the incorrect value returned.
Server System Specs
This particular MySQL Server is running the x86 version of 5.5.50 on Windows Server 2008 with 144 GB of RAM for some quick specs.
Question
I'd like to know what is causing this, and if there is a workaround to the problem either with or without changing the data type of the column assuming that's the issue when it's returned as a variable rather than just a straight query result.
I'll be happy to disclose more technical specs of the environment if needed but I've included what I think it important for the question. Perhaps this is a version bug or there's something obvious that causes this that I cannot see easily so I'm hoping someone can help me with this or explain why this is or is not possible with MySQL.
Sorry, declares can only be used in stored procedures in MySQL. I found this article which may help. It explains how MySQL rounds when storing digits and recommends using doubles. Try changing your floats to doubles.
MySql FLOAT datatype and problems with more then 7 digit scale

Why * is Inserted in SQL

This happened when I was just testing.
I've created a table as
Create Table Test_Table
(
Field_char char(1)
);
When I want to insert value with code
Insert Into Test_Table(Field_char)
Select 13;
It inserts '*' in the column. For single digits it inserts them as it is. If the length is modified from 1 to 2, similar thing happen for 3 digits input such as 100 etc.
Why is this?
In your create statement you set the length of Field_char to 1 (char(1)). This means that your entries must have a length smaller or equal to 1. valid entries are 1,2 etc. Invalid entries are 12, 13 as they are longer than 1 char -> * is a placeholder to indicate invalid values.
EDIT: (Thanks To Vladimir)
To be more precise take a look here.
Truncating and Rounding Results
[...] Conversions to char, varchar, nchar, nvarchar, binary, and varbinary are truncated, except for the conversions shown in the following table.
There we have the following entry:
From data type int to data type char result *
where * = Result length too short to display
When you are writing
Insert Into Test_Table(Field_char)
Select 13;
The it is converting int to char. So your 13 is converted into *. If you want you can check by writing
select CONVERT(char(1),13)
If you want to see the result as 13 then you need to put that in single inverted comma like this:
Insert Into Test_Table(Field_char)
Select '13';
And also you need to increase the size of column as char(1) can hold only one character.
SQL FIDDLE DEMO
It simply Convert Int to Char
for Example
select CONVERT(char(1),13)
it will give *
Sql Implicitly convert int to char which is you column type..

Why does TINYINT(1) function as a boolean but INT(1) does not?

Why does TINYINT(1) work as a boolean? The way I understood the official docs, the (1) should mean it has a display width of 1, so if I store 56 in it, I thought it should print 5. But for some reason it always prints either 1 or 0.
And another case is if I store 56 in an INT(1), then it prints 56 (at least according to SQLFiddle). What's going on here?
The (1) in parentheses for a MySQL integer type has nothing to do with the range of values accepted by the data type, or how it is stored. It's only for display.
See also my answer to Types in MySQL: BigInt(20) vs Int(20) etc.
TINYINT is no different from TINYINT(1) or TINYINT(2) or TINYINT(64). It's an 8-bit signed integer data type, and it accepts any 8-bit integer value from -128 to 127.
mysql> create table b (i tinyint(1));
mysql> insert into b values (42);
mysql> select * from b;
+------+
| i |
+------+
| 42 |
+------+
For convenience, MySQL supports an alias for BOOL, which is replaced immediately by TINYINT(1).
mysql> create table b2 (i bool);
mysql> show create table b2;
CREATE TABLE `b2` (
`i` tinyint(1) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
As I said, the use of (1) means almost nothing, it's only a convention so that if you see TINYINT(1) it's reasonable to assume the column is intended to be used as a boolean. But nothing in MySQL prevents you from storing other integer values in it.
If you want a column to accept only 0 or 1, you can use BIT(1):
mysql> create table b3 (i bit(1));
mysql> insert into b3 values (0), (1);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> insert into b3 values (-1);
ERROR 1406 (22001): Data too long for column 'i' at row 1
mysql> insert into b3 values (2);
ERROR 1406 (22001): Data too long for column 'i' at row 1
This doesn't save any space compared to TINYINT though, because the storage for a given column rounds up to the nearest byte.
PS: Despite answer from #samdy1, TINYINT does not store strings '0' or '1' at all, it stores integers 0 or 1, as well as other integers from -128 to 127. There is no need to quote integers in SQL, and I am often puzzled why so many developers do.
TINYINT columns can store numbers from -128 to 127.
TINYINT(1) is a bit weird though. It is (perhaps because it is supposed to act as a BOOLEAN datatype), returns only 0 and 1 in some context, while it still keeps the stored (-128 to 127) values.
(Correction: I only see this weird behaviour in SQL-Fiddle and not when accessing MySQL locally so it may well be a SQL-Fiddle quirkiness, possibly related to the quivalence with BOOLEAN) and not a MySQL problem.
See the SQL-Fiddle
CREATE TABLE test
( i TINYINT(1)
) ;
INSERT INTO test
(i)
VALUES
(0), (1), (6), (120), (-1) ;
Where we get (only in SQL-Fiddle, not if we access MySQL otherwise!):
SELECT i
FROM test ;
i
-----
0
1
1
1
1
but:
SELECT CAST(i AS SIGNED) i2
FROM test ;
i2
-----
0
1
6
120
-1
This is a mysql Jdbc configuration subject.
You can config mysql jdbc to convert TinyInt(1) to Boolean or Integer through set jdbc url config property "tinyInt1isBit" to "true" (default) or "false".
from: https://dev.mysql.com/doc/connector-j/en/connector-j-reference-configuration-properties.html
Should the driver treat the datatype TINYINT(1) as the BIT type (because the server silently converts BIT -> TINYINT(1) when creating tables)?
Default: true
The engine is smart enough to know that TINYINT(1) and BOOL are the same. However INT(1) only affects the Display Width instead of the underlying storage size. Display width only comes into play when the value is less width then the display width. Then it gets padded.
http://alexander.kirk.at/2007/08/24/what-does-size-in-intsize-of-mysql-mean/
As I understand it, TINYINT(1) can only hold '0' or '1' (from own experience).
Thus, one can assume that the '0' or '1' is translated into true or false.