MySQL left join 2 tables order by count - mysql

I have 2 tables as below and want to have select both of them result by count(column) but doesn't work please advise.
review table
ID | RID | Name | comment
555|3000 | John | John comment
555|3001 | Ben | Ben comment
555|3002 | Smith| Smith comment
Likes table
U | PID
1 | 3000
2 | 3000
3 | 3000
4 | 3001
Expected result
ID | RID | Name | comment | votes
555|3000 | John | John comment | 3
555|3001 | Ben | Ben comment | 1
I'm expecting the result from select * from review with count PID column from Likes table
My current query is
SELECT * , (SELECT COUNT( PID ) FROM Likes AS votes WHERE there.ID = PID)
FROM review AS there
LEFT JOIN Likes b ON there.RID = b.PID
WHERE ID =555
AND there.RID = b.PID AND votes>0
ORDER BY votes DESC
But it did not woking, please advise.

Since you are after on reviews with votes only, you can make your query shorter(and perhaps faster) by converting LEFT JOIN to INNER JOIN, and eliminating detection of COUNT: http://www.sqlfiddle.com/#!2/1f920/3
SELECT r.ID, r.RID, r.Name, `Comment`, COUNT(RID) as votes
FROM review r
JOIN Likes l ON l.PID = r.RID
WHERE r.ID = 555
GROUP BY r.RID
ORDER BY votes DESC
Output:
| ID | RID | NAME | COMMENT | VOTES |
--------------------------------------------
| 555 | 3000 | John | John comment | 3 |
| 555 | 3001 | Ben | Ben comment | 1 |

SELECT ID, RID, Name, `Comment`, COUNT(RID) as votes
FROM review AS there
LEFT JOIN Likes b ON there.RID = b.PID
WHERE ID = 555
AND there.RID = b.PID
GROUP BY b.PID
HAVING votes > 0
ORDER BY votes DESC
sqlfiddle

Related

How to limit and search number of joined rows from table in multiple joins in mysql

i have a following tables in MySQL database:
+------------------------+
| Users |
+----+--------+----------+
| id | name | role |
+----+--------+----------+
| 1 | Martin | admin |
+----+--------+----------+
| 2 | George | admin |
+----+--------+----------+
| 3 | John | employee |
+----+--------+----------+
+-------------------------+
| Forms |
+----+--------------------+
| id | type |
+----+--------------------+
| 10 | marketing_form |
+----+--------------------+
| 11 | client_survey_form |
+----+--------------------+
| 12 | client_survey_form |
+----+--------------------+
+---------------------------------------------+
| UsersAssignToForms |
+----+---------+---------+--------------------+
| id | user_id | form_id | additional_comment |
+----+---------+---------+--------------------+
| 20 | 1 | 10 | Lorem ipsum... |
+----+---------+---------+--------------------+
| 21 | 2 | 10 | Lorem ipsum.... |
+----+---------+---------+--------------------+
| 22 | 3 | 10 | null |
+----+---------+---------+--------------------+
| 23 | 3 | 11 | null |
+----+---------+---------+--------------------+
I would like to have result:
+---------+---------+------------+--------------------+--------------------+
| user_id | form_id | first_name | form_type | additional_comment |
+---------+---------+------------+--------------------+--------------------+
| 1 | 10 | Martin | marketing_form | Lorem ipsum... |
+---------+---------+------------+--------------------+--------------------+
| 3 | 11 | John | client_survey_form | null |
+---------+---------+------------+--------------------+--------------------+
| null | 12 | null | client_survey_form | null |
+---------+---------+------------+--------------------+--------------------+
First of all i would like to limit number of users returned from join query (one user per one form). If user with admin role is assigned to form i would like to display this user (prioritize admin role over employee role) and limit number of returned users to 1, if admin is not assign, but employee is assigned query should return this user, if no-one is assign query should return nulls (left or right join probably).
I saw this question on stackoverflow - MySQL JOIN with LIMIT 1 on joined table, but unfortunately first answer has n+1 issue and rest of answers was made with simple one join. For my purposes i need to join more tables but wouldn't like to design this tables above to clarify what i would like to achieve, but it's very important.
So my query will looks like probably:
SELECT u.id, f.id, u.name, f.type, uf.additional_comment, [more selects from other tables...] FROM Forms as f
LEFT JOIN Users as u ON ......
INNER JOIN UsersAssignToForms as uf ON .....
[here i would like to put more and more inner joins.....]
In MySql >= 8.0 you can number the rows using some criteria (for each Form starting from one and order by u.role ASC and u.id ASC), then you can filter rows with number one:
WITH sq AS (SELECT u.id AS user_id, f.id AS form_id, u.name, f.type, uf.additional_comment,
ROW_NUMBER() OVER (PARTITION BY f.id ORDER BY u.role ASC, u.id ASC) AS num
FROM Forms AS f
LEFT JOIN UsersAssignToForms AS uf ON f.id = uf.form_id
LEFT JOIN Users AS u ON u.id = uf.user_id)
SELECT *
FROM sq
WHERE num = 1;
Before MySql 8.0 you can try something like this (the idea is the same but with different implementation):
SELECT sq2.user_id, sq2.form_id, sq2.name, sq2.type, sq2.additional_comment
FROM (
SELECT
sq1.*,
#row_number:=CASE WHEN #form_id = sq1.form_id THEN #row_number + 1 ELSE 1 END AS num,
#form_id:= sq1.form_id
FROM (SELECT u.id AS user_id, f.id AS form_id, u.name, f.type, uf.additional_comment
FROM Forms AS f
LEFT JOIN UsersAssignToForms AS uf ON f.id = uf.form_id
LEFT JOIN Users AS u ON u.id = uf.user_id
ORDER BY f.id ASC, u.role ASC, u.id ASC) AS sq1
ORDER BY sq1.form_id) AS sq2
WHERE sq2.num = 1;

