SELECT… INSERT with NOT NULL fields - mysql

I am trying to do a SELECT... INSERT into a table with constraints that prevent NULL values:
mysql> create table if not exists table1 (
-> id int not null auto_increment,
-> description varchar(45),
-> primary key (`id`)
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> create table if not exists table2 (
-> id int not null auto_increment,
-> description varchar(45) not null,
-> primary key (`id`),
-> unique index `unique_desc` (`description`)
-> );
Query OK, 0 rows affected (0.02 sec)
mysql> insert ignore into table1
-> (description)
-> values("stupid thing"),
-> ("another thing"),
-> (null),
-> ("stupid thing"),
-> ("last thing");
Query OK, 5 rows affected (0.00 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> select * from table1;
+----+---------------+
| id | description |
+----+---------------+
| 1 | stupid thing |
| 2 | another thing |
| 3 | NULL |
| 4 | stupid thing |
| 5 | last thing |
+----+---------------+
5 rows in set (0.00 sec)
Cool, we have the source (table1) and destination (table2) tables created, and the source table populated with some duplicate, null data.
If I do a normal SELECT... INSERT into the destination table, I get a column with empty string as the value:
mysql> insert ignore into table2
-> (description)
-> select description
-> from table1;
Query OK, 4 rows affected, 1 warning (0.00 sec)
Records: 5 Duplicates: 1 Warnings: 1
mysql> select * from table2;
+----+---------------+
| id | description |
+----+---------------+
| 3 | |
| 2 | another thing |
| 4 | last thing |
| 1 | stupid thing |
+----+---------------+
4 rows in set (0.00 sec)
This is bad. But some boss brogrammer led me to the answer in this question:
MySQL Insert Select - NOT NULL fields
And now this method gives me the desired result:
mysql> insert ignore into table2
-> (description)
-> select description
-> from table1
-> where description <> '' and description is not null;
Query OK, 3 rows affected (0.00 sec)
Records: 4 Duplicates: 1 Warnings: 0
mysql> select * from table2;
+----+---------------+
| id | description |
+----+---------------+
| 2 | another thing |
| 3 | last thing |
| 1 | stupid thing |
+----+---------------+
3 rows in set (0.00 sec)
Is there a way for me to get the above result without having to manually protect each field using the WHERE clause?
Thanks in advance,
K

This technically answers your question in that you can eliminate the nulls by a join instead of the where clause.
insert ignore into table2
(description)
select t.description from table1 t
join
(
select distinct description from table1
) t1 on (t.description=t1.description);
I am pretty sure, however, that you will need to specify a join for each field though. Off the top of my head, I can't think of a way around this.

Related

add auto-increment to db without changing current IDs - SQL

I have a table like this:
id | name
--------------
1 | John
2 | Mary
.
.
.
NULL | Brian
NULL | Jacob
I meant to make id an AUTO INCREMENT row, but I guess I did not b/c when I added new names Brian, Jacob, it didn't automatically add incremented id values. I am wondering if there is a way to add those values to replace NULL, without changing any of the id's above it.
Demo:
mysql> create table mytable (id int, name text);
Query OK, 0 rows affected (0.02 sec)
mysql> insert into mytable values
-> (1, 'John'),
-> (2, 'Mary'),
-> (NULL, 'Brian'),
-> (NULL, 'Jacob');
Query OK, 4 rows affected (0.01 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> alter table mytable modify column id int auto_increment, add primary key (id);
Query OK, 4 rows affected (0.02 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> select * from mytable;
+----+-------+
| id | name |
+----+-------+
| 1 | John |
| 2 | Mary |
| 3 | Brian |
| 4 | Jacob |
+----+-------+
4 rows in set (0.00 sec)
Conclusion: Yes.
You do need id to be the first column in a key (I used PRIMARY KEY here). MySQL's InnoDB storage engine won't let a column be auto-increment unless it's the leftmost column in some key (that is, any index will suffice).

MySQL auto-increment based on group

The problem is related to autoincrement with mysql. What I'm trying to achieve is to increment an ID value based on the customer number. So basically i insert data sets without any order into a table. Each time a new customer is inserted, i would like the id column to be incremented, but of course kept for every row related to the customer, see the table below. Is there any way to achieve that via sql? I tried my luck with multiple primary keys and also looked into partioning, but was not able to figure it out by myself.
you can use a query like this:
INSERT INTO autoinc (cid,info,customer)
SELECT
COALESCE(max(cid),0) +1
, 'A Customer 1'
, 12345
FROM autoinc
WHERE customer = 12345;
sample
mysql> SELECT * from autoinc;
Empty set (0,00 sec)
mysql> INSERT INTO autoinc (cid,info,customer)
-> SELECT
-> COALESCE(max(cid),0) +1
-> , 'A Customer 1'
-> , 12345
-> FROM autoinc
-> WHERE customer = 12345;
Query OK, 1 row affected (0,00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * from autoinc;
+----+------+--------------+----------+
| id | cid | info | customer |
+----+------+--------------+----------+
| 1 | 1 | A Customer 1 | 12345 |
+----+------+--------------+----------+
1 row in set (0,00 sec)
mysql> INSERT INTO autoinc (cid,info,customer)
-> SELECT
-> COALESCE(max(cid),0) +1
-> , 'A Customer 1'
-> , 12345
-> FROM autoinc
-> WHERE customer = 12345;
Query OK, 1 row affected (0,00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * from autoinc;
+----+------+--------------+----------+
| id | cid | info | customer |
+----+------+--------------+----------+
| 1 | 1 | A Customer 1 | 12345 |
| 2 | 2 | A Customer 1 | 12345 |
+----+------+--------------+----------+
2 rows in set (0,00 sec)
mysql> INSERT INTO autoinc (cid,info,customer)
-> SELECT
-> COALESCE(max(cid),0) +1
-> , 'B Customer 2'
-> , 9876
-> FROM autoinc
-> WHERE customer = 9876;
Query OK, 1 row affected (0,00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * from autoinc;
+----+------+--------------+----------+
| id | cid | info | customer |
+----+------+--------------+----------+
| 1 | 1 | A Customer 1 | 12345 |
| 2 | 2 | A Customer 1 | 12345 |
| 3 | 1 | B Customer 2 | 9876 |
+----+------+--------------+----------+
3 rows in set (0,00 sec)
mysql> INSERT INTO autoinc (cid,info,customer)
-> SELECT
-> COALESCE(max(cid),0) +1
-> , 'A Customer 1'
-> , 12345
-> FROM autoinc
-> WHERE customer = 12345;
Query OK, 1 row affected (0,00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * from autoinc;
+----+------+--------------+----------+
| id | cid | info | customer |
+----+------+--------------+----------+
| 1 | 1 | A Customer 1 | 12345 |
| 2 | 2 | A Customer 1 | 12345 |
| 3 | 1 | B Customer 2 | 9876 |
| 4 | 3 | A Customer 1 | 12345 |
+----+------+--------------+----------+
4 rows in set (0,00 sec)
mysql>
What you probably need is to have different values for ID for each customer. The easiest way to achieve this is to use an AUTO_INCREMENT column as PK of your table.
It is an implementation detail that for consecutively inserted rows an AUTO_INCREMENT column has consecutive values. And the previous statement is not even true. It just happens some times, it is not guaranteed. If an INSERT statement is enclosed in a transaction that is rolled back, the value generated by that insert is skipped. Also, if an INSERT statements that use ON DUPLICATE KEYS UPDATE tries to insert many rows but some of them already exist in the table then the IDs generated for the duplicate keys are skipped.
What I want to stress out is that there is no point trying to get consecutive values using an AUTO_INCREMENT column and it is not even possible.
Back to your problem, if the column ID is the PK of the table and its type is INT AUTO_INCREMENT then MySQL guarantees there won't be two rows having the same value in the ID column and this also satisfies your need to have different values for ID for all the rows with the same value in customer.
You could procedurally do this using a stored procedure, which I won't elaborate on (unless requested) as it isn't a simple query (as you're asking for).
A hacky solution would be to bulk insert into a new joining table:
CREATE TABLE auto_inc_customer_id (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
customer_id INT UNSIGNED NOT NULL, -- Could/should add a FK constraint
PRIMARY KEY (id)
) ENGINE=innodb;
INSERT INTO auto_inc_customer_id SELECT NULL, DISTINCT(Customer) FROM YourExistingTable;
See: http://dev.mysql.com/doc/refman/5.7/en/ansi-diff-select-into-table.html

Use of UNION when creating tables

Database-1
create table sample (
id INT,
nm VARCHAR(10)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
UNION=(for tables from another databases);
So, when we do union what actually it meance?
Please explain, I am getting confusing for this type of UNION.
That looks close to the syntax for creating a merge table, but it has the engine type wrong. Your statement will ignore the union clause and simply create a new, empty table. In order to create merge table you need to specify ENGINE=MERGE.
14.3 The MERGE Storage Engine
The MERGE storage engine, also known as the MRG_MyISAM engine, is a
collection of identical MyISAM tables that can be used as one.
The tables you specify in the UNION clause there, must all be identical - ie, having the same index and column specification, and they must all be in the same order in each table.
After that, can you query your merge table and access the data from all of the tables that form it.
You can also insert into your merge table, which is something you cannot do with a view:
You can optionally specify an INSERT_METHOD option to control how
inserts into the MERGE table take place. Use a value of FIRST or LAST
to cause inserts to be made in the first or last underlying table,
respectively. If you specify no INSERT_METHOD option or if you specify
it with a value of NO, inserts into the MERGE table are not permitted
and attempts to do so result in an error.
Anyway, the doco has the rest of the information if you want to peruse more - I've never felt the need to use this type of table.
Example:
mysql>
mysql> create table t2 (
-> id integer primary key auto_increment,
-> val char(20)
-> ) engine=myisam;
Query OK, 0 rows affected (0.05 sec)
mysql>
mysql> insert into t1(val) values ('table1 a'), ('table1 b');
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> insert into t2(val) values ('table2 a'), ('table2 b');
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql>
mysql>
mysql> create table mt (
-> id integer primary key auto_increment,
-> val char(20)
-> ) engine=merge union=(t1,t2) insert_method=last;
Query OK, 0 rows affected (0.04 sec)
mysql>
mysql> select * from mt;
+----+----------+
| id | val |
+----+----------+
| 1 | table1 a |
| 2 | table1 b |
| 1 | table2 a |
| 2 | table2 b |
+----+----------+
4 rows in set (0.00 sec)
mysql> insert into mt(val) values ('12345');
Query OK, 1 row affected (0.00 sec)
mysql> select * from mt;
+----+----------+
| id | val |
+----+----------+
| 1 | table1 a |
| 2 | table1 b |
| 1 | table2 a |
| 2 | table2 b |
| 3 | 12345 |
+----+----------+
5 rows in set (0.01 sec)
mysql> select * from t2;
+----+----------+
| id | val |
+----+----------+
| 1 | table2 a |
| 2 | table2 b |
| 3 | 12345 |
+----+----------+
3 rows in set (0.00 sec)

allowing null values in already existing foreign key column mysql

I have a MySQL database with tables t1 and t2. One of the columns in table t1 has a foreign key to t2.
Need to allow the foreign key column to accept null values. There is already some important data so recreating the table is not an option.
Tried the usual alter table commands but it showed syntax error.
Is there a way to go around it without affecting the database?
This is what I tried:
ALTER TABLE t1 MODIFY fk_column_id NULL;
The missing part is the type definition in the modify statement. With MODIFY you redefine the column, thus you need to give the new type as well. But in case you only modify that it can be null, no data will be lost.
Create referenced table and filling it :
mysql> -- Creating referenced table
mysql> create table `tUser` (
-> `id` int auto_increment not null,
-> `name` varchar(16),
-> primary key (`id`)
-> );
Query OK, 0 rows affected (0.07 sec)
mysql> -- Filling and checking referenced table
mysql> insert into `tUser` (`name`) values ("Jane"), ("John");
Query OK, 2 rows affected (0.04 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from `tUser`;
+----+------+
| id | name |
+----+------+
| 1 | Jane |
| 2 | John |
+----+------+
2 rows in set (0.07 sec)
mysql> -- Creating referencing table
mysql> create table `tHoliday` (
-> `id` int auto_increment not null,
-> `userId` int,
-> `date` date,
-> primary key (`id`),
-> foreign key (`userId`) references `tUser` (`id`)
-> );
Query OK, 0 rows affected (0.14 sec)
mysql> -- Filling and checking referencing table
mysql> insert into `tHoliday` (`userId`, `date`) values
-> (1, "2014-11-10"),
-> (1, "2014-11-13"),
-> (2, "2014-10-10"),
-> (2, "2014-12-10");
Query OK, 4 rows affected (0.08 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> select * from `tHoliday`;
+----+--------+------------+
| id | userId | date |
+----+--------+------------+
| 1 | 1 | 2014-11-10 |
| 2 | 1 | 2014-11-13 |
| 3 | 2 | 2014-10-10 |
| 4 | 2 | 2014-12-10 |
+----+--------+------------+
4 rows in set (0.05 sec)
mysql> -- Updating foreign key column to allow NULL
mysql> alter table `tHoliday` modify `userId` int null;
Query OK, 0 rows affected (0.08 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> -- Inserting line without foreign key
mysql> insert into `tHoliday` (`date`) values ("2014-11-15");
Query OK, 1 row affected (0.06 sec)
mysql> select * from `tHoliday`;
+----+--------+------------+
| id | userId | date |
+----+--------+------------+
| 1 | 1 | 2014-11-10 |
| 2 | 1 | 2014-11-13 |
| 3 | 2 | 2014-10-10 |
| 4 | 2 | 2014-12-10 |
| 5 | NULL | 2014-11-15 |
+----+--------+------------+
5 rows in set (0.03 sec)

MySQL Insert Select - NOT NULL fields

Oh hey there,
I am trying to load data into a table via a INSERT... SELECT statement, but I am having issues with MySQL handling NULL values.
In the below example, table1 is the source and table2 is the destination (Note that table2 has more constraints on the description field):
mysql> drop table if exists table1;
Query OK, 0 rows affected (0.03 sec)
mysql> drop table if exists table2;
Query OK, 0 rows affected (0.00 sec)
mysql> create table if not exists table1 (
-> id int not null auto_increment,
-> description varchar(45),
-> primary key (`id`)
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> create table if not exists table2 (
-> id int not null auto_increment,
-> description varchar(45) not null,
-> primary key (`id`),
-> unique index `unique_desc` (`description`)
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> insert ignore into table1
-> (description)
-> values("stupid thing"),
-> ("another thing"),
-> (null),
-> ("stupid thing"),
-> ("last thing");
Query OK, 5 rows affected (0.00 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> select * from table1;
+----+---------------+
| id | description |
+----+---------------+
| 1 | stupid thing |
| 2 | another thing |
| 3 | NULL |
| 4 | stupid thing |
| 5 | last thing |
+----+---------------+
5 rows in set (0.00 sec)
mysql> insert ignore into table2
-> (description)
-> select description
-> from table1;
Query OK, 4 rows affected, 1 warning (0.01 sec)
Records: 5 Duplicates: 1 Warnings: 1
mysql> select * from table2;
+----+---------------+
| id | description |
+----+---------------+
| 3 | |
| 2 | another thing |
| 4 | last thing |
| 1 | stupid thing |
+----+---------------+
4 rows in set (0.00 sec)
The row with the empty space and id=3 should not be there. I understand that MySQL handles the NOT NULL directive this way by default, but I tried specifying the sql_mode option to "STRICT_ALL_TABLES", which I found to have the following affect:
Without sql_mode set:
mysql> drop table if exists table2;
Query OK, 0 rows affected (0.00 sec)
mysql> create table if not exists table2 (
-> id int not null auto_increment,
-> count int,
-> description varchar(45) not null,
-> primary key (`id`),
-> unique index `unique_desc` (`description`)
-> );
Query OK, 0 rows affected (0.02 sec)
mysql> insert into table2
-> (count,description)
-> values(12,"stupid thing");
Query OK, 1 row affected (0.00 sec)
mysql> insert into table2
-> (count)
-> values(5);
Query OK, 1 row affected, 1 warning (0.01 sec)
mysql> select * from table2;
+----+-------+--------------+
| id | count | description |
+----+-------+--------------+
| 1 | 12 | stupid thing |
| 2 | 5 | |
+----+-------+--------------+
2 rows in set (0.00 sec)
With sql_mode set to "STRICT_ALL_TABLES":
mysql> drop table if exists table1;
Query OK, 0 rows affected, 1 warning (0.03 sec)
mysql> drop table if exists table2;
Query OK, 0 rows affected (0.00 sec)
mysql> create table if not exists table2 (
-> id int not null auto_increment,
-> count int,
-> description varchar(45) not null,
-> primary key (`id`),
-> unique index `unique_desc` (`description`)
-> );
Query OK, 0 rows affected (0.02 sec)
mysql> insert into table2
-> (count,description)
-> values(12,"stupid thing");
Query OK, 1 row affected (0.01 sec)
mysql> insert into table2
-> (count)
-> values(5);
ERROR 1364 (HY000): Field 'description' doesn't have a default value
mysql> select * from table2;
+----+-------+--------------+
| id | count | description |
+----+-------+--------------+
| 1 | 12 | stupid thing |
+----+-------+--------------+
1 row in set (0.00 sec)
Note that in the above comparison, if you explicitly give the description field a NULL value, the database will properly complain WITH AND WITHOUT the "STRICT_ALL_TABLES" option set:
mysql> insert into table2
-> (count,description)
-> values(12,null);
ERROR 1048 (23000): Column 'description' cannot be null
Conclusion:
For some reason, setting the sql_mode affects this kind of insert, but does not affect the INSERT... SELECT behavior.
How can I get the data from table1 into table2 with a single query, and no empty cells?
Thanks in advance,
K
Simply use a WHERE clause:
insert ignore into table2(description)
select description from table1
where description <> '' and description is not null