Order by most of items with Join - mysql

I've a 'items' table with the following structure:
id, person_id, active
and 'people' table with id and name columns.
I want to order by most active items and join the people.name column to sql.
I tried to do something like that, but it's not working:
SELECT people.id, COUNT(*) as items_count
FROM items, people
WHERE items.active = true AND people.id = items.person_id
GROUP BY items.person_id
ORDER BY items_count DESC

Use Joins this will match the condition. Order by items_count will give you most active user
Select people.id, COUNT(items.active) as items_count
FROM items
LEFT JOIN people on people.id = items.person_id
WHERE items.active = true
GROUP BY people.id
ORDER BY items_count DESC

select * from (SELECT people.id, COUNT(*) as items_count
FROM items
left outer join people on people.id = items.person_id
where items.active = true
GROUP BY items.person_id) as A
ORDER BY A.items_count DESC

Related

Subquery left join refer to parent ID

I am trying to make a query to fetch the newest car for each user:
select * from users
left join
(select cars.* from cars
where cars.userid=users.userid
order by cars.year desc limit 1) as cars
on cars.userid=users.userid
It looks like it says Unknown column "users.userid" in where clause
I tried to remove cars.userid=users.userid part, but then it only fetches 1 newest car, and sticks it on to each user.
Is there any way to accomplish what I'm after? thanks!!
For this purpose, I usually use row_number():
select *
from users u left join
(select c.* , row_number() over (partition by c.userid order by c.year desc) as seqnum
from cars c
) c
on c.userid = u.userid and c.seqnum = 1;
One option is to filter the left join with a subquery:
select * -- better enumerate the columns here
from users u
left join cars c
on c.userid = u.userid
and c.year = (select max(c1.year) from cars c1 where c1.userid = c.userid)
For performance, consider an index on car(userid, year).
Note that this might return multiple cars per user if you have duplicate (userid, year) in cars. It would be better to have a real date rather than just the year.
Maybe there are better and more efficient way to query this. Here is my solution;
select users.userid, cars.*
from users
left join cars on cars.userid = users.userid
join (SELECT userid, MAX(year) AS maxDate
FROM cars
GROUP BY userid) as sub on cars.year = sub.maxDate;

SQL- query which finds the name of a specific row which has max linked columns from another table

There are 2 tables:
users: id, name
albums: id, user_id
I need a SQL query which finds the NAME of the user who has the max count of albums. How do I do that?
Here is what I have tried so far -
SELECT Users.name
FROM Users
JOIN Albums
ON Users.id = Albums.user_id
HAVING COUNT(Albums.id) = MAX(COUNT(Albums.id));
(this doesnt work)
You could use a limit 1
select Users.name, count(distinct Albums.id) max_count
from Users
INNER JOIN Albums on Users.id = Albums.user_id
GROUP BY Users.name
ORDER max_count desc limit 1
or a filter the having beas on max for max count
select Users.name
from Users
INNER JOIN Albums on Users.id = Albums.user_id
GROUP BY Users.name
HAVING count(distinct Albums.id) = (
select max(t.max_count) from (
select Users.name, count(distinct Albums.id) max_count
from Users
INNER JOIN Albums on Users.id = Albums.user_id
GROUP BY Users.name
) t
)
I would simply use join, group by, and limit:
SELECT u.name
FROM Users u JOIN
Albums a
ON u.id = a.user_id
GROUP BY u.name
ORDER BY COUNT(*) DESC
LIMIT 1;
This makes some assumptions:
Different users do not have the same name. If so, you should include u.id in the GROUP BY.
If there are ties, then you still want one row.
This sub query should return the name of the user having maximum number of albums.
SELECT name FROM Users WHERE id = (SELECT user_id FROM Albums GROUP BY user_id ORDER BY COUNT(*) DESC LIMIT 1);
Here is the GROUP BY used to group the user_id with the COUNT of each user_id occurrences otherwise return the count for all records in the table.
If there multiple max occurrences with same count then you have to use IN keyword for the query to return all names and the query will be bit complex.

