SQL with subquery WHERE condition is empty - mysql

I am hoping someone can advise on what is wrong.
SELECT sms.id FROM sms INNER JOIN screens ON sms.screen_id = screens.id WHERE screens.experience_id = '108';
AND
SELECT id FROM sms
WHERE screen_id IN (SELECT id FROM screens WHERE experience_id = 108 )
... returns an empty row, but there are rows that should be returned.
To clarify...
SELECT id FROM sms
... returns all rows in SMS
SELECT id FROM sms
WHERE screen_id IN (SELECT id FROM screens)
... returns all rows in SMS and
SELECT id FROM screens WHERE experience_id = 108
... returns all rows from screens with that id.
SQL to make the tables...
CREATE TABLE IF NOT EXISTS `screens` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
`device_id` int(11) NOT NULL,
`type` varchar(32) NOT NULL,
`description` text NOT NULL,
`position` int(11) NOT NULL,
`experience_id` int(11) NOT NULL,
`image` varchar(512) NOT NULL,
`url` varchar(512) NOT NULL,
`persona_id` int(11) NOT NULL,
`socialPost` text NOT NULL,
`socialLinkHeadline` varchar(512) NOT NULL,
`socialLinkDescription` text NOT NULL,
`socialLink` varchar(512) NOT NULL,
`socialAction` varchar(64) NOT NULL,
`bgcolor` varchar(16) NOT NULL DEFAULT '#fff',
`created` datetime NOT NULL,
`modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`user_id` int(11) NOT NULL DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=472 ;
CREATE TABLE IF NOT EXISTS `sms` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`source` varchar(16) NOT NULL,
`content` text NOT NULL,
`position` int(11) NOT NULL,
`screen_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=20 ;
A GIF of me running these queries to verify is here: https://ibb.co/gzPFsd
I am at a loss and can see that people can't replicate, thanks!

I don't get what's wrong in your query but you can do that using join as well.
SELECT sms.id FROM sms INNER JOIN screens ON sms.screen_id = screens.id WHERE screens.experience_id = '108';

Your query works fine , here's the proof.
DROP TABLE IF EXISTS SMS,SCREENS;
CREATE TABLE SMS(ID INT, SCREEN_ID INT);
CREATE TABLE SCREENS(ID INT, EXPERIENCE_ID INT);
INSERT INTO SMS VALUES (1,1),(2,2);
INSERT INTO SCREENS VALUES(1,108),(2,100);
SELECT id FROM sms
WHERE screen_id IN (SELECT id FROM screens WHERE experience_id = 108 );
+------+
| id |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
Assuming that my data model and yours are the same.

Related

Can UPDATE statement be used as INSERT statement?

