How to update the WHERE clause to select identical data? - mysql

CREATE TABLE `schedule` (
`id` smallint(6) NOT NULL AUTO_INCREMENT,
`aircraftType` varchar(50) DEFAULT NULL,
//...other fields
PRIMARY KEY (`id`),
) ENGINE=MyISAM AUTO_INCREMENT=5611 DEFAULT CHARSET=latin1;
CREATE TABLE `aircrafts` (
`id` smallint(6) NOT NULL AUTO_INCREMENT,
`aircraftType` varchar(50) DEFAULT NULL,
//...other fields
PRIMARY KEY (`id`),
) ENGINE=MyISAM AUTO_INCREMENT=5611 DEFAULT CHARSET=latin1;
SAMPLE CONTENT OF DB TABLES:
Table "Schedule"
aircraftType = "320"
Table "Aircrafts"
aircraftType = "A320"
aircraftType = "A330"
Query:
SELECT *
FROM Schedule F, Aircrafts A
WHERE F.aircraftType = A.aircraftType;
How to update this query in such a way that aircratf types "320" and "A320" would be considered as similar in the WHERE clause?

SELECT *
FROM Schedule F, Aircrafts A
WHERE F.aircraftType = A.aircraftType LIKE CONCAT('%', F.aircraftType, '%')
OR
LIKE CONCAT('\"','%', F.aircraftType, '%','\"')-added double quotes.

Try cutting of first char with SUBSTRING() :
SELECT *
FROM Schedule F, Aircrafts A
WHERE F.aircraftType = SUBSTRING(A.aircraftType, 2)
Or like #Mihai suggested, just put % on field that hasn't have A in it :
SELECT *
FROM Schedule F, Aircrafts A
WHERE CONCAT('%', F.aircraftType) LIKE A.aircraftType
But best solution would be to update data for identical relation string.

Related

MySQL Query to get all neighborhoods which a user did not join

I want to get all the neighborhoods (based on different zips) which the user is not a member of already.
I have a users table and several other tables like this:
table name: neighborhood
CREATE TABLE neighborhood(
`neighborhood_id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`description` TEXT DEFAULT NULL,
`neighborhood_postal_code` VARCHAR(255) NOT NULL,
`region_neighborhood` VARCHAR(255) NOT NULL,
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`neighborhood_id`),
INDEX `neighborhood_region_neighborhood_FI_1` (`region_neighborhood`)
) ENGINE = InnoDB;
table name: user_neighborhood
CREATE TABLE user_neighborhood(
`user_id` INT(11) NOT NULL,
`neighborhood_id` INT(11) NOT NULL,
`activity_circle` INT(1) DEFAULT 0,
`duo_circle` INT(1) DEFAULT 0,
FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`),
FOREIGN KEY (`neighborhood_id`) REFERENCES `neighborhood` (`neighborhood_id`)
) ENGINE = InnoDB;
I have tried the following query, but the result is not correct:
SELECT n.*
FROM `neighborhood` as n
left join user_neighborhood as un on n.neighborhood_id = un.neighborhood_id
where un.user_id != 1 and n.neighborhood_postal_code IN ('2000', '2100')
UPDATE: I managed to make the query seem correct at first instance using a subquery like this:
select *
from neighborhood
where neighborhood_id NOT IN (select neighborhood_id from user_neighborhood where user_id != 1)
AND neighborhood_postal_code IN ('2000', '2100')
However, it also returns (some) of the neighborhoods i am in already. It doesnot make much sense to me why only some..
Why exactly are you adding user_id != 1 in your subquery? I think if you know the id of the user you want to fetch for lets say user_id is 10 then use where user_id = 10 in subquery like:
select *
from neighborhood
where neighborhood_id NOT IN (select distinct neighborhood_id from user_neighborhood where user_id = 10)
AND neighborhood_postal_code IN ('2000', '2100')
But if you want to fetch all the neighbors which have no user then you can use this Query:
select *
from neighborhood
where neighborhood_id NOT IN (select distinct neighborhood_id from user_neighborhood)
AND neighborhood_postal_code IN ('2000', '2100')
Hope this helps!

