I have a table users:
user_id name
1 John
2 Dan
3 Jane
4 Sophie
5 Jodie
I then have a table named associates:
user_id assoc_id
1 2
1 3
3 4
3 1
3 5
4 1
5 1
5 2
What I want to do is show how many associates each user has, or none
So, the results would show
user_id Name Number of Associates
1 John 2
2 Dan 0
3 Jane 3
4 Sophie 1
5 Jodie 2
What I'm trying works but does not show those with 0
Here's what I'm trying, how do I get the 0s?
SELECT u.user_id, u.name, count(a.user_id) as howmany from users u
join associates a on a.user_id = u.user_id
group by u.user_id order by u.user_id asc
You need a LEFT OUTER JOIN:
SELECT u.user_id, u.name, count(a.user_id) as howmany
FROM users u LEFT OUTER JOIN associates a
ON a.user_id = u.user_id
GROUP BY u.user_id
ORDER BY u.user_id ASC
The LEFT OUTER JOIN will include every rows of the first table even is they aren't present in the joined table.
Try this :
SELECT u.user_id,
u.name,
count(a.user_id) as howmany
FROM users u
LEFT OUTER JOIN associates a
ON a.user_id = u.user_id
GROUP BY u.user_id
ORDER BY u.user_id ASC
Try using a left join instead of a inner join, that should select the rows that do not have corresponding associates.
SELECT u.user_id, u.name, count(a.user_id) as howmany
from users u
left join associates a
on a.user_id = u.user_id
group by u.user_id
order by u.user_id asc
This will work with strict rules also (if i had not made any typo):
SELECT users.*, ISNULL(associatesCount.AssocCount, 0) AS AssocCount
FROM users
LEFT JOIN (
SELECT user_id, COUNT(*) AS AssocCount
FROM associates
GROUP BY user_id
) AS associatesCount
ON users.user_id = associatesCount.user_id
Related
I have an users table and amount table.
The users table has following columns.
name id
A 1
B 2
C 3
D 4
The amount table has following columns.
userId amount id
1 10 1
1 20 2
1 10 3
2 12 4
I need a sql which sums all the users amount from the amount table
Final output would be
name id totalAmount
A 1 30
B 2 12
C 3 0
D 4 0
I have tried using but does not work. Kindly help
let searchQuery = `SELECT u.id, u.name, (SELECT IFNULL(SUM(amount), 0) from amount WHERE amount.userId = u.id) as totalAmount, FROM users u LEFT JOIN amount amt on u.id = amt.userId WHERE`;
Correct syntax for correlated subquery version
SELECT u.id, u.name, (SELECT coalesce(SUM(a.amount), 0)
FROM amount a
WHERE a.userId = u.id) as totalAmount
FROM users u
You can do it using standard sql aggregation
select
u.name,
u.id,
sum(a.amount) as totalAmount
from users u
left join amount a
on a.userId = u.id
group by u.name, u.id
The left join is just to include those users whitout amounts, which will have a 0 as totalAmount
I want to get the sum of several entities from several tables using a query.
Specifically, I want the devices and messages count of a user. In addition, the timestamp of the last received message for that user.
I have 3 tables:
Users
id name (other fields)
1 Mike ...
2 John ...
3 Yay ...
4 Jim ...
Devices
id user_id (other fields)
1 1 ...
2 1 ...
3 1 ...
4 2 ...
Messages
id device_id message time (other fields)
1 1 Hi 2019-04-07 12:06:44 ...
2 1 Hey 2019-04-06 12:06:44 ...
3 2 Sup 2019-04-05 12:06:44 ...
4 3 Ok 2019-04-04 12:06:44 ...
5 4 Yay 2019-04-08 12:06:44 ...
... and, for example, for user Mike I want to end up with:
Result
nDevices nMessages time
3 4 2019-04-07 12:06:44
Any ideas?
Thanks in advance.
Join the 3 tables and count distinct values of the columns:
select
count(distinct d.id) devicescounter,
count(distinct m.id) messagescounter,
max(m.time) lastmessagetime
from users u
left join devices d on u.id = d.user_id
left join nessages m on m.device_id = d.id
where u.name = 'Mike'
If you want the results for all users:
select
u.id, u.name,
count(distinct d.id) devicescounter,
count(distinct m.id) messagescounter,
max(m.time) lastmessagetime
from users u
left join devices d on u.id = d.user_id
left join nessages m on m.device_id = d.id
group by u.id, u.name
The easiest way to do this would be to get the number of messages and most recent message time for each device in a subquery.
SELECT u.id,
COUNT(d.id) AS num_devices,
SUM(messages) AS num_messages,
MAX(most_recent) AS most_recent_message
FROM users u
JOIN devices d ON d.user_id = u.id
JOIN (SELECT device_id,
COUNT() AS messages,
MAX(TIME) AS most_recent_message
FROM messages
GROUP BY device_id) m ON m.device_id = d.id
GROUP BY u.id
You could try using a join between user and device and a inner join with the subquery for message and device
select a.name, a.id, count(d.user_id), t.nDevice, t.max_time
from Users a
inner join device d on a.id = d.user_id
inner join (
select m.device_id, count(m.device_id) nDevice, max(m.time) max_time
from Messages m
group by m.device_id
) t on t.device_id = d.id
group by a.name, a.id
I have 3 tables:
tbl_user stores all user details (user_id,name,address)
user_id name address
1 a (shop) home
2 b (shop) bakerstreet
3 c (staff) wallstreet
4 d (staff) georgia
5 e (staff) sydney
tbl_user_group stores user type (user_id,user_type : 1=shop_owner,2=staff)
user_id user_type
1 1
2 1
3 2
4 2
5 2
tbl_user_association holds the shop_owner and staff relation (shop_owner_id, staff_id)
shop_owner_id staff_id
1 3
1 4
1 5
2 3
2 4
desired result
i want to display the list of staffs and the respective shops that they are associated with as follows:
user_id staff_name shop_owner
3 c a,b
4 d a,b
5 e a
I tried using the group_concat as mentioned here. The query is as follows:
SELECT
u.id AS user_id,
u.name AS staff_name,
(SELECT GROUP_CONCAT(u.name separator ',') FROM tbl_user u WHERE u.id = ua.shop_owner_id) AS
shop_owner
FROM tbl_user u
JOIN tbl_user_group ug ON u.id = ug.user_id
LEFT JOIN tbl_user_association ua ON u.id = ua.staff_id
WHERE ug.user_type = 2
GROUP BY u.id
But it returns single row of staffs as below. where have i gone wrong?
user_id staff_name shop_owner
3 c a
4 d a
5 e a
This is how I'd do it:
SELECT
u.user_id,
u.name,
GROUP_CONCAT( so.name )
FROM
tbl_user_group ug
INNER JOIN tbl_user u
ON ( ug.user_id = u.user_id )
INNER JOIN tbl_user_association ua
ON ( ua.staff_id = u.user_id )
INNER JOIN tbl_user so -- here join again the user table to get shop owners names
ON ( ua.shop_owner_id = so.user_id )
WHERE
ug.user_type = 2
GROUP BY
u.user_id;
There are two tables
users
+--+----+
|id|name|
+--+----+
1 A
2 B
orders
+--+--------+-------+-------+
|id|subtotal|created|user_id|
+--+--------+-------+-------+
1 10 1000001 1
2 20 1000002 1
3 10 1000003 2
4 10 1000005 1
The idea is to get AVG, SUM and the last created order from the users.
SELECT
users.name,
users.phone,
SUM(a.subtotal),
COALESCE(a.created, NULL)
FROM users
LEFT JOIN
(
SELECT
orders.id,
orders.subtotal,
orders.user_id,
orders.created
FROM
orders
JOIN(
SELECT MAX(i.created) created, i.user_id
FROM orders i
GROUP BY i.user_id
)AS j ON(j.user_id = orders.user_id AND orders.created = j.created) GROUP BY orders.user_id
) AS a ON users.id = a.user_id
GROUP BY users.id
For example the SQL request should return this:
+--+----+---+--------+
|id|name|sum|date |
+--+----+---+--------+
1 A 40 1000005
2 B 10 1000003
But the SQL above failed to calculate sum. What did i miss?
Your query seems way too complicated. How about this?
SELECT u.id, u.name, SUM(o.subtotal), MAX(o.created)
FROM users u LEFT JOIN
orders o
ON u.id = o.user_id
GROUP BY u.id, u.name;
In MySQL it is particularly important to avoid unnecessary subqueries in the FROM clause. These are actually materialized and that can impede the use of indexes for performance.
It must be pretty easy, but i can't think of any solution nor can I find an answer somewhere...
I got the table 'users'
and one table 'blogs' (user_id, blogpost)
and one table 'messages' (user_id, message)
I'd like to have the following result:
User | count(blogs) | count(messages)
Jim | 0 | 3
Tom | 2 | 3
Tim | 0 | 1
Foo | 2 | 0
So what I did is:
SELECT u.id, count(b.id), count(m.id) FROM `users` u
LEFT JOIN blogs b ON b.user_id = u.id
LEFT JOIN messages m ON m.user_id = u.id
GROUP BY u.id
It obviously doesn't work, because the second left join relates to blogs not users. Any suggestions?
First, if you only want the count value, you could do subselects:
select u.id, u.name,
(select count(b.id) from blogs where userid = u.id) as 'blogs',
(select count(m.id) from messages where userid = u.id) as 'messages'
from 'users'
Note that this is just a plain sql example, I have no mysql db here to test it right now.
On the other hand, you could do a join, but you should use an outer join to include users without blogs but with messages. That would imply that you get several users multiple times, so a group by would be helpful.
If you use an aggregate function in a select, SQL will collapse all your rows into a single row.
In order to get more than 1 row out you must use a group by clause.
Then SQL will generate totals per user.
Fastest option
SELECT
u.id
, (SELECT(COUNT(*) FROM blogs b WHERE b.user_id = u.id) as blogcount
, (SELECT(COUNT(*) FROM messages m WHERE m.user_id = u.id) as messagecount
FROM users u
Why you code does not work
SELECT u.id, count(b.id), count(m.id)
FROM users u
LEFT JOIN blogs b ON b.user_id = u.id <<-- 3 matches multiplies # of rows *3
LEFT JOIN messages m ON m.user_id = u.id <<-- 5 matches multiplies # of rows *5
GROUP BY u.id
The count will be off, because you are counting duplicate items.
Simple fix, but will be slower than option 1
If you only count distinct id's, you will get the correct counts:
SELECT u.id, count(DISTNICT b.id), count(DISTINCT m.id)
FROM users u
LEFT JOIN blogs b ON b.user_id = u.id
LEFT JOIN messages m ON m.user_id = u.id
GROUP BY u.id