i have 2 table
users : id , name
order : id , price, user_id
a users have more than one order. And i want to select a users
who have total price >100 . how to do ?
EX : user John have 3 orders with price : 30$, 40$ , 50$
SELECT * FROM user u
INNER JOIN order o ON o.user_id = u.id
WHERE sum(o.price) >100
this query will get the user is john ? 30+40+50 = 110 >100
?
First of all you are not allowed to use aggregate functions (i.e. SUM) in your WHERE clause. They should be used in the HAVING clause. To compute aggregates you need to GROUP BY something, in your case by u.id.
So:
SELECT *
FROM user u
INNER JOIN order o ON u.user_id = u.id
GROUP BY u.id
HAVING sum(o.price) > 100
Note that if you would need users with no order you would have to use LEFT JOIN!
SELECT u.Id, Sum(o.price) FROM user u
INNER JOIN order o ON o.user_id = u.id
GROUP BY u.Id
HAVING sum(o.price) > 100
Thank for all answer but i catch problem
now i have a new table order_file
users : id , name
order : id , price, user_id
order_file : id , file , order_id
users, order is one-many
order , order_file is one-many
a user John have 1 order with price is 200$
and this order link to order_file with two record
SELECT *
FROM user u
INNER JOIN order o ON u.user_id = u.id
INNER JOIN order_file of ON of.order_id = o.id
WHERE u.name = 'John'
we will get two rows.Only diff value in order_file
now to get once i use DISTINCT , and i get 1 row
SELECT DISTINCT *
FROM user u
INNER JOIN order o ON u.user_id = u.id
INNER JOIN order_file of ON of.order_id = o.id
WHERE u.name = 'John'
then i do SUM , oh la la , i get 400$ , not 200$
SELECT DISTINCT *, sum(o.price)
FROM user u
INNER JOIN order o ON u.user_id = u.id
INNER JOIN order_file of ON of.order_id = o.id
WHERE u.name = 'John'
how to i can get extracty 200$ , not duplicate row :(
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 3 tables "maintenances", "cars", "users" . I want to select all data from table maintenance with a distinct car_id and the last record for each distinct (based on max maintenance_date)
SELECT
m. * , u.username, c.Model, c.Make, c.License, c.Milage, COUNT( m.process_id ) AS count_nr
FROM
maintenances AS m
LEFT JOIN users AS u ON u.id = m.user_id
LEFT JOIN cars AS c ON c.id = m.car_id
WHERE
maintenance_date = (SELECT MAX(maintenance_date) FROM maintenances WHERE car_id = m.car_id)
The problem is that this query returns only one record which has the max date from all records. I want all records (distinct car_id and from records with the same car_id to display only values for max(maintenance_date))
This is your query:
SELECT m. * , u.username, c.Model, c.Make, c.License, c.Milage, COUNT( m.process_id ) AS count_nr
----------------------------------------------------------------^
FROM maintenances AS m LEFT JOIN
users AS u
ON u.id = m.user_id LEFT JOIN
cars AS c
ON c.id = m.car_id
WHERE maintenance_date = (SELECT MAX(maintenance_date) FROM maintenances WHERE car_id = m.car_id);
It is an aggregation query. Without a group by, only one row is returned (all the rows are in one group). So, add the group by:
SELECT m. * , u.username, c.Model, c.Make, c.License, c.Milage, COUNT( m.process_id ) AS count_nr
FROM maintenances AS m LEFT JOIN
users AS u
ON u.id = m.user_id LEFT JOIN
cars AS c
ON c.id = m.car_id
WHERE maintenance_date = (SELECT MAX(m2.maintenance_date) FROM maintenances m2 WHERE m2.car_id = m.car_id);
GROUP BY c.id
I also fixed the correlation statement, to be clear that it is correlated to the outer query.
add GROUP BY u.username .
WHERE
maintenance_date = (SELECT MAX(maintenance_date) FROM maintenances WHERE car_id = m.car_id)
GROUP BY u.username
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;
I have the following query, in which I used JOINs. It says:
unknown column m.bv ..
Could you please take a look and tell me what I'm doing wrong?
$query4 = 'SELECT u.*, SUM(c.ts) AS total_sum1, SUM(m.bv) AS total_sum
FROM users u
LEFT JOIN
(SELECT user_id ,SUM(points) AS ts FROM coupon GROUP BY user_id) c
ON u.user_id=c.user_id
LEFT JOIN
(SELECT user_id ,SUM(points) AS bv FROM matching GROUP BY user_id) r
ON u.user_id=m.user_id
where u.user_id="'.$_SESSION['user_name'].'"
GROUP BY u.user_id';
You are selecting SUM(points) AS bv from the table with the alias r, there is no tables with the alias m. So that it has to be r.bv instead like so:
SELECT
u.*,
SUM(c.ts) AS total_sum1,
SUM(r.bv) AS total_sum
FROM users u
LEFT JOIN
(
SELECT
user_id,
SUM(points) AS ts
FROM coupon
GROUP BY user_id
) c ON u.user_id=c.user_id
LEFT JOIN
(
SELECT
user_id,
SUM(points) AS bv
FROM matching
GROUP BY user_id
) r ON u.user_id = m.user_id
where u.user_id="'.$_SESSION['user_name'].'"
GROUP BY u.user_id
Replace m., with r. Look at second Join
You have aliased the derived table with r and you reference that table (twice) with m. Correct one or the other.
Since you group by user_id in the two subqueries and user_id is (I assume) the primary key of table user, you don't really need the final GROUP BY.
I would write it like this, if it was meant for all (many) users:
SELECT u.*, COALESCE(c.ts, 0) AS total_sum1, COALESCE(m.bv, 0) AS total_sum
FROM users u
LEFT JOIN
(SELECT user_id, SUM(points) AS ts FROM coupon GROUP BY user_id) c
ON u.user_id = c.user_id
LEFT JOIN
(SELECT user_id, SUM(points) AS bv FROM matching GROUP BY user_id) m
ON u.user_id = m.user_id
and like this in your (one user) case:
SELECT u.*, COALESCE(c.ts, 0) AS total_sum1, COALESCE(m.bv, 0) AS total_sum
FROM users u
LEFT JOIN
(SELECT SUM(points) AS ts FROM coupon
WHERE user_id = "'.$_SESSION['user_name'].'") c
ON TRUE
LEFT JOIN
(SELECT SUM(points) AS bv FROM matching
WHERE user_id = "'.$_SESSION['user_name'].'") m
ON TRUE
WHERE u.user_id = "'.$_SESSION['user_name'].'"
The last query can also be simplified to:
SELECT u.*,
COALESCE( (SELECT SUM(points) FROM coupon
WHERE user_id = u.user_id)
, 0) AS total_sum1,
COALESCE( (SELECT SUM(points) FROM matching
WHERE user_id = u.user_id)
, 0) AS total_sum
FROM users u
WHERE u.user_id = "'.$_SESSION['user_name'].'"
My database have got 4 table :
users
id
username
images
id
user_id
image
user_follow
user_id
user_follow
commentaries
image_id
text
I try to make a query to get all my and my friends pictures
1) row must be shown only if user have picture in "images" table
2) only image from me and my friends (depending on "user_follow" table)
3) count commentaries for each picture
my query is:
SELECT u.username as user, i.image as user_image, p.image, UNIX_TIMESTAMP(p.date) as date, COALESCE ( imgcount.cnt, 0 ) as comments
FROM users u
LEFT JOIN user_follow f ON u.id = f.follow_id
LEFT JOIN images p ON p.user_id = u.id
LEFT JOIN images i ON i.id = (SELECT b.id FROM images AS b where p.user_id = b.user_id ORDER BY b.id DESC LIMIT 1)
LEFT JOIN (SELECT image_id, COUNT(*) as cnt FROM commentaries GROUP BY image_id ) imgcount ON p.id = imgcount.image_id
WHERE f.user_id = 3 OR p.user_id = 3
ORDER BY p.date DESC
Commentaries count of each image sql line works fine in this query
LEFT JOIN (SELECT image_id, COUNT(*) as cnt FROM commentaries GROUP BY image_id ) imgcount ON p.id = imgcount.image_id
in this line I try to get user his last upload image as avatar from "images" table
LEFT JOIN images i ON i.id = (SELECT b.id FROM images AS b where p.user_id = b.user_id ORDER BY b.id DESC LIMIT 1)
This query dot not return result correctly because it show my friends who do not have pictures and something is not good with my own pictures (in database I have 2 row with my user_id : 3 ) but sql return 4
If I'm understanding correctly, it seems like you've made this a lot more complex than it needs to be. The reason you are getting records for your friends without pictures is because you are using a LEFT JOIN. Change that to an INNER JOIN and you will only get the records that match the join condition.
I think you are looking for something like the following. You'll need to make a few tweaks but hopefully this helps.
SELECT u.username as user, i.image as user_image, count(*) as comments
FROM users u
INNER JOIN user_follow f ON u.id = f.follow_id
INNER JOIN images p ON p.user_id = u.id
INNER JOIN commentaries c ON c.image_id = p.id
WHERE u.user_id = 3
GROUP BY u.username, i.image;