Can I improve my movie selecting SQL query

I've created a database to store movies data. My tables are the following:
movies:
CREATE TABLE IF NOT EXISTS `movies` (
`movieId` int(11) NOT NULL AUTO_INCREMENT,
`imdbId` varchar(255) DEFAULT NULL,
`imdbRating` float DEFAULT NULL,
`movieTitle` varchar(255) NOT NULL,
`movieLength` varchar(255) NOT NULL,
`imdbRatingCount` varchar(255) NOT NULL,
`poster` varchar(255) NOT NULL,
`year` varchar(255) NOT NULL,
PRIMARY KEY (`movieId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
I have a table in which i store movie actors:
CREATE TABLE IF NOT EXISTS `actors` (
`actorId` int(10) NOT NULL AUTO_INCREMENT,
`actorName` varchar(255) NOT NULL,
PRIMARY KEY (`actorId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
And one other in which i store the relation between the movies and actors: (movieActor)
CREATE TABLE IF NOT EXISTS `movieActor` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`movieId` int(10) NOT NULL,
`actorId` int(10) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Now when i want to select a list of movies in which are the selected actors my query is:
SELECT *
FROM movies m inner join
(SELECT movieId FROM movieActor WHERE actorId IN(1,2,3) GROUP BY movieId having count(*) = 3) ma ON m.movieId = ma.movieId
WHERE imdbRating IS NOT NULL ORDER BY imdbRating DESC
This is working perfectly, but i don't know that this is the optimal table structure and query to accomplish this. Are there any better table structure to store data or query the list?
First of all, use indexes on your tables. In my opinion it should be useful to have 3 indexes on movieActor. MovieId - ActorID - MovieIdActorId.
Second try tu use foreign keys. These help to identify the best execution plan for your dbs.
Third try to avoid generating temp tables in your execution plan of your query. Subselects often creates temp tables which are used when the database has to temporarily save something in the RAM. To check this, write EXPLAIN in front of goer query.
I would write it like this:
SELECT m.*, movieActor
FROM movies m inner join
movieActor ma ON m.movieId = ma.movieId
WHERE imdbRating IS NOT NULL
and actorId IN(1,2,3)
GROUP BY movieId
having count(*) = 3)
ORDER BY imdbRating DESC
(Not tested)
Just try to optimize it with the EXPLAIN keyword. It also can help you to create the right indexes.

Mysql query optimisation to transform subquery in join without DISTINCT

I have tables:
CREATE TABLE IF NOT EXISTS `bk_cart_rule` (
`id_cart_rule` int(10) unsigned NOT NULL DEFAULT '0',
`cart_rule_restriction` tinyint(1) unsigned NOT NULL DEFAULT '0',
KEY `id_cart_rule` (`id_cart_rule`),
KEY `cart_rule_restriction` (`cart_rule_restriction`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `bk_cart_rule_combination` (
`id_cart_rule_1` int(10) unsigned NOT NULL,
`id_cart_rule_2` int(10) unsigned NOT NULL,
KEY `id_cart_rule_1` (`id_cart_rule_1`),
KEY `id_cart_rule_2` (`id_cart_rule_2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `bk_cart_rule_lang` (
`id_cart_rule` int(10) unsigned NOT NULL,
`id_lang` int(10) unsigned NOT NULL,
KEY `id_cart_rule` (`id_cart_rule`),
KEY `id_lang` (`id_lang`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
And a query :
SELECT SQL_NO_CACHE cr.*, crl.*, 1 as selected FROM bk_cart_rule cr
LEFT JOIN bk_cart_rule_lang crl ON (cr.id_cart_rule = crl.id_cart_rule AND crl.id_lang = 2)
WHERE cr.id_cart_rule != 375 AND
( cr.cart_rule_restriction = 0 OR
cr.id_cart_rule IN (
SELECT IF(id_cart_rule_1 = 375, id_cart_rule_2, id_cart_rule_1) FROM bk_cart_rule_combination WHERE 375 = id_cart_rule_1 OR 375 = id_cart_rule_2 ) )
Obvious optimization is:
SELECT SQL_NO_CACHE DISTINCT cr.*, crl.* 1 as selected FROM bk_cart_rule cr
LEFT JOIN bk_cart_rule_lang crl ON (cr.id_cart_rule = crl.id_cart_rule AND crl.id_lang = 2)
LEFT JOIN bk_cart_rule_combination crc ON (375 = crc.id_cart_rule_1 AND cr.id_cart_rule = crc.id_cart_rule_2) OR (375 = crc.id_cart_rule_2 AND cr.id_cart_rule = crc.id_cart_rule_1)
WHERE cr.id_cart_rule != 375 AND (cr.cart_rule_restriction = 0 OR NOT ISNULL(crc.id_cart_rule_1))
But how can i get rid off DISTINCT (in bk_cart_rule_combination I've two-way combinations : )
id_cart_rule_1 id_cart_rule_2
375 776
776 375
Or maybe there is a better optimization possible?
If the ordering of the cart rules is not important, then add the constraint that the id for the first one is less than the id of the second one. That is, put them in the table in order.
Sadly, MySQL doesn't allow simple check constraints. Instead, you have to implement it in some other way. Here are three:
Implement an insert/update trigger to maintain the ordering (and prevent duplicates).
Implement the logic on the application side.
Wrap all data modifications in stored procedures and implement the logic in the stored procedure.
If you don't want to go through all that trouble (which would probably help with other issues), you can replace the select distinct with:
group by least(id_cart_rule_1, id_cart_rule_2), greatest(id_cart_rule_1, id_cart_rule_2)

MySQL Table Performance

I've a table in MySQL which has more than 50 Million rows. Bellow is the table structure:
CREATE TABLE `links` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`loc` text NOT NULL,
`lastmod` datetime NOT NULL,
`changefreq` varchar(15) NOT NULL,
`priority` float NOT NULL,
`isdownloaded` tinyint(1) NOT NULL,
`mainrepoid` bigint(20) NOT NULL,
PRIMARY KEY (`id`),
FULLTEXT KEY `locfulltext` (`loc`)
) ENGINE=MyISAM AUTO_INCREMENT=11426345 DEFAULT CHARSET=latin1
FullText is enabled on field loc. I need to fetch all the rows containing both name and details words. The following query didn't return the expected results:
SELECT *
FROM links
WHERE
MATCH (
loc
)
AGAINST (
'name +details' IN BOOLEAN MODE
)
so I am forced to use the following query:
SELECT id, loc
FROM links
WHERE
loc like '%name%' and
loc like '%details%'
Is there any better alternative?
I don't know which version of mySql do you use. But the following query that you give works very well in my server.
SELECT *
FROM links
WHERE
MATCH (
loc
)
AGAINST (
'name +details' IN BOOLEAN MODE
)
If you fetch a problem with this query till now then just try with add a plus(+) sign before name . Just like :
SELECT *
FROM links
WHERE
MATCH (
loc
)
AGAINST (
'+name +details' IN BOOLEAN MODE
)
For further more information see the following link:
http://dev.mysql.com/doc/refman/5.0/en/fulltext-boolean.html

MySQL query killing my server

Looking at this query there's got to be something bogging it down that I'm not noticing. I ran it for 7 minutes and it only updated 2 rows.
//set product count for makes
$tru->query->run(array(
'name' => 'get-make-list',
'sql' => 'SELECT id, name FROM vehicle_make',
'connection' => 'core'
));
while($tempMake = $tru->query->getArray('get-make-list')) {
$tru->query->run(array(
'name' => 'update-product-count',
'sql' => 'UPDATE vehicle_make SET product_count = (
SELECT COUNT(product_id) FROM taxonomy_master WHERE v_id IN (
SELECT id FROM vehicle_catalog WHERE make_id = '.$tempMake['id'].'
)
) WHERE id = '.$tempMake['id'],
'connection' => 'core'
));
}
I'm sure this query can be optimized to perform better, but I can't think of how to do it.
vehicle_make = 45 rows
taxonomy_master = 11,223 rows
vehicle_catalog = 5,108 rows
All tables have appropriate indexes
UPDATE: I should note that this is a 1-time script so overhead isn't a big deal as long as it runs.
CREATE TABLE IF NOT EXISTS `vehicle_make` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
`product_count` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=46 ;
CREATE TABLE IF NOT EXISTS `taxonomy_master` (
`product_id` int(10) NOT NULL,
`v_id` int(10) NOT NULL,
`vehicle_requirement` varchar(255) DEFAULT NULL,
`is_sellable` enum('True','False') DEFAULT 'True',
`programming_override` varchar(25) DEFAULT NULL,
PRIMARY KEY (`product_id`,`v_id`),
KEY `idx2` (`product_id`),
KEY `idx3` (`v_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `vehicle_catalog` (
`v_id` int(10) NOT NULL,
`id` int(11) NOT NULL,
`v_make` varchar(255) NOT NULL,
`make_id` int(11) NOT NULL,
`v_model` varchar(255) NOT NULL,
`model_id` int(11) NOT NULL,
`v_year` varchar(255) NOT NULL,
PRIMARY KEY (`v_id`,`v_make`,`v_model`,`v_year`),
UNIQUE KEY `idx` (`v_make`,`v_model`,`v_year`),
UNIQUE KEY `idx2` (`v_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Update: The successful query to get what I needed is here....
SELECT
m.id,COUNT(t.product_id) AS CountOf
FROM taxonomy_master t
INNER JOIN vehicle_catalog v ON t.v_id=v.id
INNER JOIN vehicle_make m ON v.make_id=m.id
GROUP BY m.id;
without the tables/columns this is my best guess from reverse engineering the given queries:
UPDATE m
SET product_count =COUNT(t.product_id)
FROM taxonomy_master t
INNER JOIN vehicle_catalog v ON t.v_id=v.id
INNER JOIN vehicle_make m ON v.make_id=m.id
GROUP BY m.name
The given code loops over each make, and then runs a query the counts for each. My answer just does them all in one query and should be a lot faster.
have an index for each of these:
vehicle_make.id cover on name
vehicle_catalog.id cover make_id
taxonomy_master.v_id
EDIT
give this a try:
CREATE TEMPORARY TABLE CountsOf (
id int(11) NOT NULL
, CountOf int(11) NOT NULL DEFAULT 0.00
);
INSERT INTO CountsOf
(id, CountOf )
SELECT
m.id,COUNT(t.product_id) AS CountOf
FROM taxonomy_master t
INNER JOIN vehicle_catalog v ON t.v_id=v.id
INNER JOIN vehicle_make m ON v.make_id=m.id
GROUP BY m.id;
UPDATE taxonomy_master,CountsOf
SET taxonomy_master.product_count=CountsOf.CountOf
WHERE taxonomy_master.id=CountsOf.id;
instead of using nested query ,
you can separated this query to 2 or 3 queries,
and in php insert the result of the inner query to the out query ,
its faster !
#haim-evgi Separating the queries will not increase the speed significantly, it will just shift the load from the DB server to the Web server and create overhead of moving data between the two servers.
I am not sure with the appropriate indexes you run such query 7 minutes. Could you please show the table structure of the tables involved in these queries.
Seems like you need the following indices:
INDEX BTREE('make_id') on vehicle_catalog
INDEX BTREE('v_id') on taxonomy_master