msql wrong total and sum on result - mysql

We have three different following tables...
users
id,
username
password
email
user_clubs
id,
user_id,
club_name
sales
id,
club_id,
amount,
admin_fees,
dnt
And we want to get total sum of admin_fees as outstanding for user_id(for example 55), so we tried following...
SELECT u.id, count(c.id), SUM(s.admin_fees) as total_admin_fees
FROM users u
LEFT JOIN user_clubs c ON c.user_id = u.id
LEFT JOIN sales s ON s.club_id = c.id
WHERE u.id = 55
GROUP BY u.id;
But its returning value of first row, so balance is not correct, Please help to resolve.

Try this:
SELECT g.id, count(g.club_id), SUM(g.admin_fees) AS total_admin_fees
FROM (
SELECT u.id, c.id AS club_id, s.admin_fees
FROM users u
LEFT JOIN user_clubs c ON c.user_id = u.id
LEFT JOIN sales s ON s.club_id = c.id
WHERE u.id = 55
) AS g
GROUP BY g.id;

Related

SQL - select for each user the total articles and the total article comments

I am trying to get for each user the total number of articles and for each article the total number of comments, something like this:
username | total_articles | total_comments
John Doe | 3 | 10
This is my SQL until now, I am using MySQL:
SELECT u.id, u.username, COUNT(a.id) AS total_articles, COUNT(c.id) AS total_comments FROM users u
LEFT JOIN articles a ON u.id = a.user_id
LEFT JOIN comments c ON a.id = c.article_id
GROUP BY u.id;
I tried to group by u.id, a.id, c.id at the same time but it's not working correctly.
Thanks.
In the first query there are all the articles by user, in the second all the comments joined by user
edited: use LEFT JOIN insted JOIN
SELECT id_total_articles, username, total_articles, total_comments
FROM
(
SELECT u.id as id_total_articles, u.username, COUNT(a.id) AS total_articles FROM users u
LEFT JOIN articles a ON u.id = a.user_id
GROUP BY u.id, u.username
) as AC
left join
(
SELECT u.id as id_total_comments, COUNT(c.id) AS total_comments FROM users u
LEFT JOIN comments c ON u.id = c.user_id
GROUP BY u.id, u.username
) as CC
ON AC.id_total_articles = CC.id_total_comments;
use u.id, u.username both column in group by
SELECT u.id, u.username, COUNT(a.id) AS total_articles,
COUNT(c.id) AS total_comments FROM users u
LEFT JOIN articles a ON u.id = a.user_id
LEFT JOIN comments c ON a.id = c.article_id
GROUP BY u.id, u.username
If what you want is the number of articles for a user, and the total number of comments on all the articles of the user - then this is your query:
SELECT
u.id,
u.username,
COUNT(DISTINCT a.id) AS total_articles,
COUNT(c.id) AS total_comments
FROM users u
LEFT JOIN articles a
ON u.id = a.user_id
LEFT JOIN comments c
ON a.id = c.article_id
GROUP BY
u.id,
u.username;
But - if you are looking for the number of comments (just a thought here) of the user - then you want to join the comments table on the user id, and not the article id.
You are missing the u.username in the group by, also COUNT(a.id) must change into COUNT(distinct a.id):
SELECT u.id, u.username, COUNT(distinct a.id) AS total_articles, COUNT(c.id) AS total_comments FROM users u
LEFT JOIN articles a ON u.id = a.user_id
LEFT JOIN comments c ON a.id = c.article_id
GROUP BY u.id, u.username;
Update:
However, I guess that what you actually need is something other than your proposed query. You said that you need the total number of articles for each user and the total number of comment for each article. That means you need two separate queries:
SELECT a.id article_id , COUNT(c.id) AS total_comments
FROM articles a
LEFT JOIN comments c ON a.id = c.article_id
GROUP BY a.id
SELECT u.id, u.username, COUNT(distinct a.id) AS total_articles
FROM users u
LEFT JOIN articles a ON u.id = a.user_id
GROUP BY u.id, u.username;
You are aggregating along related dimensions and getting overcounting.
One approach is to use multiple aggregations:
SELECT u.id, u.username, COUNT(a.id) AS total_articles,
SUM(c.num_comments) AS total_comments
FROM users u LEFT JOIN
articles a
ON a.user_id = a.id LEFT JOIN
(SELECT c.article_id, COUNT(c.id) as num_comments
FROM comments c
GROUP BY c.article_id
) c
ON a.id = c.article_id
GROUP BY u.id, u.username;

