mysql 5.7 timestamp default insert null error - mysql

I have the following create table statement.
CREATE TABLE `test_table` (
`id` INT(11) NOT NULL,
`field1` varchar(10),
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
);
when I do the following insert, I'll get the erro "Column 'updated_at' cannot be null"
insert into test_table (id, field1, updated_at) values (1234, 'foo', null);
I expected updated_at would just take on the default value in this case.
mysql version 5.7.12
However when I do this in mysql version 5.6, the insert commands works.
Is there a change in the versoin from 5.6 to 5.7? The only difference I thought was 5.7 has NO_ZERO_DATE default to true. But I thought that was only for datetime. Is there a configuration change that I need to make?
It's possible to achieve the result by not passing in updated_at but I don't have over insert statement in this case.

I suspect that this is related to SQL Strict mode - but I can't find the exact quote in the documentation that matches your use case.
Bottom line, you should not be expecting the server to use the default when you provide it with an explicit null value.
If you can't remove the column from the insert list for some reason, a possible workaround is to use the default keyword, which makes your intent unambiguous:
insert into test_table (id, field1, updated_at)
values (1234, 'foo', default);

This error is thrown because explicit_defaults_for_timestamp is enabled. Disabling this will solve the issue
Refer: https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_explicit_defaults_for_timestamp

Related

MYSQL insert null for not null default column

I have curious about why some not null column already set default value, but during insert sql script, it will throw error.
Here is the sample table
drop table if exists `delivery`;
create table `delivery`(
`price` BIGINT not null default 0,
`created_time` TIMESTAMP(6) not null default CURRENT_TIMESTAMP (6)
) ENGINE=INNODB DEFAULT CHARSET=UTF8MB4
;
Let's say, execute the three statement below, only the second statement will not throw error
insert into `delivery` (`price`,`created_time`) values (null, null);
insert into `delivery` (`price`,`created_time`) values (1, null);
insert into `delivery` (`price`,`created_time`) values (null, now());
So does it have anyway to insert null for bigint datatype column and make it execute success? And any ideas for the logic behind.
You can't insert null values since you have NOT NULL constraints on the columns.
The first and third statement throw an error since you are trying to insert a null value into the column price and/or created_time, and that clearly doesn't satisfy the constraint(s).
If you really want to allow null values, then remove the NOT NULL constraint on the column(s).
Alternatively, you could sucessfully run your SQL statements as shown below:
insert into `delivery` () values ();
insert into `delivery` (`price`) values (1);
insert into `delivery` (`created_time`) values (now());
select * from `delivery`;
Result:
price created_time
----- --------------------------
0 2020-04-16 09:48:23.505147
1 2020-04-16 09:48:25.549202
0 2020-04-16 09:48:26.0
EDIT:
The second query actually succeeds in MySQL 5.7; it silently ignores the explicit null value and uses the default value.
It seems that the behavior was fixed in MySQL 8.x since it fails now (as it should).

SQL Query not working on RDS