Error in my MYSQL query?

Trying some queries on the database, but I have a problem. Can somebody help me with proper query?
This is what I need
SELECT
IdNews, Caption, NewsText, NumberOfViews, NumberOfComments,
PublishDate, CoinValue, category.IdNewsCategory,
NewsCategory, country.IdCountry, CountryName, news.IdUser,
FirstName, LastName, Picture, DateTimeUpCoin
FROM
news
INNER JOIN
category ON category.IdNewsCategory = news.IdNewsCategory
INNER JOIN
country ON news.IdCountry = country.IdCountry
INNER JOIN
user ON user.IdUser = news.IdUser
WHERE
news.IdCountry = 1
LIMIT 0, 10
ORDER BY
NumberOfViews DESC
You have written wrong query for Order by.
In query, LIMIT comes always last.
You need to write corrected query as per below :
SELECT
IdNews,Caption,NewsText,NumberOfViews,NumberOfComments,
PublishDate,CoinValue,category.IdNewsCategory,
NewsCategory,country.IdCountry,CountryName,news.IdUser,
FirstName, LastName,Picture, DateTimeUpCoin
FROM news
INNER JOIN category ON category.IdNewsCategory = news.IdNewsCategory
INNER JOIN country ON news.IdCountry = country.IdCountry
INNER JOIN user ON user.IdUser = news.IdUser
WHERE news.IdCountry = 1
ORDER BY NumberOfViews DESC
LIMIT 0, 10
IdCountry column is present in both the tables news and country. That's why it is showing error. Prepend table name before IdCountry in where clause. Put ORDER BY before LIMIT.
SELECT IdNews,Caption,NewsText,NumberOfViews,NumberOfComments,PublishDate,CoinValue,category.IdNewsCategory, NewsCategory,country.IdCountry,CountryName,news.IdUser,FirstName, LastName,Picture, DateTimeUpCoin
FROM news
INNER JOIN category ON category.IdNewsCategory = news.IdNewsCategory
INNER JOIN country ON news.IdCountry = country.IdCountry
INNER JOIN user ON user.IdUser = news.IdUser
WHERE news.IdCountry =1
ORDER BY NumberOfViews DESC
LIMIT 0 , 10

Mysql count and return just one row of data

I need to count the amount of users that have have answered all of those 3 profile_options (so they have at least 3 records in the profile_answers table).
SELECT COUNT(DISTINCT(users.id)) users_count
FROM users
INNER JOIN profile_answers ON profile_answers.user_id = users.id
WHERE profile_answers.profile_option_id IN (37,86,102)
GROUP BY users.id
HAVING COUNT(DISTINCT(profile_answers.id))>=3
The problem is that this query is return a table with rows for each user and how many they answered (in this case always 3). What I need is to return just one row that has the total number of users (so the sum of all rows of this example)
I know how to do it with another subquery but the problem is that I am running into "Mysql::Error: Too high level of nesting for select"
Is there a way to do this without the extra subquery?
SELECT SUM(sum_sub.users_count) FROM (
(SELECT COUNT(DISTINCT(users.id)) users_count
FROM users
INNER JOIN profile_answers ON profile_answers.user_id = users.id
WHERE profile_answers.profile_option_id IN (37,86,102)
GROUP BY users.id
HAVING COUNT(DISTINCT(profile_answers.id))>=3)
) sum_sub
Please give this query a shoot
SELECT COUNT(DISTINCT(u.id)) AS users_count
FROM users AS u
INNER JOIN (
SELECT user_id, COUNT(DISTINCT profile_option_id) AS total
FROM profile_answers
WHERE profile_option_id IN (37,86,102)
GROUP BY users.id
HAVING COUNT(DISTINCT profile_option_id) = 3
) AS a ON a.user_id = u.id
If you have lots of data in your tables, you will get a better/faster performance by using temporary tables like so
CREATE TEMPORARY TABLE a (KEY(user_id)) ENGINE = MEMORY
SELECT user_id, COUNT(DISTINCT profile_option_id) AS total
FROM profile_answers
WHERE profile_option_id IN (37,86,102)
GROUP BY users.id
HAVING COUNT(DISTINCT profile_option_id) = 3;
Then your final query will look like this
SELECT COUNT(DISTINCT(u.id)) as users_count
FROM a
INNER JOIN on a.user_id = u.id
Unless there is a need to join the users table you can go with this
SELECT COUNT(*) AS users_count
FROM (
SELECT user_id, COUNT(DISTINCT profile_option_id) AS total
FROM profile_answers
WHERE profile_option_id IN (37,86,102)
GROUP BY users.id
HAVING COUNT(DISTINCT profile_option_id) = 3
) AS a
Should you need another solution, please consider providing us you EXPLAIN EXTENDED for the query and the table definitions along with a better problem description.
I hope this helps
You can give the queries a name using the AS clause. See the updated query below.
SELECT SUM(sum_sub.users_count) FROM (
(SELECT COUNT(DISTINCT(users.id)) as users_count
FROM users
INNER JOIN profile_answers ON profile_answers.user_id = users.id
WHERE profile_answers.profile_option_id IN (37,86,102)
GROUP BY users.id
HAVING COUNT(DISTINCT(profile_answers.id))>=3)
) as sum_sub
You should not group by on a field not present in select statement.
select id, count(*) from users group by id is fine
select count(id) from users group by id is NOT
Regarding your query I think the link to user table is not necessary. Just using foreign key should be fine.
Try this one:
select count(*) from
(SELECT users_id count(*) as cnt
FROM profile_answers
INNER JOIN users ON profile_answers.user_id = users.id
WHERE profile_answers.profile_option_id IN (37,86,102)
group by users_id
having count(*) >3)

