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 |
Related
I see a weird behavior where my auto-increment column number is only increasing in a step of 2 instead of 1. So I end up with row ids as 1, 3, 5, 7. I use MySQL 5.6 + InnoDB as the engine. Any idea why this weirdness?
mysql> select version();
+-----------------+
| version() |
+-----------------+
| 5.6.20-68.0-log |
+-----------------+
1 row in set (0.00 sec)
mysql> show create table temp_table;
| superset_version | CREATE TABLE `temp_table` (
`_id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'comm1',
`name` varchar(100) NOT NULL COMMENT 'comm2',
`start_time` bigint(20) NOT NULL COMMENT 'comm3',
`updated_at` bigint(20) NOT NULL COMMENT 'comm4',
`status` varchar(50) NOT NULL COMMENT 'comm5',
PRIMARY KEY (`_id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8 |
Notice that insert incremented the _id column by a difference of 2.
mysql> insert into superset_version(name, start_time, updated_at, status) value("TEMP ROW", -1, -1, "erro");
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> select * from superset_version order by _id desc limit 3;
+-----+----------+------------+------------+--------+
| _id | name | start_time | updated_at | status |
+-----+----------+------------+------------+--------+
| 33 | TEMP ROW | -1 | -1 | erro |
| 31 | TEMP ROW | -1 | -1 | erro |
| 29 | TEMP ROW | -1 | -1 | erro |
+-----+----------+------------+------------+--------+
3 rows in set (0.00 sec)
auto_increment_increment setting is most likely set to 2, therefore mysql increases auto increment numbers by 2. Use show varibles like ... command to check the setting.
for double check you could try:
SELECT AUTO_INCREMENT
From `information_schema`.`TABLES`
WHERE TABLE_NAME = '<<YOUR TABLE NAME HERE>>' AND
TABLE_SCHEMA = '<< YOUR DATABASE NAME HERE >>'
if the step is really equals 2, it's possible to replace it.
or one another way:
Check values in:
mysql.cnf / ini:
auto-increment-increment
auto-increment-offset
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 | *** |
Consider following scheme:
CREATE TABLE IF NOT EXISTS `test` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(20) NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
--
-- Dumping data for table `test`
--
INSERT INTO `test` (`user_id`, `username`) VALUES
(1, 'Jason'),
(2, 'OOO'),
(3, 'Stack'),
(4, 'Overflow');
And this query:
SELECT * FROM TEST WHERE username = 0
It Shows:
| USER_ID | USERNAME |
----------|----------|--
| 1 | Jason |
| 2 | OOO |
| 3 | Stack |
| 4 | Overflow |
But not when username = '0' or when username = 1
Here is SQLFIDDLE DEMO
Since the username is String and you have compared it to a Number, MySQL silently cast the column name into number. See Here.
When the string is cast into a number and it starts with a letter, the value will be zero, that's why all the records are shown.
The adding a username of 5, like this demo, you'll see all the records except with this username since 5 <> 0.
I'm using a trigger in MySQL to do the following:
When I add a new client to the client table, it should create a set of entries in a 'Client-Type' table, linking the client id to a set of type ids (client1, type1 client1, type2) etc...
However, the database is inserting the entry for the last type twice when the trigger is run. So the last two entries are (client1, type9 client1, type9).
The trigger code is as follows:
AFTER INSERT ON `nmsTicket`.`client`
FOR EACH ROW
BEGIN
DECLARE done BOOLEAN DEFAULT 0;
DECLARE a CHAR(2);
DECLARE types CURSOR
FOR
SELECT typeID FROM type;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;
OPEN types;
REPEAT
FETCH types INTO a;
INSERT INTO clientType(id_type, id_client) VALUES (a,new.idClient);
UNTIL done END REPEAT;
CLOSE types;
I've looked it over a few times, but I can't see why it would be exhibiting this behaviour; all the entries before the last one work fine.
Any pointers?
I'm not sure why you're using a cursor in your trigger - this should be avoided unless you absolutely need one (see here for example Optimal MySQL settings for queries that deliver large amounts of data?)
The following is a simplified example (minus referential integrity) which uses a cross join instead of a cursor. In addition you'll notice I'm not using a surrogate primary key on the client_types table but a composite one instead which better enforces data integrity.
Schema
drop table if exists client_type; --your type table
create table client_type
(
type_id tinyint unsigned not null auto_increment primary key,
name varchar(255) unique not null
)
engine=innodb;
drop table if exists client;
create table client
(
client_id int unsigned not null auto_increment primary key,
name varchar(255) not null
)
engine=innodb;
drop table if exists client_types; -- your clienttype table
create table client_types
(
client_id int unsigned not null,
type_id tinyint unsigned not null,
primary key (client_id, type_id) -- ** note use of composite primary key **
)
engine=innodb;
delimiter #
create trigger client_after_ins_trig after insert on client
for each row
begin
insert into client_types (client_id, type_id)
select
c.client_id,
ct.type_id
from
client c
cross join client_type ct
where
c.client_id = new.client_id
order by
ct.type_id;
end#
delimiter ;
Testing
mysql> insert into client_type (name) values ('type one'),('type two'),('type three');
Query OK, 3 rows affected (0.03 sec)
mysql> insert into client (name) values ('client A'),('client B');
Query OK, 2 rows affected (0.04 sec)
mysql> select * from client_type;
+---------+------------+
| type_id | name |
+---------+------------+
| 1 | type one |
| 3 | type three |
| 2 | type two |
+---------+------------+
3 rows in set (0.00 sec)
mysql> select * from client;
+-----------+----------+
| client_id | name |
+-----------+----------+
| 1 | client A |
| 2 | client B |
+-----------+----------+
2 rows in set (0.00 sec)
mysql> select * from client_types;
+-----------+---------+
| client_id | type_id |
+-----------+---------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 2 | 2 |
| 2 | 3 |
+-----------+---------+
6 rows in set (0.00 sec)
Hope this helps :)
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