How to select only last matching result if this is equal to x from mysql table

i've three tables in my mysql database:
orders table (example):
orders
id | user_id | price
1 | 10 | 29.99
2 | 20 | 29.99
3 | 30 | 29.99
4 | 40 | 29.99
users table:
users
id | name | surname
10 | mark | white
20 | john | long
30 | anders | red
40 | john | smith
and orders_updates table
orders_updates
id | order_id | status_id | date
1 | 1 | 1 | 03/05/2020
2 | 1 | 2 | 04/05/2020
3 | 2 | 1 | 05/05/2020
4 | 3 | 1 | 06/05/2020
5 | 4 | 1 | 06/05/2020
6 | 4 | 2 | 06/05/2020
What i need:
new orders
order_id | user_id | name | surname
2 | 20 | john | long
3 | 30 | anders | red
Now, i need to create the "new orders" page (orders_updates.status_id = 1), how i can get only orders with only status_id=1 and not some other status_id.
This is where i'm stuck:
SELECT o.*, u.*
FROM orders o, users u, orders_updates ou
WHERE o.user_id = u.id
AND (SELECT MAX(ID) FROM order_updates WHERE order_updates.order_id = o.id)
AND ou.order_id = o.id
Thank you all.
Try the following
select
order_id,
user_id,
name,
surname
from orders_updates ou
join orders o
on ou.order_id = o.id
join users u
on u.id = o.user_id
where ou.status_id = 1
order by
order_id
I would go with:
select
order_id,
user_id,
name,
surname
from orders_updates ou
join orders o
on ou.order_id = o.id
join users u
on u.id = o.user_id
where ou.status_id = 1
and ou.order_id not in (
select distinct order_id
from orders_updates
where status_id in (2,3)
)
order by
order_id
I put as a sample status_id in (2,3) but you should include there all the other status_ids you don’t want to be considered.
Hope that helps!

Count distinct records from child table for each user in MYSQL