MySQL DELETE statement with a join, HAVING and GROUP BY

I have a table of items and another of reports. Each report has a foreign key linking to an item being reported.
I am trying to delete all items displayed in this query:
SELECT items.id, title, SUM(weight) AS total_weight, SUM(weight)*10/views AS score
FROM items, reports
WHERE items.id = reports.item_id
GROUP BY items.id
HAVING score >= 50;
Trying something like this:
DELETE items
FROM (SELECT items.id, title, SUM(weight) AS total_weight, SUM(weight)*10/views AS score
FROM items, reports
WHERE items.id = reports.item_id
GROUP BY items.id
HAVING score >= 50)
AS T;
Gives me this error message:
ERROR 1109 (42S02): Unknown table 'items' in MULTI DELETE
In MySQL, you have to be careful about the subqueries. I think the following works:
DELETE FROM items
WHERE id IN (select *
from (SELECT items.id
FROM items join reports
on items.id = reports.item_id
GROUP BY items.id
HAVING SUM(weight)*10/views >= 50
)
)
It tricks the compiler into accepting the query by using an additional subquery. I also fixed your join syntax.
The following, though, rewrites the query into a more common syntax, using a correlated subquery:
delete from items
where exists (select r.item_id
from reports r
where r.item_id = items.item_id
group by r.item_id
having SUM(r.weight)*10/items.views >= 50
)
This is guessing that weight and views come from reports. Otherwise, you need to put theitems` alias in front instead.
DELETE FROM items
WHERE
id IN (
SELECT
items.id
FROM items, reports
WHERE items.id = reports.item_id
GROUP BY items.id
HAVING SUM(weight)*10/views >= 50)
I believe your delete statement is wrong. It should be delete from tablename where [condition].
DELETE FROM items
WHERE
id IN (
Select T.id from (SELECT items.id, title, SUM(weight) AS total_weight, SUM(weight)*10/views AS score
FROM items, reports
WHERE items.id = reports.item_id
GROUP BY items.id
HAVING score >= 50) T)
Try this:
DELETE FROM items
WHERE id IN (SELECT id
FROM (SELECT i.id itemId, (SUM(weight) * 10 / views) score
FROM items i INNER JOIN reports r ON i.id = r.item_id
GROUP BY itemId HAVING score >= 50
) AS A
);