MySQL: Needing to return top 3 Users with the most votes. Results wanted in one column from the SUM of two subqueries. Java/Spring MVC

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

mysql join with multiple tables and count query

I have total 6 tables in which different info has been saved
Now i need a result in which get count from 5 tables and select all info from main table but if record does not exist than it must be need to return 0 instead of no row found that's the problem here
I have tried below query but didn't get success
SELECT
u.*,
COUNT(DISTINCT c.id) as comments,
COUNT(DISTINCT d.id) as dislikes,
COUNT(DISTINCT l.id) as likes,
COUNT(DISTINCT s.id) as shares,
COUNT(DISTINCT t.id) as tags
FROM
job_details as u
JOIN job_comments as c ON u.id = c.job_id
JOIN job_dislike as d ON u.id = d.job_id
JOIN job_like as l ON u.id = l.job_id
JOIN job_share as s ON u.id = s.job_id
JOIN job_tags as t ON u.id = t.job_id
WHERE
u.id = c.job_id AND
u.id = d.job_id AND
u.id = l.job_id AND
u.id = s.job_id AND
u.id = t.job_id
GROUP BY
u.id
This query is executed, but didn't get exact result.
I don't quite understand why.
I was hoping somebody here could help me out?
Thanks!
You probably didn't get the exact result because some tables may be missing values.
Although you can solve this problem with a LEFT JOIN, the safer solution is to pre-aggregate the data:
SELECT u.*, c.comments, d.dislikes, l.likes, s.shares, t.tags
FROM job_details as u LEFT JOIN
(select c.job_id, count(*) as comments from job_comments group by c.job_id
) c
ON u.id = c.job_id LEFT JOIN
(select d.job_id, count(*) as dislikes from job_dislike d group by d.job_id
) d
ON u.id = d.job_id LEFT JOIN
(select l.job_id, count(*) as likes from job_like l group by l.job_id
) l
ON u.id = l.job_id LEFT JOIN
(select s.job_id, count(*) as shares from job_share s group by s.job_id
) s
ON u.id = s.job_id LEFT JOIN
(select t.job_id, count(*) as tags from job_tags t group by t.job_id
) t
ON u.id = t.job_id;
Why is this better? Consider an id that has 5 comments, likes, dislikes, shares and tags. The JOIN approach produces an intermediate result with 5*5*5*5*5 = 3,125 intermediate rows. Things can really get out of hand for popular ids.
Use LEFT JOIN instead of JOIN. and you don't need WHERE clause since you have joined those tables. And, use IFNULL function to return 0 for null values. You need to modify you query like this :
SELECT u.id,
IFNULL(COUNT(DISTINCT c.id),0) as comments,
IFNULL(COUNT(DISTINCT d.id),0) as dislikes,
IFNULL(COUNT(DISTINCT l.id),0) as likes,
IFNULL(COUNT(DISTINCT s.id),0) as shares,
IFNULL(COUNT(DISTINCT t.id),0) as tags
FROM job_details as u
LEFT JOIN job_comments as c ON u.id = c.job_id
LEFT JOIN job_dislike as d ON u.id = d.job_id
LEFT JOIN job_like as l ON u.id = l.job_id
LEFT JOIN job_share as s ON u.id = s.job_id
LEFT JOIN job_tags as t ON u.id = t.job_id
GROUP BY u.id

SQL Join with MAX().