I have a competition which counts how many species each user has collected.
this is managed by 3 tables:
a parent table called "sub" with collection,each collection is unique, has an id and is associated to a user id.
+----+---------+
| id | user_id |
+----+---------+
| 1 | 1 |
| 2 | 10 |
| 3 | 1 |
| 4 | 3 |
| 5 | 1 |
| 6 | 10 |
+----+---------+
the child table called "sub_items" contains multiple unique records of the specs and is related to the parent table by the sub id to id.(each sub can have multiple records of specs)
+----+--------+---------+--+
| id | sub_id | spec_id | |
+----+--------+---------+--+
| 1 | 1 | 1000 | |
| 2 | 1 | 1003 | |
| 3 | 1 | 2520 | |
| 4 | 2 | 7600 | |
| 5 | 2 | 1000 | |
| 6 | 3 | 15 | |
+----+--------+---------+--+
a user table with associated user_id
+--------+-------+--+
| usename | name |
+---------+-------+--+
| 1 | David |
| 10 | Ruth |
| 3 | Rick |
+--------+-------+--+
i need to list the users with the most unique specs collected in a decsending order.
output expected:
David has a total of 2 unique specs.Ruth has a total of 2 unique specs.
+--------+---------+
| id | total |
+----+-------------+
| David | 2 |
| Ruth | 2 |
| Rick | 2 |
+----+-------------+
so far i have this,it produces a result. but its not accurate, it counts the total records.
im probably missing a DISTINCT somewhere in the sub-query.
SELECT s.id, s.user_id,u.name, sum(t.count) as total
FROM sub s
LEFT JOIN (
SELECT id, sub_id, count(id) as count FROM sub_items GROUP BY sub_id
) t ON t.sub_id = s.id
LEFT JOIN user u ON u.username = s.user_id
GROUP BY user_id
ORDER BY total DESC
i have looked at this solution, but it doesn't consider the unique aspect
You'll first have to get the max "score" for all the users like:
SELECT count(DISTINCT si.id) as total
FROM sub INNER JOIN sub_items si ON sub.id = su.sub_id
GROUP BY sub.user_id
ORDER BY total DESC
LIMIT 1
Then you can use that to restrict your query to users that share that max score:
SELECT u.name, count(DISTINCT si.id) as total
FROM
user u
INNER JOIN sub ON u.usename = sub.user_id
INNER JOIN sub_items si ON sub.id = su.sub_id
GROUP BY u.name
HAVING total =
(
SELECT count(DISTINCT si.id) as total
FROM sub INNER JOIN sub_items si ON sub.id = su.sub_id
GROUP BY sub.user_id
ORDER BY total DESC
LIMIT 1
)
this worked for me, i have to add the
COUNT(distinct spec_id)
to the sub-query
SELECT s.id, s.user_id,u.name, sum(t.count) as total
FROM sub s
LEFT JOIN (
SELECT sub_id, COUNT(distinct spec_id) as count FROM sub_items group by sub_id
) t ON t.sub_id = s.id
LEFT JOIN user u ON u.username = s.user_id
GROUP BY user_id
ORDER BY total DESC

Get default value from JOIN query if join field value doesn't exist in another table

I have two tables customers and reviews. The structure is like this:
customers:-
|---------------------------------|
| id | name |
|---------------------------------|
| 1 | Thutmekri |
|---------------------------------|
| 3 | Conan |
|---------------------------------|
reviews:-
|-------------------------------------------|
| id | business_id | customer_id |
|-------------------------------------------|
| 1 | 1 | 1 |
|-------------------------------------------|
| 2 | 1 | 2 |
|-------------------------------------------|
| 3 | 1 | 3 |
|-------------------------------------------|
customer_id of reviews is id of customer.
The join query,
SELECT customers.name, reviews.id as review_id
FROM customers, reviews
WHERE customers.id = reviews.customer_id
returns the dataset like this:-
|----------------------------------|
| review_id | name |
|----------------------------------|
| 1 | Thutmekri |
|----------------------------------|
| 3 | Conan |
|----------------------------------|
But I want it to return:-
|----------------------------------|
| review_id | name |
|----------------------------------|
| 1 | Thutmekri |
|----------------------------------|
| 2 | N/A |
|----------------------------------|
| 3 | Conan |
|----------------------------------|
For customer_id in reviews, which doesn't have any data in customers table, I want 'N/A' to be displayed. How can I do it?
The following query also didn't help
SELECT reviews.id as review_id, COALESCE( name, 'N/A' )
FROM customers, reviews
WHERE customers.id = reviews.customer_id
Use a left join and switch the order of the tables in the join:
SELECT
r.id AS review_id,
COALESCE(c.name, 'N/A') AS name
FROM reviews r
LEFT JOIN customers c
ON c.id = r.customer_id;
SQLFiddle
Try this :
SELECT r.id as review_id, COALESCE( c.name, 'N/A' ) FROM reviews r
LEFT JOIN customers c ON c.id = r.customer_id
Use the Right outer join to achieve this:
SELECT
reviews.id as review_id,
COALESCE(name, 'N/A' )
FROM customers
RIGHT JOIN reviews
ON customers.id = reviews.customer_id;
You can use below query
SELECT
R.id AS review_id,
COALESCE(C.name, 'N/A') AS name FROM reviews R LEFT JOIN customers C ON R.customer_id = C.id ;

MYSQL JOIN two tables limit results from second table by date

