Mysql in sentence - mysql

Maybe I didnt explain well.
these are the tables:
Table 1
CREATE TABLE `notforeverdata` (
`id` int(11) NOT NULL auto_increment,
`num` varchar(255) default NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `notforeverdata` VALUES (1, '4,3,0,5');
Table 2
CREATE TABLE `notforeverdata2` (
`id2` int(11) NOT NULL auto_increment,
`num2` varchar(255) default NULL,
PRIMARY KEY (`id2`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `notforeverdata2` VALUES (1, '2,5,6,8');
What I need to do is to check is if any of the numbers of the column "num" in notforeverdata exists in the column num2 of notforeverdata2. in this case the number "5" in the col num of notforeverdata exists in notforeverdata2.
Any Idea?
Thanks

For this example I will create a table, load it with random numbers, and search for each number in a provided list. Here is the catch: the provided list must start with and end with a comma.
From your question, I will use ',3,2,5,'
Here is the example
use test
drop table if exists notforeverdata;
create table notforeverdata
(
id int not null auto_increment,
num VARCHAR(255),
PRIMARY KEY (id)
);
insert into notforeverdata (num) values
(2),(7),(9),(11),(13),(15),(4),(3),(90),(97),(18),(5),(17);
SELECT * FROM notforeverdata;
SELECT * FROM notforeverdata WHERE LOCATE(CONCAT(',',num,','),(',3,2,5,'));
I actually ran it in MySQl 5.5.12 on my desktop. Here is the result:
mysql> use test
drop table if exists notforeverdata;
Database changed
mysql> drop table if exists notforeverdata;
Query OK, 0 rows affected (0.03 sec)
mysql> create table notforeverdata
-> (
-> id int not null auto_increment,
-> num VARCHAR(255),
-> PRIMARY KEY (id)
-> );
Query OK, 0 rows affected (0.12 sec)
mysql> insert into notforeverdata (num) values
-> (2),(7),(9),(11),(13),(15),(4),(3),(90),(97),(18),(5),(17);
Query OK, 13 rows affected (0.06 sec)
Records: 13 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM notforeverdata;
+----+------+
| id | num |
+----+------+
| 1 | 2 |
| 2 | 7 |
| 3 | 9 |
| 4 | 11 |
| 5 | 13 |
| 6 | 15 |
| 7 | 4 |
| 8 | 3 |
| 9 | 90 |
| 10 | 97 |
| 11 | 18 |
| 12 | 5 |
| 13 | 17 |
+----+------+
13 rows in set (0.00 sec)
mysql> SELECT * FROM notforeverdata WHERE LOCATE(CONCAT(',',num,','),(',3,2,5,'));
+----+------+
| id | num |
+----+------+
| 1 | 2 |
| 8 | 3 |
| 12 | 5 |
+----+------+
3 rows in set (0.00 sec)
mysql>
This will, of course, perform a full table scan. Notwithstanding, this works.
Give it a Try !!!

Related

mysql error 1175 while using inner query

Let's say I have 2 tables - item_images and images.
When I run query
SELECT image_id FROM item_images WHERE item_id=1
I get image_id values 5, 6
When I run
DELETE FROM images WHERE id in (5, 6);
It also works and deletes these 2 rows.
But when I try to chain these 2 queries together, it fails with error 1175.
DELETE FROM images WHERE id in (SELECT image_id FROM item_images WHERE item_id=1);
Error Code:
1175. You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column To disable safe mode, toggle the option in Preferences -> SQL Editor and reconnect. 0.000 sec
id field is set as private key, not null.
Why does this happen if if id in WHERE is clearly private key?
Is the only way to go around this is to disable safe mode, or is there another way?
Thanks!
Assuming id column (images table) is always greater than zero (0):
mysql> SET SESSION SQL_SAFE_UPDATES := 1;
Query OK, 0 rows affected (0.00 sec)
mysql> DROP TABLE IF EXISTS `item_images`, `images`;
Query OK, 0 rows affected (0.09 sec)
mysql> CREATE TABLE IF NOT EXISTS `images` (
-> `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE IF NOT EXISTS `item_images` (
-> `item_id` BIGINT UNSIGNED NOT NULL,
-> `image_id` BIGINT UNSIGNED NOT NULL
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO `images`
-> VALUES (NULL), (NULL), (NULL),
-> (NULL), (NULL), (NULL);
Query OK, 6 rows affected (0.00 sec)
Records: 6 Duplicates: 0 Warnings: 0
mysql> INSERT INTO `item_images`
-> (`item_id`, `image_id`)
-> VALUES (1, 5), (1, 6), (2, 1),
-> (2, 3), (3, 2), (4, 2);
Query OK, 6 rows affected (0.00 sec)
Records: 6 Duplicates: 0 Warnings: 0
mysql> SELECT `image_id`
-> FROM `item_images`
-> WHERE `item_id` = 1;
+----------+
| image_id |
+----------+
| 5 |
| 6 |
+----------+
2 rows in set (0.00 sec)
mysql> DELETE
-> FROM `images`
-> WHERE `id` IN (SELECT `image_id`
-> FROM `item_images`
-> WHERE `item_id` = 1);
ERROR 1175 (HY000): You are using safe update mode and you tried to update
a table without a WHERE that uses a KEY column
mysql> DELETE
-> FROM `images`
-> WHERE `id` > 0 AND
-> `id` IN (SELECT `image_id`
-> FROM `item_images`
-> WHERE `item_id` = 1);
Query OK, 2 rows affected (0.01 sec)
See db-fiddle.
UPDATE
In the first DELETE the index (key) is not reached.
mysql> SET SESSION SQL_SAFE_UPDATES := 0;
Query OK, 0 rows affected (0.00 sec)
mysql> EXPLAIN DELETE
-> FROM `images`
-> WHERE `id` IN (SELECT `image_id`
-> FROM `item_images`
-> WHERE `item_id` = 1);
+----+--------------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | DELETE | images | NULL | ALL | NULL | NULL | NULL | NULL | 6 | 100.00 | Using where |
| 2 | DEPENDENT SUBQUERY | item_images | NULL | ALL | NULL | NULL | NULL | NULL | 6 | 16.67 | Using where |
+----+--------------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------------+
2 rows in set (0.00 sec)
mysql> EXPLAIN DELETE
-> FROM `images`
-> WHERE `id` > 0 AND
-> `id` IN (SELECT `image_id`
-> FROM `item_images`
-> WHERE `item_id` = 1);
+----+--------------------+-------------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------------+-------------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
| 1 | DELETE | images | NULL | range | PRIMARY | PRIMARY | 8 | const | 6 | 100.00 | Using where |
| 2 | DEPENDENT SUBQUERY | item_images | NULL | ALL | NULL | NULL | NULL | NULL | 6 | 16.67 | Using where |
+----+--------------------+-------------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
2 rows in set (0.01 sec)
See db-fiddle.

mysql insert ignore. Need to get only all inserted rows

Good day everyone! I have MySQL Database with tables on
CREATE TABLE `TableWithInnoDBEngine` (
`userID` int(11) NOT NULL, PRIMARY KEY (`userID`),
UNIQUE KEY `userID_UNIQUE` (`userID`) )
ENGINE=InnoDB DEFAULT CHARSET=utf8;
mysql> select * from TableWithInnoDBEngine;
+--------+
| userID |
+--------+
| 1 |
| 2 |
| 3 |
+--------+
I'm doing :
INSERT IGNORE INTO TableWithInnoDBEngine (UserID) VALUES (1),(2),(3),(4),(5);
2 row(s) affected Records: 5 Duplicates: 3 Warnings: 0
And want to get all affected rows?
SELECT LAST_INSERT_ID() returns only last value (5), but need to return
+--------+
| userID |
+--------+
| 4 |
| 5 |
+--------+
I'm using PHP 5.6.17 + MySQL 5.5.46-0+deb7u1
Thank you for your responses!
I would create a temporary table similar to the destination table, insert all the id-s there, and then you can make 2 selects, one to select the duplicates and one to insert the non-duplicates into table.
I don't understand the second part of your question: inserting all id-s from 1 to 35000, and getting the duplicates? It's equivalent to:
SELECT DISTINCT userId FROM table;
Update:
When you do:
$mysqli->query("INSERT IGNORE INTO TableWithInnoDBEngine (UserID) VALUES (1),(2),(3),(4),(5)");
$info = $mysqli->info();
You can get the information you want in string format like "Records: 3 Duplicates: 0 Warnings: 0" see: http://php.net/manual/en/mysqli.info.php
If you use INSERT ... ON DUPLICATE KEY UPDATE ... istead of INSERT IGNORE ... you can save all duplicate IDs into one string doing something like this:
SET #duplicates := '';
INSERT INTO TableWithInnoDBEngine (UserID) VALUES (1),(2),(3),(4),(5)
ON DUPLICATE KEY UPDATE
userID = userID + if(#duplicates := concat(#duplicates,',',userID),0,0);
SET #duplicates := SUBSTRING(#duplicates FROM 2);
SELECT #duplicates;
You can now parse the resulting string on the application side to filter the inserted data.
Seems that fast and cheap in memory usage solution is to insert new data into temporary table and compare it with original table:
CREATE TABLE `Original_TableWithInnoDBEngine` (
`userID` int(11) NOT NULL,
UNIQUE KEY `userID_UNIQUE` (`userID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `tmp_TableWithInnoDBEngine` (
`userID` int(11) NOT NULL,
UNIQUE KEY `userID_UNIQUE` (`userID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
and then:
INSERT INTO Original_TableWithInnoDBEngine (userID) VALUES (1),(2),(3),(4),(5),(6);
select * from Original_TableWithInnoDBEngine;
+--------+
| userID |
+--------+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
+--------+
INSERT INTO tmp_TableWithInnoDBEngine (userID) VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
select * from tmp_TableWithInnoDBEngine;
+--------+
| userID |
+--------+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
+--------+
and now i use this query to get values that is in tmp table but not in original:
SELECT tmp_TableWithInnoDBEngine.UserID FROM tmp_TableWithInnoDBEngine WHERE tmp_TableWithInnoDBEngine.UserID NOT IN(SELECT UserID FROM original_TableWithInnoDBEngine)";
+--------+
| userID |
+--------+
| 7 |
| 8 |
| 9 |
| 10 |
+--------+

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 SELECT returns NULL for NOT NULL column in stored procedure

I have a stored procedure in which I'm trying to loop over a number of IDs in a table and insert them into another table... problem is the ID turns out as NULL in the loop.
For debugging purposes I have created a table called test, it has two columns named var_name and value. I also made a stored procedure like this:
CREATE DEFINER=`root`#`localhost` PROCEDURE `myProcedure`(#parent INT(11))
BEGIN
INSERT INTO `test`
(`var_name`, `value`)
VALUES
('parent', #parent);
INSERT INTO test (`var_name`, `value`)
SELECT 'id', `id`
FROM `mytable`
WHERE `parent` = #parent;
END
The table mytable has a lot of columns but id is the primary key and obviously NOT NULL, parent allows NULL. The id, parent and value columns are all INT(11).
The following statement:
CALL myProcedure(1);
Produces the following result in test:
+----------+-------+
| var_name | value |
+----------+-------+
| 'parent' | 1 |
| 'id' | NULL |
| 'id' | NULL |
| 'id' | NULL |
| 'id' | NULL |
| 'id' | NULL |
| 'id' | NULL |
+----------+-------+
The number of 'id' rows match the number of rows in mytable with parent = 1, but value is always NULL. Running the following query:
SELECT `id` FROM `mytable` WHERE `parent` = 1;
Produces the expected result:
+----+
| id |
+----+
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
+----+
What's going on here?
Not quite sure what is wrong with the given procedure but I tried creating one similar to yours and it worked pretty well. Here what I did
mysql> create table test (var_name varchar(100),value int);
Query OK, 0 rows affected (0.10 sec)
mysql> create table mytable (id int, parent int);
Query OK, 0 rows affected (0.07 sec)
mysql> insert into mytable values (2,1),(3,1),(4,1),(5,1),(6,1),(7,1);
Query OK, 6 rows affected (0.02 sec)
Records: 6 Duplicates: 0 Warnings: 0
Then added the following procedure
delimiter //
CREATE PROCEDURE myProcedure(parent INT(11))
BEGIN
declare parent_id int ;
set #parent_id := parent ;
INSERT INTO `test`
(`var_name`, `value`)
VALUES
('parent', #parent_id);
INSERT INTO test (`var_name`, `value`)
SELECT 'id', `id`
FROM `mytable`
WHERE `parent` = #parent_id;
END; //
mysql> CALL myProcedure(1);
Query OK, 6 rows affected (0.05 sec)
mysql> select * from test ;
+----------+-------+
| var_name | value |
+----------+-------+
| parent | 1 |
| id | 2 |
| id | 3 |
| id | 4 |
| id | 5 |
| id | 6 |
| id | 7 |
+----------+-------+
7 rows in set (0.00 sec)
Only thing I changed is used a variable inside the procedure to hold the param value and use it in the query.
I lied a little bit in the question. My real stored procedure contained the portion I posted at the beginning, but after a couple of DECLARE, including:
DECLARE id INT;
which replaced the value of id in mytable...

MySQL: How to find newest row using 3 keys? - not as simple as it sounds

I have a product table with 3 columns that can be used to determine the product version: major_version, minor_version and release_date.
I need a query that, as fast as possible, returns the row with the newest product version.
As I see it, the newest version can be determined like this:
a) New major release:
a.major_version = MAX(major_version) AND
a.major_version > any other major_version
b) New minor release:
a.major_version = MAX(major_version) AND
a.major_version = b.major_version AND
a.minor_version > b.minor_version AND
a.release_date >= b.release_date
c) "Silent update" of existing version:
a.major_version = MAX(major_version) AND
a.major_version = b.major_version AND
a.minor_version = b.minor_version AND
a.release_date > b.release_date
Example data:
CREATE TABLE mytest
(
id int(10) NOT NULL,
major_version int(10) NOT NULL,
minor_version int(10) NOT NULL,
release_date datetime NOT NULL,
PRIMARY KEY(id)
);
truncate table mytest;
insert into mytest values(1,1,1,'2012-02-26');
insert into mytest values(2,1,2,'2012-02-26');
insert into mytest values(3,1,3,'2012-02-26');
insert into mytest values(4,2,1,'2012-02-26');
insert into mytest values(5,2,2,'2012-02-26');
insert into mytest values(6,2,2,'2012-02-27');
My brain has deadlocked.. Can a single query accomplish this?
If you are willing to change the table by adding an additional column, I have an easy solution for you.
Setup the following
Add a column called major_minor that contains the value major_version * 100 + minor_version.
Add an index on major_minor and release date
Now just get the max value in the back of the index
First let's make your sample data with my proposed changes
use test
DROP TABLE IF EXISTS mytest;
CREATE TABLE mytest
(
id int(10) NOT NULL,
major_version int(10) NOT NULL,
minor_version int(10) NOT NULL,
major_minor int(10) DEFAULT 0,
release_date datetime NOT NULL,
PRIMARY KEY(id),
KEY release_order_ndx (major_minor,release_date)
);
insert into mytest (id,major_version,minor_version,release_date) values
(1,1,1,'2012-02-26'),(2,1,2,'2012-02-26'),(3,1,3,'2012-02-26'),
(4,2,1,'2012-02-26'),(5,2,2,'2012-02-26'),(6,2,2,'2012-02-27');
UPDATE mytest SET major_minor = major_version * 100 + minor_version;
Here it is loaded
mysql> use test
Database changed
mysql> DROP TABLE IF EXISTS mytest;
Query OK, 0 rows affected (0.03 sec)
mysql> CREATE TABLE mytest
-> (
-> id int(10) NOT NULL,
-> major_version int(10) NOT NULL,
-> minor_version int(10) NOT NULL,
-> major_minor int(10) DEFAULT 0,
-> release_date datetime NOT NULL,
-> PRIMARY KEY(id),
-> KEY release_order_ndx (major_minor,release_date)
-> );
Query OK, 0 rows affected (0.07 sec)
mysql> insert into mytest (id,major_version,minor_version,release_date) values
-> (1,1,1,'2012-02-26'),(2,1,2,'2012-02-26'),(3,1,3,'2012-02-26'),
-> (4,2,1,'2012-02-26'),(5,2,2,'2012-02-26'),(6,2,2,'2012-02-27');
Query OK, 6 rows affected (0.06 sec)
Records: 6 Duplicates: 0 Warnings: 0
mysql> UPDATE mytest SET major_minor = major_version * 100 + minor_version;
Query OK, 6 rows affected (0.07 sec)
Rows matched: 6 Changed: 6 Warnings: 0
mysql>
Now just query the table and order by major_minor desc, release_date desc
mysql> select * from mytest order by major_minor desc, release_date desc;
+----+---------------+---------------+-------------+---------------------+
| id | major_version | minor_version | major_minor | release_date |
+----+---------------+---------------+-------------+---------------------+
| 6 | 2 | 2 | 202 | 2012-02-27 00:00:00 |
| 5 | 2 | 2 | 202 | 2012-02-26 00:00:00 |
| 4 | 2 | 1 | 201 | 2012-02-26 00:00:00 |
| 3 | 1 | 3 | 103 | 2012-02-26 00:00:00 |
| 2 | 1 | 2 | 102 | 2012-02-26 00:00:00 |
| 1 | 1 | 1 | 101 | 2012-02-26 00:00:00 |
+----+---------------+---------------+-------------+---------------------+
6 rows in set (0.02 sec)
Finally, just query the table and order by major_minor desc, release_date desc limit 1
mysql> select * from mytest order by major_minor desc, release_date desc limit 1;
+----+---------------+---------------+-------------+---------------------+
| id | major_version | minor_version | major_minor | release_date |
+----+---------------+---------------+-------------+---------------------+
| 6 | 2 | 2 | 202 | 2012-02-27 00:00:00 |
+----+---------------+---------------+-------------+---------------------+
1 row in set (0.00 sec)
mysql>
Give it a Try !!!
If you do not want to add major_minor, then let's go with your original table
You will need to add an index on the three columns
mysql> use test
Database changed
mysql> DROP TABLE IF EXISTS mytest;
Query OK, 0 rows affected (0.03 sec)
mysql> CREATE TABLE mytest
-> (
-> id int(10) NOT NULL,
-> major_version int(10) NOT NULL,
-> minor_version int(10) NOT NULL,
-> release_date datetime NOT NULL,
-> PRIMARY KEY(id),
-> KEY release_order_ndx (major_version,minor_version,release_date)
-> );
Query OK, 0 rows affected (0.13 sec)
mysql> insert into mytest (id,major_version,minor_version,release_date) values
-> (1,1,1,'2012-02-26'),(2,1,2,'2012-02-26'),(3,1,3,'2012-02-26'),
-> (4,2,1,'2012-02-26'),(5,2,2,'2012-02-26'),(6,2,2,'2012-02-27');
Query OK, 6 rows affected (0.10 sec)
Records: 6 Duplicates: 0 Warnings: 0
Just query the table and order by major_version desc, minor_version desc, release_date desc limit 1
mysql> select * from mytest order by major_version desc,minor_version desc, release_date desc limit 1;
+----+---------------+---------------+---------------------+
| id | major_version | minor_version | release_date |
+----+---------------+---------------+---------------------+
| 6 | 2 | 2 | 2012-02-27 00:00:00 |
+----+---------------+---------------+---------------------+
1 row in set (0.00 sec)
mysql>