I have the following tables:
MOVIES
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | YES | MUL | NULL | |
| title | varchar(40) | NO | | NULL | |
| description | text | NO | | NULL | |
| created_at | datetime | YES | | NULL | |
| updated_at | datetime | YES | | NULL | |
+-------------+-------------+------+-----+---------+----------------+
MOVIE_VOTES
+------------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | YES | MUL | NULL | |
| movie_id | int(11) | YES | MUL | NULL | |
| like | tinyint(1) | YES | | NULL | |
| created_at | datetime | YES | | NULL | |
| updated_at | datetime | YES | | NULL | |
+------------+------------+------+-----+---------+----------------+
And I want to query all the movies sorted by the number of likes they have. I have this query:
SELECT *, COUNT(*) AS count_likes
FROM movie_votes
RIGHT JOIN movies
ON movies.id=movie_votes.movie_id
WHERE movie_votes.like = 1
GROUP BY movie_id
ORDER BY count_likes;
And this returning the movies sorted by the number of likes BUT not the movies that haven't be voted(liked) yet. For some reason the RIGHT join works as simple join.
I have searched for some relative answers but cant find anything helpful.
You should specify a column name when doing outer joins so that it will count only the non-null values
SELECT movies.id,
movies.user_id,
movies.title,
movies.description,
movies.created_at,
movies.updated_at,
COUNT(movie_votes.movie_id) AS count_likes
FROM movies
LEFT JOIN movie_votes
ON movies.id = movie_votes.movie_id
AND movie_votes.like = 1
GROUP BY movies.id,
movies.user_id,
movies.title,
movies.description,
movies.created_at,
movies.updated_at
ORDER BY count_likes
The condition movie_votes.like = 1 should be put in the ON clause so it will filter the rows in table movie_votes first before joining it to table movies.
Related
I have two tables:
mysql> DESCRIBE swaps;
+-------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+----------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user1_id | int(11) | NO | | NULL | |
| user2_id | int(11) | NO | | NULL | |
| hasto | int(11) | NO | | NULL | |
| requested | datetime | NO | | NULL | |
| accepted | datetime | YES | | NULL | |
| swapped1 | datetime | YES | | NULL | |
| swapped2 | datetime | YES | | NULL | |
| rejected | datetime | YES | | NULL | |
| rejected_by | int(11) | YES | | NULL | |
+-------------+----------+------+-----+---------+----------------+
mysql> DESCRIBE messages;
+-----------+----------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------+------+-----+-------------------+----------------+
| msg_id | int(11) | NO | PRI | NULL | auto_increment |
| sender_id | int(11) | NO | | NULL | |
| msg | text | NO | | NULL | |
| msg_time | datetime | NO | | CURRENT_TIMESTAMP | |
| swap_id | int(11) | NO | | NULL | |
| seen | datetime | YES | | NULL | |
+-----------+----------+------+-----+-------------------+----------------+
and query that I adjusted from this question
SELECT s.*, m.*
FROM swaps as s
JOIN messages as m
ON (s.id= m.swap_id AND m.msg_time=
(SELECT MAX(msg_time) FROM messages WHERE messages.swap_id = s.id));
as a result I single row for every swap and information about last sent message within this swap. I want to add the count of messages that have not jet been seen (m.seen IS NULL).
I tried different approaches but always get error. What I want is to add count of messages in corresponding swap with seen IS NULL to my result set. Would appreciate any suggestions.
You can add the count as a subquery:
SELECT s.*, m.*,
(SELECT COUNT(*) FROM messages m2 WHERE m2.seen IS NULL) as seen_is_null
FROM swaps s JOIN
messages m
ON s.id= m.swap_id AND
m.msg_time =(SELECT MAX(m2.msg_time) FROM messages m2 WHERE m2.swap_id = s.id));
It seems curious to be counting over all messages, but that is what the question asks for. You can, of course, introduce a correlation clause to count for a given swap or something else.
I am developing a EAV system for multiple entities (Product, Company,...)
I will tell the problem at the end.
The database structure is the following:
EAV_ENTITY
This table will give me a list of all available Entities, like:
1 | Product
2 | Company
Structure:
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| model | varchar(255) | NO | | | |
+-------+------------------+------+-----+---------+----------------+
EAV_ATTRIBUTE
This table have a list of attributes, the ref is a mnemonic for getting the attributes by query easier. I add here the entity_type_id that is related with the table eav_entity because I want to limit each attribute to only one entity.
+----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| entity_type_id | int(11) unsigned | NO | MUL | NULL | |
| ref | varchar(50) | NO | UNI | | |
| name | varchar(255) | NO | UNI | | |
+----------------+------------------+------+-----+---------+----------------+
EAV_VALUE
This table have the values related to the attribute, values would be: red, green, orange, for attribute "color"
+-----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| attribute_id | int(11) unsigned | NO | MUL | NULL | |
| value | varchar(255) | NO | MUL | NULL | |
+-----------------+------------------+------+-----+---------+----------------+
EAV_ATTRIBUTE_VALUE
+----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| entity_id | int(11) unsigned | YES | | NULL | |
| entity_type_id | int(11) unsigned | YES | MUL | NULL | |
| value_id | int(11) | YES | | NULL | |
+----------------+------------------+------+-----+---------+----------------+
Here I make all the "magic", I make a query making a relation between an entity(type, id) and all the values related and the attribute that the value belongs to.
My query is this one
SELECT
e.model,
av.entity_id,
a.id as category_id,
a.ref as category_ref,
v.id as value_id
FROM eav_entity as e
RIGHT JOIN eav_attribute_value as av
ON e.id = av.entity_type_id
LEFT JOIN eav_value as v
ON v.id = av.value_id
LEFT JOIN eav_attribute as a
ON v.attribute_id = a.id
WHERE e.model = 'App\Product'
PROBLEM & QUESTION
When I add the statement WHERE e.model ='Whatever' I dont get any result.
And it is supposed to be filter. But without the WHERE statement I get the results as expected.
I think that it might be a problem related to the way I am doing the joins.
A real example without WHERE e.model
+-------------+-----------+-------------+---------------------------+----------+
| model | entity_id | category_id | category_ref | value_id |
+-------------+-----------+-------------+---------------------------+----------+
| App\Product | 13 | 2 | product_development_phase | 2 |
| App\Product | 13 | 2 | product_development_phase | 3 |
| App\Product | 13 | 4 | product_therapeutics | 58 |
| App\Company | 13 | 4 | product_therapeutics | 58 |
+-------------+-----------+-------------+---------------------------+----------+
AS #Uuerdo said, I need to add a second backslash as escape character to interpret the second one as a real backslash.
The query will result in the next below:
SELECT
e.model,
av.entity_id,
a.id as category_id,
a.ref as category_ref,
v.id as value_id
FROM eav_entity as e
RIGHT JOIN eav_attribute_value as av
ON e.id = av.entity_type_id
LEFT JOIN eav_value as v
ON v.id = av.value_id
LEFT JOIN eav_attribute as a
ON v.attribute_id = a.id
WHERE e.model = "App\\Product"
I have two tables "tbl_shop" and "tbl_shop_category" each shop can be in multiple category. Following is a table structure.
1) tbl_shop
+----------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| shop_name | varchar(100) | NO | | NULL | |
| category_limit | int(11) | NO | | 1 | |
+----------------+--------------+------+-----+---------+----------------+
2) tbl_shop_category
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| shop_id | int(11) | NO | | NULL | |
| category | varchar(100) | NO | | NULL | |
+----------+--------------+------+-----+---------+----------------+
I want to fetch all shops with their categories with limit define in tbl_shop table in column category_limit
e.g.
if Shop name "Mysha" has 20 categories in tbl_shop_category and has category_limit of 5 in tbl_shop table then it should return only 5 categories for that shop.
I tried following query but not getting result as I want.
SELECT shop.shop_name,
cat.category
FROM tbl_shop shop
LEFT JOIN tbl_shop_category cat
ON shop.id = cat.shop_id
LIMIT shop.category_limit;
I have schema like this (just experimenting, so if you have improvement suggestions I am all ears):
mysql> describe contest_entries;
+---------------+----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+----------------+------+-----+---------+----------------+
| entry_id | int(10) | NO | PRI | NULL | auto_increment |
| member_id | int(10) | YES | | NULL | |
| person_name | varchar(10000) | NO | | NULL | |
| date | date | NO | | NULL | |
| platform | varchar(30) | YES | | NULL | |
| business_name | varchar(100) | YES | | NULL | |
| url | varchar(200) | YES | | NULL | |
| business_desc | varchar(3000) | YES | | NULL | |
| guid | varchar(50) | YES | UNI | NULL | |
+---------------+----------------+------+-----+---------+----------------+
9 rows in set (0.00 sec)
mysql> describe contest_votes;
+------------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+---------+------+-----+---------+----------------+
| vote_id | int(10) | NO | PRI | NULL | auto_increment |
| user_id | int(10) | NO | | NULL | |
| contest_entry_id | int(10) | NO | MUL | NULL | |
| vote | int(7) | NO | | NULL | |
+------------------+---------+------+-----+---------+----------------+
And I am trying to pull the data as a leaderboard, ordering the results by the most votes. How would I do that? I am able to do the left-join part, but the sum and the ordering part of the query is confusing me.
Thank you!
SELECT entry_id
FROM contest_entries
LEFT OUTER JOIN contest_votes ON entry_id = contest_entry_id
GROUP BY entry_id
ORDER BY SUM(vote) DESC
select e.entry_id, sum(v.vote) as votes
from contest_entries e
left join contest_votes v on e.entry_id = v.contest_entry_id
group by e.member_id
order by votes desc
I have this schema:
mysql> describe suggested_solution_comments;
+-----------------------+----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+----------------+------+-----+---------+----------------+
| comment_id | int(10) | NO | PRI | NULL | auto_increment |
| problem_id | int(10) | NO | | NULL | |
| suggested_solution_id | int(10) | NO | | NULL | |
| commenter_id | int(10) | NO | | NULL | |
| comment | varchar(10000) | YES | | NULL | |
| solution_part | int(3) | NO | | NULL | |
| date | date | NO | | NULL | |
| guid | varchar(50) | YES | UNI | NULL | |
+-----------------------+----------------+------+-----+---------+----------------+
8 rows in set (0.00 sec)
mysql> describe solution_sections;
+---------------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+---------------+------+-----+---------+----------------+
| solution_section_id | int(10) | NO | PRI | NULL | auto_increment |
| display_order | int(10) | NO | | NULL | |
| section_name | varchar(1000) | YES | | NULL | |
+---------------------+---------------+------+-----+---------+----------------+
My query is this:
select s.display_order,
s.section_name,
s.solution_section_id ,
count(c.comment_id) AS comment_count
FROM solution_sections s left outer join suggested_solution_comments c
ON (c.solution_part = s.solution_section_id)
where problem_id = 400
group by s.display_order, s.section_name, s.solution_section_id
order by display_order;
it returns only rows where there is a count > 0 but if the count is 0 it doesnt return those rows.
Any idea how to make it return all the rows? :)
Thanks!!
This is because the where problem_id = 400 removes rows with no corresponding suggested_solution_comments row. Moving the condition from the where filter to the on clause should address the problem:
select s.display_order, s.section_name, s.solution_section_id ,count(c.comment_id)
AS comment_count
from solution_sections s
left outer join suggested_solution_comments c
ON (c.solution_part = s.solution_section_id) AND problem_id = 400
group by s.display_order, s.section_name, s.solution_section_id
order by display_order;