I am trying to retrieve date from two tables using a MYSQL query. I want to join them together were categories.cat_id=topics.topic_cat. Multiple entries may have the same topic_cat, so I only want to SELECT the most recent, which is equal to MAX(topic_date).
The following query shows the correct information from topics, with only one result per topic_cat and that result having the most recent date.
SELECT topic_subject, topic_cat, topic_date
FROM topics
GROUP BY topic_cat DESC
Multiple rows may have the same value for topic_cat, but I only want to retrieve and join only the most recent, MAX(topic_date) and then join to a query which shows the following information from the categories table.
SELECT categories.cat_id, categories.cat_name, categories.cat_description, topics.topic_subject, topics.topic_cat, topics.topic_date, topics.topic_by
FROM categories
LEFT JOIN topics
ON categories.cat_id=topics.topic_cat
GROUP BY cat_id;
This query displays the correct information, except one thing. It shows the topic_cat with the oldest entry, or MIN(topic_date). I have tried the following to get the topic_cat by newest entry or MAX(topic_date), but without success.
SELECT categories.cat_id, categories.cat_name, categories.cat_description
FROM categories
LEFT JOIN (SELECT topic_subject, topic_cat, topic_date, topic_by
FROM topics
GROUP BY topic_cat DESC) AS topics
ON categories.cat_id=topics.topic_cat
Any help or suggestions would be greatly appreciated.
Ok, so here is the sample data and associated desired result.
Table 1 = categories
_______________________________________________________
| cat_id | cat_name | cat_description |
-------------------------------------------------------
| 1 | james | Some information about james|
-------------------------------------------------------
| 2 | myo | Some information about myo |
-------------------------------------------------------
| 3 | brandon | Some information about brandon |
-------------------------------------------------------
Table 2 = topics
__________________________________________________
| topic_subject | topic_cat | topic_date | topic_by |
----------------------------------------------------------
| marcos | 2 | 2013-9-28 | User 1 |
---------------------------------------------------------
| ferdinand | 2 | 2013-9-29 | User 2 |
---------------------------------------------------------
| maria luisa | 2 | 2013-9-30 | User 1 |
---------------------------------------------------------
| Isabella | 1 | 2013-8-24 | User 3 |
--------------------------------------------------------
| Carlos | 3 | 2012-6-21 | User 2 |
--------------------------------------------------------
| Enrique | 3 | 2011-4-2 | User 3 |
---------------------------------------------------------
I would like the query to return the following data based on the above tables:
_________________________________________________________________________________________________
| cat_id | cat_name | cat_description | topic_subject | topic_cat | topic_date | topic_by |
----------------------------------------------------------------------------------------------------------------
| 1 | james | Some information about james | Isabella | 1 | 2013-8-24 | User 3 |
----------------------------------------------------------------------------------------------------------------
| 2 | myo | Some information about myo | maria luisa | 2 | 2013-9-30 | User 1 |
----------------------------------------------------------------------------------------------------------------
| 3 | brandon | Some information about brandon | Carlos | 3 | 2012-6-21 | User 2 |
----------------------------------------------------------------------------------------------------------------
I hope that clarifies things.
Try This:
###
SELECT * FROM categories c
LEFT JOIN topics t ON c.cat_id = t.topic_cat
WHERE c.cat_id IN (SELECT t1.cat_id FROM (
SELECT c.cat_id, c.cat_name, MAX(t.topic_date) AS maxdate FROM categories c
LEFT JOIN topics t ON c.cat_id = t.topic_cat
GROUP BY c.cat_name
) as t1 WHERE t1.maxdate = t.topic_date OR t.topic_date IS NULL );
### without nulls
SELECT * FROM categories c
LEFT JOIN topics t ON c.cat_id = t.topic_cat
WHERE c.cat_id IN (SELECT t1.cat_id FROM (
SELECT c.cat_id, c.cat_name, MAX(t.topic_date) AS maxdate FROM categories c
LEFT JOIN topics t ON c.cat_id = t.topic_cat
GROUP BY c.cat_name
) as t1 WHERE t1.maxdate = t.topic_date);
Try changing
LEFT JOIN (SELECT topic_subject, topic_cat, topic_date, topic_by
FROM topics
GROUP BY topic_cat DESC) AS topics
to:
LEFT JOIN (SELECT topic_subject, topic_cat, topic_date, topic_by
FROM topics
GROUP BY topic_cat
ORDER BY topic_date DESC
LIMIT 0,1) AS topics