Using MySQL 5.6.40
This is the table definition:
CREATE TABLE IF NOT EXISTS `updated_tables` (
`table_name` VARCHAR(50) NOT NULL,
`updated_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
PRIMARY KEY (`table_name`),
UNIQUE INDEX `table_name_UNIQUE` (`table_name` ASC))
ENGINE = InnoDB;
This is the query (Generated by Sequalize):
INSERT INTO `updated_tables` (`table_name`,`updated_at`) VALUES ('workdamnit',NULL) ON DUPLICATE KEY UPDATE `table_name`=VALUES(`table_name`), `updated_at`=VALUES(`updated_at`);
Simplified form of the same query:
INSERT INTO `updated_tables` (`table_name`,`updated_at`) VALUES ('workdamnit',NULL)
And it produces the following entry in table:
table_name: workdamnit
updated_at: 2018-07-05 14:27:17.142494
Now to the question.
Using MySQL 5.6.39-log on AWS RDS
Gives this error:
Error Code: 1048. Column 'updated_at' cannot be null
Is it since the MySQL versions are a bit different, or it has to do something with RDS?
During the creation of your table you have mentioned the following on your column: updated_at:
Do not allow NULL
If nothing is provided, use CURRENT_TIMESTAMP(6) as default.
Hence, It is giving the error when you are inserting NULL in your query.
So, If I understand what you are trying to do currectly, this should be your query:
INSERT INTO `updated_tables` (`table_name`) VALUES ('workdamnit')
instead of
INSERT INTO `updated_tables` (`table_name`,`updated_at`) VALUES ('workdamnit',NULL)
Hope it helps
You are trying to INSERT NULL on a field that does not allow it. Furthermore this field has a default value. so you can simply try:
INSERT INTO `updated_tables` (`table_name`) VALUES ('workdamnit') ...
After some research I found the answer. The RDS instance has a strict mode turned on by default, so it was responding properly. While my local instance, and also an instance of MySQL on EC2, were not using the strict mode.

MySQL: INSERT error "Cannot be NULL" -- DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP

In fact there are so many similar questions, I could not solve this problem.
I am using codeigniter framework. When I call insert method of ActiveRecord by passing a php object, it send all properties either by its value or as null. It causes cannot be null. error.
Table Structure:
CREATE TABLE `scheduledTasks` (
`id` int(11) NOT NULL,
`type` varchar(255) COLLATE utf8_bin NOT NULL,
`createTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`executionTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`ownerUserId` int(11) DEFAULT NULL,
`subjectUserId` text COLLATE utf8_bin,
`detail` text COLLATE utf8_bin,
`isExecuted` int(1) DEFAULT '0'
);
ALTER TABLE `scheduledTasks`
ADD PRIMARY KEY (`id`);
ALTER TABLE `scheduledTasks`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
Query I tried:
INSERT INTO `scheduledTasks` (`id`, `type`, `createTime`, `executionTime`, `ownerUserId`, `detail`, `isExecuted`)
VALUES (NULL, 'QuoteRequest', NULL, NULL, '926', NULL, NULL)
Mysql Version:
+-------------------------+
| VERSION() |
+-------------------------+
| 5.7.17-0ubuntu0.16.04.1 |
+-------------------------+
I have
explicit_defaults_for_timestamp | OFF
and sql mode is
+-------------------------------------------------------------------------------------------------------------------------------------------+
| ##SESSION.sql_mode |
+-------------------------------------------------------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+-------------------------------------------------------------------------------------------------------------------------------------------+
Discussion
The MySQL 5.7 manual states that...
In addition, you can initialize or update any TIMESTAMP column to the
current date and time by assigning it a NULL value, unless it has been
defined with the NULL attribute to permit NULL values.
The manual does not say you can do this for DATETIME fields. The best thing to do would be to supply no values in your INSERT query for the createTime and executionTime fields. That should give you the DEFAULT_TIMESTAMP. If that fails, well, I tried.
INSERT INTO `scheduledTasks` (`id`, `type`, `createTime`, `executionTime`, `ownerUserId`, `detail`, `isExecuted`)
VALUES (NULL, 'QuoteRequest', , , '926', NULL, NULL)
Also, keep this in mind about MySQL default values, even though your DATETIME columns do have an explicit DEFAULT clause.
For data entry into a NOT NULL column that has no explicit DEFAULT
clause, if an INSERT or REPLACE statement includes no value for the
column, or an UPDATE statement sets the column to NULL, MySQL handles
the column according to the SQL mode in effect at the time:
If strict SQL mode is enabled, an error occurs for transactional tables and the statement is rolled back. For nontransactional tables,
an error occurs, but if this happens for the second or subsequent row
of a multiple-row statement, the preceding rows will have been
inserted.
If strict mode is not enabled, MySQL sets the column to the implicit default value for the column data type.
Finally, about strict mode in the MySQL Manual:
For STRICT_TRANS_TABLES, MySQL converts an invalid value to the
closest valid value for the column and inserts the adjusted value. If
a value is missing, MySQL inserts the implicit default value for the
column data type. In either case, MySQL generates a warning rather
than an error and continues processing the statement. Implicit
defaults are described in Section 12.7, “Data Type Default Values”.
Conclusion
In summary, if you are in strict mode (which you are, STRICT_TRANS_TABLES) and have DATETIME columns set to NOT NULL DEFAULT CURRENT_TIMESTAMP, and then you supply NULL values during an INSERT, and then subsequently you get a "cannot be NULL" error, ... next time around do not supply values to the DATETIME fields.
If your framework cannot be setup to omit values during INSERT, and changing the SQL mode does not work, then altering the table to use (gasp) TIMESTAMP may be your only option to use NULL in strict mode and have a DEFAULT TIMESTAMP appear.

insert not working on mysql 5.7.12-0?

my table structure is
CREATE TABLE IF NOT EXISTS `emp` (
`id` int(3) NOT NULL AUTO_INCREMENT,
`name` varchar(11) DEFAULT NULL,
`age` varchar(31) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
My query is :
INSERT INTO `emp` (`id`, `name`) VALUES ('1', 'prashant');
This is working with all the MYSQL versions below 5.7, but not working with MYSQL version 5.7.12-0ubuntu1
Getting error :
#1364 - Field 'age' doesn't have a default value
What is new in this version ??
Try it on mysql version below 5.7 ,you will see the difference.
Thanks :-)
It would be a huge surprise if this worked in any version of mysql at all. Copy paste this into sqlfiddle.com (mysql 5.6 or 5.5) and confirm for yourself.
age is defined as varchar(31) and not null. Thus your insert statement should have a value for that column. Or you should give it a default value. While you are at it, change it to a more appropriate data type.
CREATE TABLE IF NOT EXISTS `emp` (
`id` int(3) NOT NULL AUTO_INCREMENT,
`name` varchar(11) DEFAULT NULL,
`age` int(3) NOT NULL default 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
Updated:
Thinking about this some more I think you have switched off Strict Mode in your older version of mysql
Strict mode controls how MySQL handles invalid or missing values in
data-change statements such as INSERT or UPDATE. A value can be
invalid for several reasons. For example, it might have the wrong data
type for the column, or it might be out of range. A value is missing
when a new row to be inserted does not contain a value for a non-NULL
column that has no explicit DEFAULT clause in its definition. (For a
NULL column, NULL is inserted if the value is missing.) Strict mode
also affects DDL statements such as CREATE TABLE.
So my original statement is wrong! With string mode off, the default for varchar is probably '' (not sure though never used strict mode off)
In your table age described as not null.
`age` varchar(31) NOT NULL
So, it is required field for insert.
The NOT NULL constraint enforces a field to always contain a value. This means that you cannot insert a new record, or update a record without adding a value to this field.You have to give value for age also in your insert query because it cannot be null.For eg:-
insert into emp(`id`,`name`,`age`) values('1','rahul','26')
hope this helps!!.Comment for further query

MySQL insert query with missing not null fields

I currently trying to use an Object Relational Mapper for CodeIgniter and I'm experiencing something I did not expect.
I have a table with a couple of fields, some of which are NOT NULL. An insert query is which is missing of the NOT NULL fields is generated -- a new row is added but with blanks for those fields.
I did not know MySQL would disregard the NOT NULL fields that aren't present in the query and insert the row anyways. Is there a way to restrict this?
-Edit-
Let me add a few more details and try to explain it a bit more
Here is a sample table:
CREATE TABLE `test` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`color` varchar(40) COLLATE utf8_bin DEFAULT '',
`shape` varchar(40) COLLATE utf8_bin NOT NULL,
`size` varchar(40) COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
Here is a sample query:
INSERT INTO `test` (`shape`) VALUES ('foo')
I don't have size in my query yet it still adds the row - is this expected?
(The sample query was run in phpMyAdmin)
I believe the accepted answer is incorrect, given the question's test INSERT statement. It looks to me like MySQL's "strict mode" is turned off for this table or database. From the docs:
Strict mode controls how MySQL handles input values that are invalid or missing... A value is missing when a new row to be inserted does not contain a value for a non-NULL column that has no explicit DEFAULT clause in its definition...
If you are not using strict mode (that is, neither STRICT_TRANS_TABLES nor STRICT_ALL_TABLES is enabled), MySQL inserts adjusted values for invalid or missing values and produces warnings.
You can find out how your database is running with these queries:
SELECT ##global.sql_mode;
SELECT ##session.sql_mode;
Changing these values is discussed here: https://stackoverflow.com/a/5273824/27846
Empty string is not the same thing as NULL. Perhaps ORM inserts just '' for those fields.
Not a codeigniter dev, but I would hazard a guess that the issue is your ORM is passing blank values on to the database, I would check your logs to verify this and if its the case, check your ORM if it has some validation options.