join query does not return null values - mysql

I have this table with units/homes
CREATE TABLE `units` (
`id` bigint NOT NULL AUTO_INCREMENT,
`cancellation_policy` varchar(255) DEFAULT NULL,
`description` varchar(255) DEFAULT NULL,
`image_url` varchar(255) NOT NULL,
`price` decimal(19,2) NOT NULL,
`region` varchar(255) NOT NULL,
`title` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UKha7gwhuig6p6vftvoghfi2b7g` (`title`,`image_url`),
UNIQUE KEY `UK_pdd7pto9vch2kb58kohy96a5f` (`image_url`),
UNIQUE KEY `UK_58rre8c1gk28a7d5p6wguiti9` (`title`)
)
and this one with reviews
CREATE TABLE `reviews` (
`id` bigint NOT NULL AUTO_INCREMENT,
`description` varchar(255) DEFAULT NULL,
`stars` int NOT NULL,
`user_id` varchar(255) NOT NULL,
`unit_id` bigint NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UKc3rd8vjkpbcda34jomifuybu9` (`user_id`,`unit_id`),
KEY `FKbgbdator49pjrbriaktrbv1q2` (`unit_id`),
CONSTRAINT `FKbgbdator49pjrbriaktrbv1q2` FOREIGN KEY (`unit_id`) REFERENCES `units` (`id`)
)
and I want to get all movies together with the average rating. However this query does not return me back movies without ratings (NULL) values. This query does not return movies without ratings
select
u.id, u.cancellation_policy, u.description, u.image_url, u.price, u.region, u.title, round(avg(stars),0) as ratings
from units u
inner join
reviews r
ON u.id = r.unit_id
group by u.id
What is the correct way to get all movies including those w/o stars?

A LEFT JOIN would show you all units even those that have no reviews
SELECT
u.id,
u.cancellation_policy,
u.description,
u.image_url,
u.price,
u.region,
u.title,
ROUND(AVG(IFNULL(stars,0)), 0) AS ratings
FROM
units u
LEFT JOIN
reviews r ON u.id = r.unit_id
GROUP BY u.id

Try a LEFT JOIN instead of the INNER JOIN

Related

Joining two tables with a LIKE statement

