I'm trying to retrieve the last 10 posts from a posts table ordered ASC, but the last left joined query doesn't retrieve anything.
Basic: it retrieves results ordered DESC
SELECT
p.post, p.id_post, u.name
FROM
posts p
LEFT JOIN
users u ON u.id_user = p.id_user
WHERE
p.id_user = 4
ORDER BY
p.date DESC
LIMIT 10
Ordered ASC: it doesn't work at all:
SELECT
num.*
FROM
(SELECT
p.post, p.id_post, u.name
FROM
posts p
LEFT JOIN
users u ON u.id_user = p.id_user
WHERE
p.id_user = 4
ORDER BY
p.date DESC
LIMIT 10) num
ORDER BY
p.date ASC
What am I doing wrong?
In my php variables I use $row['id_post'] $row['post'] $row['name']. I don't want to use array_reverse() just plain sql
You need to return the date in the subquery:
SELECT pu.post, pu.id_post, pu.name
FROM (SELECT p.*, u.name
FROM posts p LEFT JOIN
users u
ON u.id_user = p.id_user
WHERE p.id_user = 4
ORDER BY p.date DESC
LIMIT 10
) pu
ORDER BY pu.date ASC;
Your second query should have returned an error message to the effect that date is not recognized as a column. You should be capturing and reading error messages, if you want to write an effective application.
Related
I have a Spring MVC blog with functionality for Post and Comment voting. I want to return the top 3 users based on number of votes they've received on all their posts and comments.
tables:
users u [id, username]
posts p [id, u.id]
comments c [id, p.id, u.id]
post_votes pv [p.id, u.id, type (1 or -1)]
comment_votes cv [c.id, u.id, type (1 or -1)]
The following statement gives me total votes per user by querying two separate voting tables and then adding the totals together:
SELECT
(SELECT SUM(type)
FROM posts_votes pv
JOIN posts p ON p.id = pv.post_id
JOIN users u ON u.id = p.user_id
WHERE u.id LIKE ?1)
+
(SELECT SUM(type)
FROM comments_votes cv
JOIN comments c ON c.id = cv.comment_id
JOIN users u ON u.id = c.user_id
WHERE u.id LIKE ?1)
That works fine with a WHERE clause per user id... But now I'm trying to find just the top 3 users that have the most votes and I'm having too much difficulty. This is what I have so far:
SELECT u.id, u.username, IFNULL(SUM(pv.type), 0) AS totalPostVotes
FROM posts_votes pv
JOIN posts p ON p.id = pv.post_id
JOIN users u ON u.id = p.user_id
GROUP BY u.id ORDER BY totalPostVotes DESC LIMIT 3
That above statement works by itself giving me: u.id, u.username, and totalPostVote in descending order. So does the one below for comments:
SELECT u.id, u.username, IFNULL(SUM(cv.type), 0) AS totalCommentVotes
FROM comment_votes cv
JOIN comments c ON c.id = cv.comment_id
JOIN users u ON u.id = c.user_id
GROUP BY u.id ORDER BY totalCommentVotes DESC LIMIT 3
Great! But I want that third column SUM result to be essentially "totalVotes" and contain the sum of both of those subqueries. Then I'll GROUP BY u.id ORDER BY totalVotes DESC LIMIT 3.
Something like this:
SELECT u.id, u.username, SUM(
(SELECT IFNULL(SUM(pv.type), 0) AS totalPostVotes
FROM posts_votes pv
JOIN posts p ON p.id = pv.post_id
JOIN users u ON u.id = p.user_id
GROUP BY u.id ORDER BY totalPostVotes DESC LIMIT 1)
+
(SELECT IFNULL(SUM(cv.type), 0) AS totalCommentVotes
FROM comments_votes cv
JOIN comments c ON c.id = cv.comment_id
JOIN users u ON u.id = c.user_id
GROUP BY u.id ORDER BY totalCommentVotes DESC LIMIT 1))
AS totalVotes from users u
GROUP BY u.id, u.username ORDER BY totalVotes DESC LIMIT 3
id | username | totalVotes
2 user2 11
1 user1 11
29 user29 11
What's happening is the result of totalVotes is indeed the correct vote count, 11, for the "top" user, but none of those users are the real top user, and the correct vote is being repeated 3 times in the guise of other users. I'm not even sure how users are being sorted at that point because they're not in an order I recognize.
The subqueries work separately (they give me the correct user) when I add SELECT "u.id, u.username " IFNULL(SUM()) but then if I run the whole block, I get the error "Operand should contain 1 column(s)" So I delete them and revert to only SELECT IFNULL(SUM())
I'm also noticing the subqueries are only allowed LIMIT 1. How would I get the top 3, then? Should I do a UNION somewhere or is "+" sufficient? This is rather confusing. Can someone please help me with this? Any help is appreciated. Thanks in advance!
Updated code, thank you Peter:
SELECT
u.username,
pv_sum.total AS postTotal,
cv_sum.total AS commentTotal,
IFNULL(pv_sum.total, 0) + IFNULL(cv_sum.total, 0) as totalVotes
FROM users u
LEFT JOIN (
SELECT p.user_id, IFNULL(SUM(pv.type), 0) AS total
FROM posts p
JOIN posts_votes pv ON pv.post_id = p.id
GROUP BY p.user_id
) pv_sum ON pv_sum.user_id = u.id
LEFT JOIN (
SELECT c.user_id, IFNULL(SUM(cv.type), 0) AS total
FROM comments c
JOIN comments_votes cv ON cv.comment_id = c.id
GROUP BY c.user_id
) cv_sum ON cv_sum.user_id = u.id
GROUP BY u.username, postTotal, commentTotal
ORDER BY totalVotes DESC LIMIT 3;
Don't place your subqueries in your SELECT-part, but join them on the users-table:
SELECT
u.username,
pv_sum.total AS postTotal,
cv_sum.total as commentTotal,
IFNULL(pv_sum.total, 0) + IFNULL(cv_sum.total, 0) as totalVotes
FROM users u
LEFT JOIN (
SELECT p.user_id, IFNULL(SUM(pv.type), 0) AS total
FROM posts p
JOIN post_votes pv ON pv.post_id = p.id
GROUP BY p.user_id
) pv_sum ON pv_sum.user_id = u.id
LEFT JOIN (
SELECT c.user_id, IFNULL(SUM(cv.type), 0) AS total
FROM comments c
JOIN comment_votes cv ON cv.comment_id = c.id
GROUP BY c.user_id
) cv_sum ON cv_sum.user_id = u.id
GROUP BY u.id
ORDER BY totalVotes DESC
LIMIT 3;
Fiddle: http://sqlfiddle.com/#!9/980cb2/11
I have this query:
SELECT * FROM project as p inner join users as u on p.user_id = u.user_id
ORDER BY p.projectname, u.date_joined
Now what I want to ORDER by projectname ASC and u.date_joined DESC.
How could I make it this way? I tried this code here but doesn't work:
SELECT * FROM project as p inner join users as u on p.user_id = u.user_id
ORDER BY p.projectname ASC, u.date_joined DESC
Order the projectname ascending works but the descending won't work.
To order project name descending, do this:
SELECT *
FROM project p
INNER JOIN users u ON p.user_id = u.user_id
ORDER BY p.projectname DESC, u.date_joined DESC
This will order your result by projectname desc (Z to A) first. For identical projectname records, date_joined will be used for sorting further (latest date first).
What I want:
SELECT u.username, u.last_activity
FROM users_userprofile
WHERE u.id IN (
SELECT DISTINCT(p.user_id) FROM forums_post p
WHERE p.thread_id = 423993
ORDER BY p.created_at DESC
LIMIT 4
);
This doesn't work because of LIMIT in subquery. I want to keep order of subquery but I want to get username and last_activity instead of user_id.
Any suggestion how I could achieve this?
Replace the subquery with a view:
CREATE VIEW subv AS SELECT p.user_id FROM forums_post p
WHERE p.thread_id = 423993
ORDER BY p.created_at DESC
LIMIT 4;
SELECT u.username, u.last_activity
FROM users_userprofile
WHERE u.id IN (SELECT * FROM subv);
you could use join for the table and the subquery instead of using where in:
SELECT u.username, u.last_activity
FROM users_userprofile u
JOIN (
SELECT p.user_id FROM forums_post p
WHERE p.thread_id = 423993
ORDER BY p.created_at DESC
LIMIT 4
) q
on u.user_id=q.user_id
Why woldn't you do it with a JOIN? There seems to be no performance impact because WHERE and LIMIT clauses are the same. It won't JOIN the whole tables:
SELECT p.user_id, u.username, u.last_activity
FROM users_userprofile u
JOIN forums_post p ON p.user_id = u.id
WHERE p.thread_id = 423993
GROUP BY p.user_id ORDER BY MAX(p.created_at) DESC
LIMIT 4
i have this
SELECT COUNT(1) cnt, a.auther_id
FROM `posts` a
LEFT JOIN users u ON a.auther_id = u.id
GROUP BY a.auther_id
ORDER BY cnt DESC
LIMIT 20
its work fine
bu now i want select from posts which added from 1 day tried to use
WHERE from_unixtime(post_time) >= SUBDATE(NOW(),1)
but its didnot worked
any one have idea
My guess is that you added the WHERE clause in the wrong place. It should come after the JOIN but before the GROUP BY, like this:
SELECT COUNT(1) cnt, a.auther_id
FROM `posts` a
LEFT JOIN users u ON a.auther_id = u.id
WHERE from_unixtime(post_time) >= SUBDATE(NOW(),1)
GROUP BY a.auther_id
ORDER BY cnt DESC
LIMIT 20
i have users table and i have posts table i want select from users the top users that have the big amount of posts from posts table and order them by numbers of posts
i can make it by array_count_values() by i cant order it
now i think if i make it by one mysql query by left and join will be more better
table structure
posts
id | auther_id
i tried this
SELECT COUNT(1) cnt, u.user_id
FROM users u
LEFT JOIN posts p
ON p.author_id=u.user_id
GROUP BY u.user_id
ORDER BY cnt DESC
LIMIT 20
it gave me this
alt text http://img511.imageshack.us/img511/6707/31154352.gif
see the arrow
what is this
i just have 2 posts under user_id 5
what is this first row
You need to aggregate the posts by user using GROUP BY u.user_id, get a COUNT value for the number of posts and ORDER BY that number, in descending order:
SELECT COUNT(1) cnt, u.user_id
FROM users u
LEFT JOIN posts p
ON p.author_id=u.user_id
GROUP BY u.user_id
ORDER BY cnt DESC
LIMIT 20
SELECT u.user_id, COUNT(*) as post_count
FROM users u
INNER JOIN posts p
USING (user_id)
GROUP BY u.user_id
ORDER BY post_count
i used this and its worked
is it true
SELECT COUNT( 1 ) cnt, a.auther_id
FROM `posts` a
LEFT JOIN users u ON a.auther_id = u.id
GROUP BY a.auther_id
ORDER BY cnt DESC
LIMIT 20