I'm using MYSQL and my tables are like below. what I need to do is to update speciality_name field in specialities table corresponding to list_of_specialities in clinics table but when I do it like
below
UPDATE clinics c
LEFT
JOIN specialities s
ON s.clinic_id = c.clinic_id
SET s.speciality_name = concat_ws('',c.list_of_specialities,s.speciality_id)
WHERE s.clinic_id = c.clinic_id
my table looks like this
speciality_id speciality_name clinic_id
6 data 16
since there is no speciality_id for other list_of_specialities I think I must insert others but I need it to be automatically inserted and what I really need is that the table to look like this
speciality_id speciality_name clinic_id
6 data 16
7 data2 16
8 data3 16
9 data4 16
10 asdsads 16
CREATE TABLE IF NOT EXISTS `clinics` (
`clinic_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`clinic_name` varchar(100) DEFAULT NULL,
`location` varchar(500) DEFAULT NULL,
`list_of_specialities` json DEFAULT NULL,
PRIMARY KEY (`clinic_id`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `doctors` (
`doctor_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`first_name` varchar(50) DEFAULT NULL,
`last_name` varchar(50) DEFAULT NULL,
`age` int(10) UNSIGNED DEFAULT NULL,
`clinic_id` int(10) UNSIGNED NOT NULL,
`speciality_id` int(10) UNSIGNED NOT NULL,
`user_id` int(10) UNSIGNED NOT NULL,
PRIMARY KEY (`doctor_id`),
KEY `Doctor_FKIndex1` (`clinic_id`),
KEY `Doctor_FKIndex2` (`speciality_id`),
KEY `Doctor_FKIndex3` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `specialities` (
`speciality_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`speciality_name` varchar(100) DEFAULT NULL,
`clinic_id` int(10) UNSIGNED NOT NULL,
PRIMARY KEY (`speciality_id`),
KEY `Speciality_FKIndex1` (`clinic_id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
problem solved with a little change to speciality_name field. it should be a UNIQUE INDEX and REPLACE statement must be used. here is an example:
REPLACE
INTO specialities
SET speciality_name = 'data1', clinic_id = '16'

mysql NOT EXISTS, very slow - How to improve?

I've got a small question about trying to ompimise this command I'm running on a table in my database. The table has over 934,836 rows and grows daily by about 12,000.
It holds snapshots of tanks taken daily. What I'm trying to achieve is to see the difference in the snapshots. i.e. see if the player has purchased any new tanks.
The actual snapshot data per account_id is only 100 to 250 rows.
Table wot_snapshots:
CREATE TABLE `wot_snapshots` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`snapshot` varchar(30) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=95 DEFAULT CHARSET=latin1
Table wot_tanks_all:
CREATE TABLE `wot_tanks_all` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`snapshot` int(11) NOT NULL,
`account_id` int(11) NOT NULL,
`tank_id` int(6) NOT NULL,
`wn8` float DEFAULT NULL,
`spotted` int(11) NOT NULL,
`avg_damage_blocked` decimal(6,2) NOT NULL,
`capture_points` int(11) NOT NULL,
`explosion_hits` int(11) NOT NULL,
`piercings` int(11) NOT NULL,
`xp` int(11) NOT NULL,
`survived_battles` int(11) NOT NULL,
`dropped_capture_points` int(11) NOT NULL,
`damage_dealt` int(11) NOT NULL,
`hits_percents` int(11) NOT NULL,
`draws` int(11) NOT NULL,
`battles` int(11) NOT NULL,
`damage_received` int(11) NOT NULL,
`frags` int(11) NOT NULL,
`direct_hits_received` int(11) NOT NULL,
`hits` int(11) NOT NULL,
`battle_avg_xp` int(11) NOT NULL,
`wins` int(11) NOT NULL,
`losses` int(11) NOT NULL,
`piercings_received` int(11) NOT NULL,
`no_damage_direct_hits_received` int(11) NOT NULL,
`shots` int(11) NOT NULL,
`explosion_hits_received` int(11) NOT NULL,
`tanking_factor` decimal(2,2) NOT NULL,
`mark_of_mastery` int(1) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=934837 DEFAULT CHARSET=utf8
Query:
SELECT t1.tank_id, wot_tanks.short_name_i18n FROM wot_tanks_all t1
JOIN wot_tanks ON t1.tank_id = wot_tanks.tank_id
WHERE NOT EXISTS (SELECT tank_id
FROM wot_tanks_all t2
WHERE t1.tank_id = t2.tank_id AND account_id = 527080765 AND snapshot = 60)
AND account_id = 527080765 AND snapshot = 93
Output:
tank_id short_name_i18n
8465 Panther II
53505 T-127
54865 Light VIC
Its currently taking around 30 seconds to run. Am I best to do this all in mysql or offload some of it to PHP?
Any advice and help is greatly appreciated
Thanks,
Jason
Edit: This has just been put together from Google. Still learning!
There is no index on tank id so joining on it will be very slow,I`ve rewritten it to eliminate the self join
SELECT t1.tank_id, wot_tanks.short_name_i18n FROM wot_tanks_all t1
JOIN wot_tanks
ON t1.tank_id = wot_tanks.tank_id
GROUP BY t1.tank_id,wot_tanks.short_name_i18n
HAVING SUM(account_id = 527080765 AND snapshot = 60)=0
AND SUM(account_id = 527080765 AND snapshot = 93)>0
These indexes will speed things up
ALTER TABLE wot_tanks_all ADD KEY(account_id ,snapshot )
ALTER TABLE wot_tanks_all ADD KEY(tank_id )

getting number of records from 2 tables - one to many relationship

I have problem with search query that i have to built on the fly to return records from the database.
I have 2 tables: adds andadds_filters`. For the sake of simplicity, i make the table adds shorter than it is, removing some of the (irrelevant) fields
My table structure:
CREATE TABLE IF NOT EXISTS `adds` (
`addid` int(11) NOT NULL AUTO_INCREMENT,
`memberid` int(11) NOT NULL,
`isnew` int(11) NOT NULL,
`catid` int(11) NOT NULL,
`manufacturerid` int(11) NOT NULL,
`modelid` varchar(255) DEFAULT NULL,
`colorid` int(11) DEFAULT NULL,
`geographicareaid` int(45) NOT NULL,
`addtypeid` varchar(45) NOT NULL,
`addcreatedon` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`addvalidfrom` date NOT NULL,
`addvaliduntil` date NOT NULL,
`addcreatedfromip` varchar(255) NOT NULL,
`yearofmanufacturing` varchar(255) DEFAULT NULL,
`monthofmanufacturing` int(11) DEFAULT NULL,
`hoursused` int(11) DEFAULT NULL,
`cc2` int(11) DEFAULT NULL,
`horsepowers` int(11) DEFAULT NULL,
`metalic` tinyint(4) DEFAULT NULL,
`isdamaged` tinyint(4) DEFAULT NULL,
`price` float DEFAULT NULL,
`hasvat` tinyint(4) NOT NULL,
`canbenegotiated` tinyint(4) DEFAULT NULL,
`addtitle` varchar(255) DEFAULT NULL,
`addtext` text NOT NULL,
`youtubevideo` varchar(255) DEFAULT NULL,
`visible` tinyint(4) DEFAULT NULL,
`ff1` varchar(255) DEFAULT NULL,
`ff2` varchar(255) DEFAULT NULL,
`ff3` varchar(255) DEFAULT NULL,
`ff4` varchar(255) DEFAULT NULL,
PRIMARY KEY (`addid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=43 ;
CREATE TABLE IF NOT EXISTS `adds_filters` (
`addfilterid` int(11) NOT NULL AUTO_INCREMENT,
`addid` int(11) NOT NULL,
`filterid` int(11) NOT NULL,
PRIMARY KEY (`addfilterid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=45 ;
Here is the fiddle
Problem is that user can add more than one filter for each adds, that is if the
vehicle has AC,GPS, removable cabin and so on...This data is stored in the adds_filters. So, one add can have many filters.
How the query should look like when user choose that catid is 1, manufacturerid is 1 and then users check filters with ids
67 and 158 for example?
I would prefer view over the query, but i have no idea how can i build such view. Reason from preferring the view is that in such a case, i will be able to use select * instead of complicated queries...
Any help will be deeply appreciated.
With this table structure, you gonna need subqueries for each checked filterid, if you want filterids to be displayed.
Without displaying, you can just use DISTINCT and IN.
Here is the query without displaying filterids
SELECT DISTINCT a.*
FROM adds a
JOIN adds_filters f
ON a.`addid` = f.`addid`
WHERE a.`catid` = 1
AND a.`manufacturerid` = 1
AND f.`filterid` IN (67, 158);
Here is the query, that displays two different filterids:
SELECT t1.*, t2.filterid as filterid2
FROM
(
SELECT DISTINCT a.*,
f.`filterid`
FROM adds a
JOIN adds_filters f
ON a.`addid` = f.`addid`
WHERE a.`catid` = 1
AND a.`manufacturerid` = 1
AND f.`filterid` = 67
) t1
JOIN
(
SELECT DISTINCT a.`addid`,
f.`filterid`
FROM adds a
JOIN adds_filters f
ON a.`addid` = f.`addid`
WHERE a.`catid` = 1
AND a.`manufacturerid` = 1
AND f.`filterid` = 158
) t2
ON t1.addid = t2.addid;

Need suggestion on optimization of MYSQL query

SELECT `tb1`.`id`
FROM `table1` as tb1
INNER JOIN `table2` as tb2 ON tb1.id = tb2.id
INNER JOIN `table3` as tb3 ON tb1.id = tb3.id
WHERE (tb1.item_id = '1')
AND (tb1.user_id = '20')
AND (tb1.type IN ('UPDATE1','UPDATE2','UPDATE3'))
AND (tb1.status = 'DELIVERED')
ORDER BY tb1.date DESC
LIMIT 100
CREATE TABLE `table1` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` INT(11) UNSIGNED NOT NULL,
`item_id` INT(11) UNSIGNED NULL DEFAULT NULL,
`source` ENUM('CPAS','UNIQUE_KEY','BILLING_PARTNER','GAME','MERCURY') NOT NULL,
`date` DATETIME NOT NULL,
`status` ENUM('PENDING','DELIVERED','FAILED','REFUNDED') NOT NULL,
`source_transaction_id` VARCHAR(127) NULL DEFAULT NULL,
`type` ENUM('UPDATE1','UPDATE2','UPDATE3','UPDATE4') NULL DEFAULT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `table2` (
`id_p` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`id` INT(11) UNSIGNED NOT NULL,
`amount` DECIMAL(18,2) NOT NULL,
`old_balance` DECIMAL(18,2) NULL DEFAULT NULL,
`description` VARCHAR(255) NULL DEFAULT NULL,
`date` DATETIME NULL DEFAULT NULL,
`wallet_currency_id` INT(11) NULL DEFAULT NULL,
`wallet_currency_code` VARCHAR(50) NULL DEFAULT NULL,
`wallet_currency_name` VARCHAR(100) NULL DEFAULT NULL,
`type` ENUM('GAIN','SPENT') NULL DEFAULT NULL,
PRIMARY KEY (`id_p`),
INDEX `id` (`id`)
)
CREATE TABLE `table3` (
`id_p` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`id` INT(11) UNSIGNED NOT NULL,
`amount` DECIMAL(18,2) NOT NULL,
`old_balance` DECIMAL(18,2) NULL DEFAULT NULL,
`description` VARCHAR(255) NULL DEFAULT NULL,
`date` DATETIME NULL DEFAULT NULL,
`wallet_currency_id` INT(11) NULL DEFAULT NULL,
`wallet_currency_code` VARCHAR(50) NULL DEFAULT NULL,
`wallet_currency_name` VARCHAR(100) NULL DEFAULT NULL,
`type` ENUM('GAIN','SPENT') NULL DEFAULT NULL,
PRIMARY KEY (`id_p`),
INDEX `id` (`id`)
)
What optimization possible on the above query.
table1 contains more than 500000 rows, table2 and table3 can also have more than 100000 rows.
As per query for particular player and game table1 can have more than 100000 rows.
Is the above query is ok for large large tables or should I split the query in multiple queries.
NDB Engine used.
Please suggest me possible optimization.
Thanks,
Shiv
See comments above, but, at a guess, an index on (item_id,user_id,type,status) might help.

Get same IDs from Detail Table

I have 2 tables in my mysql database:
CREATE TABLE IF NOT EXISTS `RECIPES` (
`recipes_id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(50) COLLATE utf8_bin NOT NULL,
`text` varchar(2000) COLLATE utf8_bin NOT NULL,
`count_persons` int(11) NOT NULL,
`duration` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`date` datetime NOT NULL,
`accepted` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`recipes_id`),
KEY `recipes_user_fk` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=88 ;
CREATE TABLE IF NOT EXISTS `RECIPES_POS` (
`recipes_pos_id` int(11) NOT NULL AUTO_INCREMENT,
`recipes_id` int(11) NOT NULL,
`ingredients_id` int(11) NOT NULL,
`ingredients_value` int(11) NOT NULL,
PRIMARY KEY (`recipes_pos_id`),
KEY `recipe_pos_rec_id` (`recipes_id`),
KEY `recipes_pos_ingredient_fk` (`ingredients_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=58 ;
In the Recipe_Pos Table are many entries. This table shows what ingredients are used in the Recipe.
Now i want to find the recipe which contains incredients like powder and sugar:
SELECT r.recipes_id FROM RECIPES r, RECIPES_POS rp WHERE r.recipes_id = rp.recipes_id AND rp.ingredients_id =6 AND rp.ingredients_id =4
this statment is wrong because a entry in Recipe_Pos can'T contains both incredients.
Whats the right query? It should works with only 1 incredient and more
select r.recipes_id
from RECIPES r
inner join RECIPES_POS rp on r.recipes_id = rp.recipes_id
where rp.ingredients_id in (4, 6)
group by r.recipes_id
having count(distinct rp.ingredients_id) = 2