I am trying to join my tables with a LIKE STATEMENT and my current query is this :
SELECT
COUNT(comment_id) AS nb,
produit.nom
FROM
comments
INNER JOIN produit ON comments.comment_location like (select '%'+produit.id+'%')
GROUP BY
comment_location
and the SQL FOR THE TABLES is this :
table comments:
CREATE TABLE `comments` (
`comment_id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`comment_date` datetime NOT NULL,
`comment_content` varchar(255) NOT NULL,
`comment_location` varchar(255) NOT NULL,
PRIMARY KEY (`comment_id`),
KEY `user_id` (`user_id`),
CONSTRAINT `comments_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=41 DEFAULT CHARSET=utf8
table produit :
CREATE TABLE `produit` (
`id` int(11) NOT NULL,
`nom` varchar(25) NOT NULL,
`description` varchar(200) NOT NULL,
`categorie` varchar(25) NOT NULL,
`image` varchar(200) NOT NULL,
`prix` float NOT NULL,
`quantite` int(11) NOT NULL,
`prix_initiale` float NOT NULL,
PRIMARY KEY (`id`),
KEY `FK_CATEGORIE` (`categorie`),
CONSTRAINT `FK_CATEGORIE` FOREIGN KEY (`categorie`) REFERENCES `categorie` (`nom`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
my query does execute but doesn't return the table i was looking for
but if i try replacing produit.id in (select '%'+produit.id+'%') with a constant the table shows the corresponding rows .
What am i doing wrong
You need to modify query as below. You dont need SELECT again in the LIKE clause.
SELECT
COUNT(comment_id) AS nb,
produit.nom
FROM
comments
INNER JOIN produit ON comments.comment_location like CONCAT('%',produit.id,'%')
GROUP BY
comment_location
SELECT COUNT(comment_id) AS nb, produit.nom AS nom FROM comments INNER JOIN produit ON comments.comment_location LIKE CONCAT('%', produit.id, '%')
GROUP BY comment_location
by #Phil

Big query on a big mysql database

I have a big query to count 3 distinct things on same data table:
SELECT leagues.feed_league_id AS mleague,
leagues.league_id AS mleague_id,
leagues.league_name, countries.feed_name,
(SELECT COUNT(DISTINCT m2.match_id)
FROM `matches` AS m2
LEFT JOIN stats ON stats.match_id=m2.match_id
LEFT JOIN leagues AS l1 ON m2.feed_league_id=l1.feed_league_id
WHERE stats.tipo='Golos1ª2ª' AND
m2.status='FT' AND
(m2.home_ht_score*1+ m2.away_ht_score*1) >1 AND
m2.home_ht_score REGEXP '[0-9]+' AND
m2.away_ht_score REGEXP '[0-9]+' AND
m2.feed_league_id=mleague
) AS Total,
(SELECT COUNT(DISTINCT m3.match_id)
FROM `matches` AS m3
LEFT JOIN stats ON stats.match_id=m3.match_id
LEFT JOIN leagues AS l1 ON m3.feed_league_id=l1.feed_league_id
WHERE stats.tipo='Golos1ª2ª' AND
m3.status='FT' AND
(m3.home_ht_score*1+ m3.away_ht_score*1) >1 AND
(m3.home_ft_score*1+m3.away_ft_score*1)-(m3.home_ht_score*1+ m3.away_ht_score*1)>0 AND
m3.home_ht_score REGEXP '[0-9]+' AND
m3.away_ht_score REGEXP '[0-9]+' AND
m3.feed_league_id=mleague
) AS Golos,
(SELECT COUNT(DISTINCT m2.match_id)
FROM `matches` AS m2
LEFT JOIN stats ON stats.match_id=m2.match_id
LEFT JOIN leagues AS l1 ON m2.feed_league_id=l1.feed_league_id
WHERE DATEDIFF(DATE(NOW()), date)<=4 AND
stats.tipo='Golos1ª2ª' AND
m2.status='FT' AND
(m2.home_ht_score*1+ m2.away_ht_score*1) >1 AND
m2.home_ht_score REGEXP '[0-9]+' AND
m2.away_ht_score REGEXP '[0-9]+' AND
m2.feed_league_id=mleague
) AS LastDays
FROM leagues
LEFT JOIN countries ON countries.country_id=leagues.country_id
GROUP BY leagues.feed_league_id HAVING Total>20
ORDER BY Golos/Total DESC`
Table "leagues" - 828 records
CREATE TABLE IF NOT EXISTS `leagues` (
`league_id` int(11) NOT NULL AUTO_INCREMENT,
`league_name` varchar(255) NOT NULL,
`alt_league_name` varchar(255) NOT NULL,
`league_season` varchar(255) NOT NULL,
`feed_league_id` varchar(8) NOT NULL,
`feed_sub_id` varchar(10) NOT NULL,
`country_id` int(11) NOT NULL,
PRIMARY KEY (`league_id`),
KEY `league_name` (`league_name`),
KEY `league_season` (`league_season`),
KEY `feed_league_id` (`feed_league_id`),
KEY `country_id` (`country_id`),
KEY `feed_sub_id` (`feed_sub_id`),
KEY `alt_league_name` (`alt_league_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=837
Table "matches" - 125K records
CREATE TABLE IF NOT EXISTS `matches` (
`match_id` int(11) NOT NULL AUTO_INCREMENT,
`date` date NOT NULL,
`feed_match_id` varchar(255) NOT NULL,
`status` varchar(10) NOT NULL,
`time` varchar(10) NOT NULL,
`updated` datetime NOT NULL,
`home_team_id` int(11) NOT NULL,
`away_team_id` int(11) NOT NULL,
`home_ft_score` varchar(11) NOT NULL,
`away_ft_score` varchar(11) NOT NULL,
`home_ht_score` varchar(11) NOT NULL,
`away_ht_score` varchar(11) NOT NULL,
`country_id` int(11) NOT NULL,
`league_id` int(11) NOT NULL,
`feed_league_id` varchar(8) NOT NULL,
`feed_sub_id` varchar(10) NOT NULL,
`stage_id` int(11) NOT NULL,
`week_number` int(11) NOT NULL,
`n_updates` int(11) NOT NULL,
PRIMARY KEY (`match_id`),
KEY `date` (`date`),
KEY `feed_match_id` (`feed_match_id`),
KEY `status` (`status`),
KEY `time` (`time`),
KEY `updated` (`updated`),
KEY `home_ft_score` (`home_ft_score`),
KEY `away_ft_score` (`away_ft_score`),
KEY `home_ht_score` (`home_ht_score`),
KEY `away_ht_score` (`away_ht_score`),
KEY `country_id` (`country_id`),
KEY `league_id` (`league_id`),
KEY `stage_id` (`stage_id`),
KEY `week_number` (`week_number`),
KEY `home_team_id` (`home_team_id`),
KEY `away_team_id` (`away_team_id`),
KEY `feed_league_id` (`feed_league_id`),
KEY `feed_sub_id` (`feed_sub_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=125231 ;
Table "stats" - 250K records
CREATE TABLE IF NOT EXISTS `stats` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`match_id` int(11) NOT NULL,
`stat` varchar(255) NOT NULL,
`equipa` varchar(255) NOT NULL,
`tipo_id` smallint(6) NOT NULL,
PRIMARY KEY (`id`),
KEY `match_id` (`match_id`),
KEY `stat` (`stat`),
KEY `equipa` (`equipa`),
KEY `tipo_id` (`tipo_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=246459 ;
Can someone help me simplifying this query. It takes too long to be executed.
If you need more information, please ask.
Thanks.
I don't even know where to begin. The basic problem is that you are counting in your SELECT clause. This means that for each record in leagues (main query), you are executing 3 other big queries (not to mention all the regex). You're not giving your server a chance.
Move your counting from SELECT to FROM (make them join tables).
UPDATE: Here's what I mean:
SELECT leagues.feed_league_id, Total.cnt
FROM leagues
JOIN countries ON countries.country_id=leagues.country_id
JOIN (SELECT l1.feed_league_id, COUNT(DISTINCT m2.match_id) as cnt
FROM `matches` AS m2
LEFT JOIN stats ON stats.match_id=m2.match_id
LEFT JOIN leagues AS l1 ON m2.feed_league_id=l1.feed_league_id
WHERE stats.tipo='Golos1ª2ª' AND m2.status='FT' AND (m2.home_ht_score*1+ m2.away_ht_score*1) >1 AND m2.home_ht_score REGEXP '[0-9]+' AND m2.away_ht_score REGEXP '[0-9]+'
GROUP BY l1.feed_league_id
) AS Total on Total.feed_league_id = leagues.feed_league_id
GROUP BY leagues.feed_league_id
As you can see this is only for Total, but it's the same for the other two big queries.

How can I query for rows with latest date and do an inner join on a second table?

All the examples I've seen show how to do an inner join using an alias to get rows with the latest date. I can do that with my data but I also want to do an inner join on another table and can't figure how to do both with the same query.
Here are the two tables:
CREATE TABLE `titles` (
`titleID` int(11) unsigned NOT NULL AUTO_INCREMENT,
`titlename` tinytext NOT NULL,
`url` varchar(255) DEFAULT '',
`category` int(2) unsigned NOT NULL,
`postdate` date NOT NULL,
PRIMARY KEY (`titleID`),
KEY `category` (`category`),
CONSTRAINT `titles_ibfk_1` FOREIGN KEY (`category`) REFERENCES `categories` (`catid`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;
CREATE TABLE `stats` (
`statid` int(11) unsigned NOT NULL AUTO_INCREMENT,
`score` decimal(3,2) DEFAULT NULL,
`views` int(11) unsigned DEFAULT NULL,
`favs` int(11) DEFAULT NULL,
`comments` int(11) DEFAULT NULL,
`updatedate` date NOT NULL,
`title` int(11) unsigned NOT NULL,
PRIMARY KEY (`statid`),
KEY `title` (`title`),
CONSTRAINT `stats_ibfk_1` FOREIGN KEY (`title`) REFERENCES `titles` (`titleID`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=latin1;
My goals:
1) I want a query that gives me all the latest stats for each title.
2) I want to see the text name of the title (from the titles table).
I can use this query to get the latest score for each title.
select t.score, t.views, t.favs, t.comments, t.updatedate, t.title
from stats t
inner join (
select title, max(updatedate) as updatedate
from stats
GROUP BY title
) tm on t.title = tm.title and t.updatedate = tm.updatedate
But the problem with this query is that it displays the title column from stats which is an int. I want the text name of the title.
I can do this to get the title name and the score, but then I'm not getting the row with the latest date.
select titlename, score, updatedate
from stats
inner join titles
on titleid = title
How can I write a query that achieves both my goals?
You need to join the title table in this case as
select
s1.score,
s1.views,
s1.favs,
s1.comments,
s1.updatedate,
t.titlename
from titles t
join stats s1 on s1.title = t.titleID
join (
select title, max(updatedate) as updatedate
from stats
GROUP BY title
) s2 on s2.title = s1.title and s1.updatedate = s2.updatedate

mysql select from one to many relation

I have two tables - Users and Products. User may have a few products. I need to select all products and show which user they belong.
How to solve it using mysql joins.
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`login` varchar(16) NOT NULL,
`password` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8
CREATE TABLE `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
`description` varchar(255) NOT NULL,
`price` decimal(10,2) NOT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
CONSTRAINT `user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8
I've tried like this:
SELECT users.login FROM users LEFT JOIN products ON users.id=products.user_id;
But in this case it shows me only user logins, but i need to get product name, price and description as well.
SELECT p.name, p.price, p.description, group_concat(u.login) as users
FROM products p
LEFT JOIN users u ON u.id = p.user_id
GROUP BY p.name, p.price, p.description

MySQL query for searching subset of two tables

I have two tables:
CREATE TABLE IF NOT EXISTS `comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`photograph_id` int(11) NOT NULL,
`created` datetime NOT NULL,
`author` varchar(255) NOT NULL,
`body` text NOT NULL,
`email` varchar(255) NOT NULL,
`liked` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `photograph_id` (`photograph_id`)
)
And this:
CREATE TABLE IF NOT EXISTS `photographs` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`filename` varchar(255) NOT NULL,
`type` varchar(100) NOT NULL,
`size` int(11) NOT NULL,
`caption` varchar(255) NOT NULL,
`liked` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`)
)
I am having trouble merging these two into one query. In this query I would like to have sorting call of number of comments that every photo have. In Comments table, there is column photograph_id, that links to the photo id in Photographs table. Thanks for the help.
For photo's with 1 or more comments do:
SELECT p.id, COUNT(*) as commentcount FROM photographs p
INNER JOIN comments c ON (p.id = c.photograph_id)
GROUP BY p.id
ORDER BY commentcount DESC
If you also want photo's with zero comments do:
SELECT p.id, COUNT(c.id) as commentcount FROM photographs p
LEFT JOIN comments c ON (p.id = c.photograph_id)
GROUP BY p.id
ORDER BY commentcount DESC
SELECT *,
(SELECT COUNT(*) FROM comments
WHERE photographs.id = ccomments.photograph_id)) commentcount
FROM photographs
This will probably be faster than the join method. Maybe. You will need to experiment.