I have a simple insert to the table with a smallint(6). Now on our newest schema, the table structure gives an overload error when inserting a value over 32767 into that field.
At the same time on the same instance and with the same table structure inserted values are truncated to 32767 when getting over that max. limit.
My question is, what setting or flag might cause this behaviour? I know there are SQL modes and so on, but those are global settings. We have the same environment for both of those.
Are there some user-specific settings about this?
Mysql version 5.7.39
I have tried to find if there is user or schema based settings somewhere.
Disable STRICT SQL Mode.
DEMO
create table test (id serial primary key, val smallint);
insert into test (val) select 100;
set session sql_mode = '';
insert into test (val) select 100000;
show warnings;
Level
Code
Message
Warning
1264
Out of range value for column 'val' at row 1
set session sql_mode = 'STRICT_TRANS_TABLES';
insert into test (val) select 200000;
Out of range value for column 'val' at row 1
show warnings;
Level
Code
Message
Error
1264
Out of range value for column 'val' at row 1
select * from test;
id
val
1
100
2
32767
fiddle
Related
If i modify the max number of allowed digits in MYSQL 5.7 from double(8,2) to double(12,2), is the change immediate or will it need to process all rows??
You can test this to see if it can be changed as an instant change:
mysql> create table mytable (id serial primary key, d double(8,2));
mysql> alter table mytable modify column d double(25,2), algorithm=inplace, lock=none;
Query OK, 0 rows affected, 1 warning (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 1
The options algorithm=inplace, lock=none mean you want the alter to run as an instant change, without performing a table copy. By default, MySQL runs the DDL change in that mode if the change can be done in that mode.
If you request it explicitly, but the change cannot be done in that mode, then you'll get an error.
For example:
mysql> alter table mytable modify column d float(8,2), algorithm=inplace, lock=none;
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported.
Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.
In this example I'm changing the 8-byte DOUBLE to a 4-byte FLOAT. Any change to the size of a data type cannot be done without copying the table. So the request to do it as an instant change fails and the error shown is returned.
So if you're in doubt about whether a given change can be done instantly, you can use this method to test it. You don't have to do the test against your production table! I did this test on my local instance, without even adding any data to the table. I just created an empty table as I showed above, and ran the DDL.
You should read https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html for details on which types of DDL changes can be done inplace.
As written in the MySQL Reference Manual all ALTER Table statements needs processing time. On top of this MySQL will convert the data:
For data type changes using CHANGE or MODIFY, MySQL tries to convert existing column values to the new type as well as possible.
Therefore all Columns will be visited.
Beside the fact that specifying number of digits for floating point data types is deprecated, a change from double(8,2) to double(12,2) doesn't change the column type, it is still a double precision 8-byte number, so not even a single row will change it's value.
Example:
CREATE TABLE t1 (a double(6,2));
INSERT INTO t1 VALUES (1234.56);
# change the precision
ALTER TABLE t1 change a a double(4,2);
INSERT INTO t1 VALUES (1234.56);
ERROR 1264 (22003): Out of range value for column 'a' at row 1
SELECT a FROM t1;
+---------+
| a |
+---------+
| 1234.56 |
+---------+
Even if 1234.56 doesn't fit in double(4,2) it is still unchanged.
This is something that I stumbled across multiple projects, and I feel I'm reinventing the wheel every time:
I have a table that stores user data. Whenever the user is created, I create one row on the table. This row has several NULL fields on creation, because the user just informed some critical information (and other non-critical info is going to be filled later).
But, when the user completes the filling of the data, I want to enforce this cols to be NOT NULL.
Is there any way to make a column NULL for INSERT, but NOT NULL for UPDATE that does not involves triggers? Or any other clever solution?
Thank you
CREATE TABLE users ( regular_column SOMETYPE NOT NULL,
smart_column SOMETYPE NULL,
completed ENUM('no', 'yes') NOT NULL DEFAULT 'no',
CHECK ((completed = 'no') OR (smart_column IS NOT NULL)) );
This row has several NULL fields on creation, because the user just informed some critical information (and other non-critical info is going to be filled later).
In this moment completed = 'no', CHECK constraint is TRUE, smart_column may be NULL.
when the user completes the filling of the data, I want to enforce this cols to be NOT NULL.
In this moment completed = 'yes', and CHECK constraint does not allow NULL value in smart_column.
I.e. setting completed column to 'yes' fixes smart_column - you may alter it but cannot set it to NULL. And you cannot set completed to 'yes' until smart_column is set to a value.
If you use column options in your CREATE TABLE statement, there's no way a column can be both NULLable and NOT NULL. There's no way to distinguish between inserts and updates.
The alternative could be to let the column be nullable, but add a trigger on UPDATE that throws an exception (called a SIGNAL in MySQL terminology) if the column is still NULL after the update.
Here's a quick demo:
mysql> create table mytable (id int primary key, x int);
Query OK, 0 rows affected (0.05 sec)
mysql> delimiter //
mysql> create trigger notnullonupdate before update on mytable
-> for each row
-> begin
-> if NEW.x IS NULL then
-> signal sqlstate '45000'
-> set message_text = 'x must be updated to non-NULL value';
-> end if;
-> end//
mysql> delimiter ;
mysql> insert into mytable set id = 42, x = null;
Query OK, 1 row affected (0.03 sec)
mysql> update mytable set id = 42;
ERROR 1644 (45000): x must be updated to non-NULL value
Even though this is possible, it's kind of a lot of work.
Most developers would just handle this by writing application code to ensure the value is not null before executing an update. Of course the risk of that is if you forget one of the cases in your app that does an update, or if someone does an ad hoc update in the mysql client, it could cause your data to be in an invalid state and you wouldn't know it.
Currently, I have the MySQL 5.6 version. In this version INT type column will take 0 automatically even by default value is none.
Column = question_status, Type= INT, Default= None
Old query : INSERT INTO tbl_question (question_status) VALUES ('');
Above Query will Run Perfectly on my older version.
Now, I have imported the database into a newer version of MySQL 5.7.2
New query : INSERT INTO tbl_question (question_status) VALUES ('');
Above query is same but it says I have to change the default value of column because column datatype is INT.
if I'll change the default value manually to 0 in the newer version. It will run perfectly.
The problem is I have around 100 tables in a database and many INT Type columns so I cant change default value of every column one by one.
You can select all columns having an INT type with this query:
SELECT * FROM information_schema.columns WHERE table_schema = '<YOUR_DB>' data_type = 'INT'
Then it will be easy to write a simple script for a mass alter.
I have two tables, pattern and pattern_optimized. Some of the fields in the pattern table are defined as BIGINT(20) DEFAULT '-1', which is way too big for the data they hold; Additionally, -1 is used as "not set" (zero is a valid value) - no other negative values are used otherwise.
The pattern_optimized table uses a new data format for these rows, defining them as INT(10) UNSIGNED DEFAULT NULL. I would now like to copy the data from pattern to the pattern_optimized table.
This would be easily done using INSERT INTO pattern_optimized SELECT * FROM pattern, but obviously all negative values are out of range now, resulting in warnings like this:
100 row(s) affected, 64 warning(s):
1264 Out of range value for column 'version' at row 1
1264 Out of range value for column 'triggered' at row 1
...
Records: 100 Duplicates: 0 Warnings: 357
My first idea was to create a BEFORE INSERT trigger as follows:
CREATE TRIGGER `negativeValueFix` BEFORE INSERT ON `pattern_optimized`
FOR EACH ROW
BEGIN
IF new.version < 0 THEN
SET new.version = NULL;
END IF;
-- ...
END
but unfortunately this doesn't help either: The same warning pops up and all values that used to be -1 in the original table become 0 in the new table (instead of NULL, which is - apart from being implemented in the trigger - also the default for the row).
It seems that MySQL converts the value even before the trigger.
I know that I can solve this problem using a temporary table but I'd rather not do that. The pattern table is unpleasantly large and I don't want to do a stored procedure just for that.
Is there any other way or am I missing some simple point?
EDIT: There are quite alot columns in the original table that suffer from the SIGNED problem, so I was hoping to somewhat automate that.
Could you use a case statement? Something like:
INSERT INTO pattern_optimized
SELECT
CASE version
WHEN -1 THEN null
ELSE version
END CASE AS version
FROM pattern
Just add small condition to the SELECT statement, e.g. -
INSERT INTO pattern_optimized(version)
SELECT IF(version < 0, NULL, version) version FROM pattern
...add other fields.
I am creating a INSERT script and I am coming across a problem. There is a middle initial field that is a char(1)
Sometimes the records don't have anything in that field so I put a NULL. This causes a Data too long for column error. I don't want to just put ' ' as that leaves just a blanks space.
Is there another way around this?
It sounds like you may be attempting to insert the string 'NULL' into the char(1) field, rather than an SQL NULL, and you have strict SQL mode enabled, which prevents this being truncated to N.
If you are able, run
SHOW CREATE TABLE <your_table_name>
in the MySQL shell to determine whether your target field accepts NULLs. With no context (are you running this as pure SQL, or connecting to the database from some client program in another langauge?) it's difficult to provide the exact solution, but you may have something like this:
INSERT <your_table_name>
SELECT first_name, 'NULL', last_name
where 'NULL' is simply a string with no special meaning, when what you intend is
INSERT <your_table_name>
SELECT first_name, NULL, last_name
Here's an illustration:
mysql> CREATE TABLE my_table ( middle_initial CHAR(1) NULL );
mysql> INSERT INTO my_table SELECT 'NULL';
mysql> SHOW WARNINGS;
Level Code Message
Warning 1265 Data truncated for column 'middle_initial' at row 1
mysql> SELECT * FROM my_table;
middle_initial
--------------
N
mysql> set sql_mode = 'STRICT_TRANS_TABLES';
mysql> INSERT INTO my_table SELECT 'NULL';
ERROR 1406 (22001) at line 16: Data too long for column 'middle_initial' at row 1
mysql> INSERT INTO my_table SELECT NULL;
mysql> SELECT * FROM my_table;
middle_initial
--------------
N
NULL
Bit of a punt - apologies if no use ...