I have two tables, users and contestants. I'm trying to select the max contestant ID that has a profile picture(which is on the user table)
Heres my terrible SQL:
SELECT u.thumbnail, u.id FROM users AS u
INNER JOIN
(
SELECT c.id, c.user_id FROM contestants AS c
WHERE u.id = c.users_id
AND c.id = (select max(c.id))
) WHERE u.thumbnail IS NOT NULL
The error currently is: #1248 - Every derived table must have its own alias.
This confuses me since Users has an alias of u, and contestants has an alias of c..
What am I doing wrong here? I'm guessing a lot so some help would be really appreciated!
Whenever you are performing a join operation, you are actually joining two table. The subquery you wrote here, for instance, is working as a separate table. Hence, you have to use an alias to this table. That's the reason behind your error message.
Your query:
SELECT u.thumbnail, u.id FROM users AS u
INNER JOIN
(
SELECT c.id, c.user_id FROM contestants AS c
WHERE u.id = c.users_id
AND c.id = (select max(c.id))
) WHERE u.thumbnail IS NOT NULL
It should contain an alias for the subquery:
SELECT c.id, c.user_id FROM contestants AS c
WHERE u.id = c.users_id
AND c.id = (select max(c.id))
Let's say, it's T.
So, your query now becomes:
SELECT u.thumbnail, u.id FROM users AS u
INNER JOIN
(
SELECT c.id, c.user_id FROM contestants AS c
WHERE u.id = c.users_id
AND c.id = (select max(c.id))
) AS T
WHERE u.thumbnail IS NOT NULL
But what you are trying to achieve, can actually be done in a neater way:
SELECT u.thumbnail, u.id, max(c.id),
FROM users as u
LEFT JOIN contestants as c
on u.id = c.user_id
WHERE u.thumbnail IS NOT NULL
Why make all the fuss when you have a better and neater approach at your disposal?
try this:
SELECT u.thumbnail, u.id
FROM users AS u
INNER JOIN
(
SELECT c.id, c.user_id FROM contestants AS c
WHERE u.id = c.users_id
AND c.id = (select max(c.id))
)A
WHERE u.thumbnail IS NOT NULL
i think this should be simple,
SELECT u.thumbnail, u.id
FROM users u
INNER JOIN contestants c
ON u.id = c.users_id
WHERE u.thumbnail IS NOT NULL
ORDER BY c.id DESC
LIMIT 1
This is very simple.
SELECT user.thumbnail, user.id
FROM users user
INNER JOIN contestants cont ON cont.id = cont.users_id
WHERE cont.thumbnail IS NOT NULL
ORDER BY user.id DESC

mysql sum using left join on three tables

We have following tables...
users
id, username password email
user_clubs
id, user_id, club_name
sales
id, club_id, amount, admin_fees, dnt
We are trying to get total sum of admin_fees as outstanding for user_id(for example 5), and we tried following...
SELECT u.id, count(c.id), SUM(s.admin_fees) as total_admin_fees
FROM users u
LEFT JOIN user_clubs c ON c.user_id = u.id
LEFT JOIN sales s ON s.club_id = c.id
WHERE u.id = 5
GROUP BY u.id;
Which is only returning results for first row, which is incorrect, Please help to resolve.
here is sql fiddle to test.
thanks
Try this one for user_id = 5 there are two club ids and with amount 2,5 so total should be 7
SELECT u.id, COUNT(c.id), SUM(s.admin_fees) AS total_admin_fees
FROM users u
LEFT JOIN user_clubs c ON c.user_id = u.id
LEFT JOIN sales s ON s.club_id = c.id
WHERE u.id = 5
GROUP BY s.club_id;
for all users you can do this
SELECT u.id, COUNT(c.id), SUM(s.admin_fees) AS total_admin_fees
FROM users u
LEFT JOIN user_clubs c ON c.user_id = u.id
LEFT JOIN sales s ON s.club_id = c.id
GROUP BY u.`id`;
Fiddle