I've looked around for an answer to this but I'm not finding it. I have a site with articles stored in an article table and writers in the user table. I wanted to get a list of authors ordered by how recently they'd written an article.
This gives me the User ids:
SELECT distinct a.user_id
FROM `article` as a
ORDER BY a.id desc
The problem is that as soon as I try to bring the names in by joining the order changes so that it's by user id. I've tried this:
SELECT distinct a.user_id, u.name
FROM `article` as a
LEFT JOIN user as u on u.id = a.user_id
ORDER BY a.id desc, u.id desc
and
SELECT distinct a.user_id, u.name
FROM `article` as a
LEFT JOIN user as u on u.id = a.user_id
ORDER BY u.id desc, a.id desc
but both alter the order of the names. I'm obviously doing something stupid, but what?
The fact that DISTINCT happens to work with ORDER BY in your first example is a fluke, and not standard SQL. You need something like this:
SELECT a.user_id, u.name
FROM article a
LEFT JOIN user u ON u.id = a.user_id
GROUP BY a.user_id
ORDER BY MAX(a.id) desc
try this
SELECT a.user_id, u.name
FROM `article` a
LEFT JOIN user u on u.id = a.user_id
GROUP BY a.user_id
ORDER BY a.id desc
Your ORDER BY sorts the rows by either the User ID and/or Article ID (depending on the example).
If you want reliable sorting by name, then include the u.name field in the ORDER BY fields.
this is postgres syntax, but you can easily translate it into mysql
select u.*, q.last_article_id
from user u
inner join (
select a.user_id, max(a.id) as last_article_id
from article a
group by a.user_id
) q
on u.id = a.q.id
order by q.last_article_id desc
Something along the lines of the following should work:
select users.id, articles.id, max(articles.created_at) as recent_date
from users
left join articles on users.id = articles.user_id
group by articles.id
order by recent_date
Not sure what exactly your fields are named and all, but this should point you in the right direction.
You got a lot of answers to choose from... I believe the key to what you're asking is use of the aggregate function MAX() http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_max
Related
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;
I'm trying to select results from two different unrelated tables, showcase and questions to appear in a feed. They should be ordered by the common column hotness which is a float value.
SELECT s.id,s.date,s.title,s.views,s.image,s.hidpi,s.width,s.description,u.display_name,u.avatar
FROM showcase AS s
INNER JOIN users AS u ON s.user_id = u.id
UNION
SELECT q.id,q.date,q.title,q.views,q.text,u.display_name,u.avatar,0,0,0
FROM questions AS q
INNER JOIN users AS u ON q.user_id = u.id
ORDER BY hotness DESC
LIMIT 10
I've tried UNION, but I have no idea how I should be using it here and get this error unknown column hotness
You need to select the value in order for the ORDER BY to recognize it:
SELECT s.id,s.date,s.title,s.views,s.image,s.hidpi,s.width,s.description,u.display_name,u.avatar, s.hotness
FROM showcase AS s
INNER JOIN users AS u ON s.user_id = u.id
UNION ALL
SELECT q.id,q.date,q.title,q.views,q.text,u.display_name,u.avatar,0,0,0, q.hotness
FROM questions AS q
INNER JOIN users AS u ON q.user_id = u.id
ORDER BY hotness DESC;
Note that I also changed the UNION to UNION ALL. Unless you intend to remove duplicates, there is no reason to incur the extra processing for doing that.
You can try this query:
SELECT r.* FROM (
SELECT s.id,s.date,s.title,s.views,s.image,s.hidpi,s.width,s.description,u.display_name,u.avatar, s.hotness
FROM showcase AS s
INNER JOIN users AS u ON s.user_id = u.id
UNION
SELECT q.id,q.date,q.title,q.views,q.text,u.display_name,u.avatar,0,0,0, q.hotness
FROM questions AS q
INNER JOIN users AS u ON q.user_id = u.id
) as r
ORDER BY r.hotness DESC
LIMIT 10
You need to merge Union result in subquery to apply Order by on the result. I also added hotness in select clause, please check I take field from good table.
My query looks like as
SELECT
users.*,
(select count(*)
from user_actions
where status='pending' and user_id = users.id) number_pending
FROM users
order by name
I need to show those records first which have number_pending count greater than zero. Can you please help me how to achieve that?
SELECT
u.*, count(a.*) number_pending
FROM users u join user_actions a
on a.user_id = u.id
where a.status='pending'
order by count(a.*) desc
Is this what you are trying to do?
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)
I built working MySQL query:
SELECT
v.*, u.username
FROM
video AS v, users AS u
WHERE
v.type = 'public'
AND
v.user_ID = u.user_ID
Now I want to add a third table and count() results from the table comments where video_ID from this table will be equal to those from the table video.
I tried this but it wasn't successful:
SELECT
v.*, u.username, count(c.video_ID)
FROM
video AS v, users AS u, comments AS c
WHERE
v.type = 'public'
AND
v.user_ID = u.user_ID
AND
v.video_ID = c.video_ID
In return I want to get the number of comments related to certain video_ID's.
I don't understand how to make it work correctly in one query.
Could you please help me out?
Thank you in advance,
Ilia
If you are using an aggregate function like a COUNT in a query, you need to specify the grouping with a GROUP BY clause.
Try this
SELECT
v.*,
u.username,
count(c.video_ID) AS comment_count
FROM
video AS v
INNER JOIN users AS u ON v.user_ID = u.user_ID
INNER JOIN comments AS c ON v.video_ID = c.video_ID
WHERE
v.type = 'public'
GROUP BY
v.id,
u.username,
v.v.add_time
ORDER BY
v.add_time
While MySQL lets you leave out the some elements of the GROUP BY clause, it is good practice to specify them.
When joining two tables, it is good practice to use the INNER JOIN syntax, rather than a WHERE filter.