I'm confused when inserting null data (records with null field) into NOT NULL columns.
The mysql table disables STRICT-SQL-MODE.
According to thess two docs, it was supposed to work but the truth is not.
https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#sql-mode-strict
https://dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html#data-type-defaults-implicit
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 are inserted.
If strict mode is not enabled, MySQL sets the column to the implicit default value for the column data type.
When I insert a batch of records (with null field), for example 100 records, it works.
But when I insert only one record with null field, it failes with the message: ERROR 1048 (23000): Column 'int_without_default' cannot be null.
My question is how to insert single record with null field into NOT NULL column.
Here is the test case I made:
Create a table with two columns with 'NOT NULL' requirement:
CREATE TABLE `test_table` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`int_without_default` int(11) NOT NULL,
`int_with_default` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='for test';
Sql mode of the table
mysql> SELECT ##GLOBAL.sql_mode;
+-------------------------------------------------------------------------------------------------------------------------------------------+
| ##GLOBAL.sql_mode |
+-------------------------------------------------------------------------------------------------------------------------------------------+
| NO_ENGINE_SUBSTITUTION |
+-------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> select ##SESSION.sql_mode;
+-------------------------------------------------------------------------------------------------------------------------------------------+
| ##SESSION.sql_mode |
+-------------------------------------------------------------------------------------------------------------------------------------------+
| NO_ENGINE_SUBSTITUTION |
+-------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
Inserting single record with null caused failure:
-- ERROR 1048 (23000): Column 'int_without_default' cannot be null
insert into `test_table` (`int_without_default`,`int_with_default`)
value (null, 123);
-- ERROR 1048 (23000): Column 'int_with_default' cannot be null
insert into `test_table` (`int_without_default`,`int_with_default`)
value (123, null);
-- ERROR 1048 (23000): Column 'int_without_default' cannot be null
insert into `test_table` (`int_without_default`,`int_with_default`)
values (null, 123);
-- ERROR 1048 (23000): Column 'int_with_default' cannot be null
insert into `test_table` (`int_without_default`,`int_with_default`)
values (123, null);
But inserting multiple records with null worked. (I print the result below)
-- success
insert into `test_table` (`int_without_default`,`int_with_default`)
values
(null, 123),
(null, 456);
-- success
insert into `test_table` (`int_without_default`,`int_with_default`)
values
(123, null),
(456, null);
-- ERROR 1048 (23000): Column 'int_without_default' cannot be null
insert into `test_table` (`int_without_default`,`int_with_default`)
values
(null, null);
-- success
insert into `test_table` (`int_without_default`,`int_with_default`)
values
(null, null),
(null, null);
After executing above sql statement, the content of the table:
mysql> select * from test_table;
+----+---------------------+------------------+
| id | int_without_default | int_with_default |
+----+---------------------+------------------+
| 1 | 0 | 123 |
| 2 | 0 | 456 |
| 3 | 123 | 0 |
| 4 | 456 | 0 |
| 5 | 0 | 0 |
| 6 | 0 | 0 |
+----+---------------------+------------------+
6 rows in set (0.00 sec)
operation screenshot
Related
I would like to insert a row with only the default values (which I will then update later since I need the ID autoincremented field)
This works in SQL Server (How to insert a record with only default values?)
insert into myTable DEFAULT VALUES;
But how can I accomplish this in MySQL:
I also tried:
insert into myTable;
which fails. I know I can work around with the standard insert syntax, but there are a lot of columns in my table so a simple syntax if it exists would be helpful.
This will do it :
INSERT INTO `myTable` (`id`)
VALUES
(null),
(null);
-- or
INSERT INTO `myTable` ()
VALUES();
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE Table1
(`id` int AUTO_INCREMENT PRIMARY KEY, `title` varchar(5) DEFAULT '***')
;
INSERT INTO Table1
(`id`, `title`)
VALUES
(1, 'hi'),
(2, 'hello')
;
INSERT INTO Table1
(`id`)
VALUES
(null),
(null)
;
INSERT INTO Table1 () VALUES();
Query 1:
SELECT * from Table1
Results:
| id | title |
|----|-------|
| 1 | hi |
| 2 | hello |
| 3 | *** |
| 4 | *** |
| 5 | *** |
I have the following table structure (using SHOW CREATE command just now):
CREATE TABLE `ipstats` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`ip` VARCHAR(15) NOT NULL,
`online` ENUM('n','y') NOT NULL DEFAULT 'y',
`last_used` DATETIME NOT NULL DEFAULT '1981-09-30 00:00:00',
PRIMARY KEY (`id`),
UNIQUE INDEX `ip` (`ip`)
)
COLLATE='utf8_general_ci'
ENGINE=MyISAM
AUTO_INCREMENT=253691;
Now, I simply fetch a few recent values (I've changed the IPs for demonstration):
mysql> SELECT * FROM ipstats ORDER BY id DESC LIMIT 10;
+--------+----------------+--------+---------------------+
| id | ip | online | last_used |
+--------+----------------+--------+---------------------+
| 253690 | 10.204.102.38 | n | 2013-10-19 14:14:33 |
| 253689 | 10.188.124.196 | n | 2013-10-19 10:46:25 |
| 253688 | 10.166.124.194 | n | 2013-10-19 16:49:40 |
| 253687 | 10.250.137.166 | n | 2013-10-19 13:51:56 |
| 253686 | 10.221.102.39 | n | 2013-10-19 14:13:03 |
| 253685 | 10.129.102.57 | n | 2013-10-19 18:45:20 |
| 253684 | 10.214.102.39 | n | 2013-10-19 03:43:55 |
| 253683 | 10.31.142.41 | n | 2013-10-19 17:27:08 |
| 253682 | 10.41.142.154 | n | 2013-10-19 00:52:11 |
| 253681 | 10.41.124.84 | n | 2013-10-19 10:37:12 |
+--------+----------------+--------+---------------------+
After this, I'll try to execute a simple INSERT statement:
INSERT INTO `ipstats` (`ip`, `last_used`)
VALUES ( '10.3.100.244', NOW() )
ON DUPLICATE KEY UPDATE
`online` = 'y',
`last_used` = NOW(),
`id` = LAST_INSERT_ID(`id`)
where the value 10.3.100.244 does not already exist in the table. It results in:
ERROR 1062 (23000): Duplicate entry '253691' for key 'PRIMARY'
Selecting the LAST_INSERT_ID gives:
mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
| 0 |
+------------------+
If that wasn't already weird behaviour; I'll try to insert an already existing IP entry:
mysql> INSERT INTO `ipstats` (`ip`, `last_used`) VALUES ( '10.204.102.38', NOW() ) ON DUPLICATE KEY UPDATE `online` = 'y', `last_used` = NOW(), `id` = LAST_INSERT_ID(`id`);
ERROR 1062 (23000): Duplicate entry '253691' for key 'PRIMARY'
I'm now officially stumped at this behaviour from MySQL. All other queries are working fine in all other processes that are running. The error is occurring only when I try to INSERT to the ipstats table. I even tried the following:
mysql> UPDATE ipstats
SET `online` = 'n',
`last_used` = NOW(),
`id` = LAST_INSERT_ID(`id`)
WHERE ip = '10.204.102.38';
Affected rows: 1 Found rows: 0 Warnings: 0 Duration for 1 query: 0.000 sec.
mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
| 253690 |
+------------------+
Affected rows: 0 Found rows: 1 Warnings: 0 Duration for 1 query: 0.000 sec.
mysql> INSERT INTO `ipstats` (`ip`, `last_used`)
VALUES ( '10.204.102.38', NOW() )
ON DUPLICATE KEY UPDATE
`online` = 'y',
`last_used` = NOW(),
`id` = LAST_INSERT_ID(`id`);
Error 1062 (23000): Duplicate entry '253691' for key 'PRIMARY'
What could be the problem? How can I resolve this? The error has been occurring since today afternoon and I never faced such a problem before.
P.S.: The error occurs with all user-accounts in my MySQL installation. There are 4 users (including root) who can access the database. None of them is able to perform the INSERT query.
A force insertion of a new row (with id different from 253691) seems to have solved this problem for now. I am still not sure as to why the error occurred.
The command I used was:
INSERT INTO `ipstats` (id, ip, online, last_used)
VALUES ( 253699, '10.204.102.38', 'n', NOW() );
and the system was working normally again (for all 4 users, on every connection). I'll leave the question as still unanswered since I still don't know what caused the problem. My best guess would be that it is a possible MySQL bug.
Not sure what i am doing wrong here:
mysql> use co_sysdev;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> select * from system_params;
Empty set (0.01 sec)
mysql> INSERT INTO system_params (NUM_ENGINE_D_PROCESSES,MAX_NUM_BATCHES_PER_CLIENT,MAX_NUM_BATCHES_PER_LOCATION) VALUES(5,8,2);
ERROR 1054 (42S22): Unknown column 'NUM_ENGINE_D_PROCESSES' in 'field list'
mysql>
also:
desc system_params;
+-----------+----------------------------------------------------------------------------------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------------------------------------------------------------------------------------------------+------+-----+---------+-------+
| attribute | enum('NUM_ENGINE_D_PROCESSES','MAX_NUM_BATCHES_PER_CLIENT','MAX_NUM_BATCHES_PER_LOCATION') | NO | PRI | NULL | |
| value | varchar(256) | NO | | NULL | |
+-----------+----------------------------------------------------------------------------------------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
also:
show create table system_params;
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| system_params | CREATE TABLE `system_params` (
`attribute` enum('NUM_ENGINE_D_PROCESSES','MAX_NUM_BATCHES_PER_CLIENT','MAX_NUM_BATCHES_PER_LOCATION') NOT NULL,
`value` varchar(256) NOT NULL,
PRIMARY KEY (`attribute`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
you can't use enum values as field names. Your insert has to be something like
INSERT INTO system_params (attribute, value) VALUES ('NUM_ENGINE_D_PROCESSES', 'foo');
unless your possible values that can be inserted here are unbounded (e.g. end-user definable), you're going down a very very painful path.
well clearly this error says you are using wrong column name somwhere and NUM_ENGINE_D_PROCESSES is the enum value, and you are using it as column...
the syntax of SQL insert query should be like
INSERT INTO your_table_Name (ID, name, ...<column names goes here>...)
VALUES ('1', 'John', ...<values goes here>...);
in your case
INSERT INTO system_params (attribute, value) VALUES ('NUM_ENGINE_BLA_BLA', 'foo');
My table structure is:
CREATE TABLE IF NOT EXISTS `users_settings_temp` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`userid` int(10) unsigned DEFAULT NULL,
`type` enum('type1','type2')
`data` text,
`date_created` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
What I am trying to do is:
Let say I want to insert a new entry, but I dont want it to be duplicate, after google around, i found this format:
INSERT INTO users_settings_temp(...)
ON DUPLICATE KEY UPDATE data = '{$data}'
I guess the problem is in my table, the primary key => id. How do I alter the table, so that I could use the:
INSERT INTO ... ON DUPLICATE KEY UPDATE
Can I use user_id + type as primary key? If yes, could you please show me how to do it?
CREATE TABLE IF NOT EXISTS `users_settings_temp` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`userid` int(10) unsigned DEFAULT NULL,
`type` enum('type1','type2'),
`data` text,
`date_created` int(11) DEFAULT NULL,
PRIMARY KEY (`id`, `type`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
When you do it like this then
a) specifying id works
mysql> INSERT INTO users_settings_temp VALUES (1, 2, 'type1', 'keks', 5);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO users_settings_temp VALUES (1, 2, 'type2', 'keks', 5);
Query OK, 1 row affected (0.00 sec)
b) of course primary key is guaranteed to be unique
mysql> INSERT INTO users_settings_temp VALUES (1, 2, 'type2', 'keks', 5);
ERROR 1062 (23000): Duplicate entry '1-type2' for key 'PRIMARY'
c) letting database pull a new id works
mysql> INSERT INTO users_settings_temp VALUES (NULL, 2, 'type2', 'keks', 5);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO users_settings_temp VALUES (NULL, 2, 'type1', 'keks', 5);
Query OK, 1 row affected (0.00 sec)
but will increase them always
mysql> SELECT * FROM users_settings_temp;
+----+--------+-------+------+--------------+
| id | userid | type | data | date_created |
+----+--------+-------+------+--------------+
| 1 | 2 | type1 | keks | 5 |
| 1 | 2 | type2 | keks | 5 |
| 2 | 2 | type2 | keks | 5 |
| 3 | 2 | type1 | keks | 5 |
+----+--------+-------+------+--------------+
4 rows in set (0.00 sec)
NOTES:
You should think if your id should still be autoincrement or not.
Also, can not think of a reason why date_created should be int(11) instead of datetime
I'd like to update all NULL fields in one table to 0. Of course
UPDATE mytable SET firstcol=0 WHERE firstcol IS NULL
would do the job. But I wonder if thereĀ“s a smarter solution than just c&p this line for every column.
You could do this - repeat as necessary for each column:
UPDATE `table1` SET
`col1` = IFNULL(col1, 0),
`col2` = IFNULL(col2, 0);
Example:
DROP TABLE IF EXISTS `table1`;
CREATE TABLE `table1` (
`id` int(10) unsigned NOT NULL auto_increment,
`col1` int(10) unsigned,
`col2` int(10) unsigned,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
INSERT INTO `table1` VALUES
(1, 1, NULL),
(2, NULL, NULL),
(3, 2, NULL),
(4, NULL, NULL),
(5, 3, 4),
(6, 5, 6),
(7, 7, NULL);
UPDATE `table1` SET
`col1` = IFNULL(col1, 0),
`col2` = IFNULL(col2, 0);
SELECT * FROM `table1`;
+----+------+------+
| id | col1 | col2 |
+----+------+------+
| 1 | 1 | 0 |
| 2 | 0 | 0 |
| 3 | 2 | 0 |
| 4 | 0 | 0 |
| 5 | 3 | 4 |
| 6 | 5 | 6 |
| 7 | 7 | 0 |
+----+------+------+
UPDATE
If you want to alter the table structure by changing columns so that they no longer accept nulls, you could do it with a stored procedure. The following stored procedure queries the INFORMATION_SCHEMA COLUMNS for information about columns in a given database table. From that information, it builds up a prepared statement which is then used to alter the table structure. You may need to tweak it to suit your exact requirements - at the moment, it looks for INT columns which do not have NOT NULL set:
delimiter //
DROP PROCEDURE IF EXISTS no_nulls//
CREATE PROCEDURE `no_nulls` (IN param_schema CHAR(255), IN param_table CHAR(255))
BEGIN
SET #alter_cmd = (SELECT CONCAT(
'ALTER TABLE ',
param_table,
GROUP_CONCAT(
' MODIFY COLUMN ',
`column_name`, ' ',
`column_type`,
' NOT NULL'
SEPARATOR ', ')
) AS `sql_cmd`
FROM INFORMATION_SCHEMA.COLUMNS
WHERE `table_schema` = param_schema
AND `table_name` = param_table
AND LCASE(`data_type`) = 'int'
AND LCASE(`is_nullable`) = 'yes');
IF NOT ISNULL(#alter_cmd) THEN
SELECT #alter_cmd;
PREPARE stmt FROM #alter_cmd;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END//
delimiter ;
Example:
CREATE TABLE `test`.`table1` (
`id` int(10) unsigned NOT NULL auto_increment,
`col1` int(10) unsigned,
`col2` int(10) unsigned,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CALL no_nulls('test', 'table1');
+----------------------------------------------------------------------------------------------------------------+
| #alter_cmd |
+----------------------------------------------------------------------------------------------------------------+
| ALTER TABLE table1 MODIFY COLUMN col1 int(10) unsigned NOT NULL, MODIFY COLUMN col2 int(10) unsigned NOT NULL |
+----------------------------------------------------------------------------------------------------------------+
SHOW CREATE TABLE `test`.`table1`;
CREATE TABLE `table1` (
`id` int(10) unsigned NOT NULL auto_increment,
`col1` int(10) unsigned NOT NULL,
`col2` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
The following line displays the command that is to be executed, and may be removed from the stored procedure if necessary:
SELECT #alter_cmd;
Can you just ALTER the columns to NOT NULL DEFAULT 0?
You can do this in a single statement, as per MySQL documentation:
You can issue multiple ADD, ALTER, DROP, and CHANGE clauses in a single ALTER TABLE statement, separated by commas. This is a MySQL extension to standard SQL, which allows only one of each clause per ALTER TABLE statement.
You may want to alter your columns to NOT NULL.
ALTER TABLE your_table MODIFY COLUMN your_field INT NOT NULL;
Test case:
CREATE TABLE nulltable (id INT);
INSERT INTO nulltable VALUES (1);
INSERT INTO nulltable VALUES (2);
INSERT INTO nulltable VALUES (3);
INSERT INTO nulltable VALUES (NULL);
INSERT INTO nulltable VALUES (NULL);
INSERT INTO nulltable VALUES (NULL);
INSERT INTO nulltable VALUES (5);
Result:
mysql> SELECT * FROM nulltable;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
| NULL |
| NULL |
| NULL |
| 5 |
+------+
7 rows in set (0.00 sec)
mysql> ALTER TABLE nulltable MODIFY COLUMN id INT NOT NULL;
Query OK, 7 rows affected, 3 warnings (0.08 sec)
Records: 7 Duplicates: 0 Warnings: 3
mysql> SELECT * FROM nulltable;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 0 |
| 0 |
| 0 |
| 5 |
+----+
7 rows in set (0.00 sec)
Not without an intermediate technology or cursor. You could use DESCRIBE mytable; to get the column names and loop over them to build your UPDATE queries.
So it is possible. But by the time it took you to write that, you probably just could have copy and pasted ;)
This worked for me!
UPDATE `results` SET
column1 = IFNULL(column1,0),
column2 = IFNULL(column2,'');
This is mike's answer but without the quotes for columns on the left !
Note: If you are trying to set your values '0' instead of an empty string if a column's datatype is int
I don't believe there is; any statement that worked on rows that didn't satisfy the where clause would update rows you didn't intent to update. Jason's answer is correct, but, I think, a bit unsafe, unless you are really sure that's what you want.
ALTER TABLE dataBaseName.tableName
ADD COLUMN columnX INT(20) NULL DEFAULT 1 AFTER columnY;
It does the following
adds a new column columnX after columnY.
sets its value to default 1 throughout the column columnX
columnY columnX
| cellValueA | 1 |
| cellValueB | 1 |
| cellValueC | 1 |
| cellValueD | 1 |