MYSQL JOIN query to group user skills for conditional count - mysql

I am struggling to find the logic for a JOIN query with GROUP BY.
I have 3 tables.
1. tbl_users
2. tbl_event_orders
3.tbl_event_signature ( For saving signatures on completed events)
tbl_users
id name skill
---------------------------
1 user1 A
2 user2 B
3 user3 A
4 user4 A
tbl_orders
id user_id item_id price
------------------------------------
1 1 1 100
2 2 1 100
3 3 1 100
4 4 1 100
tbl_signature
id item_id user_id signature
----------------------------------------------
1 1 1 xxxxxxxx...
1 1 3 NULL
1 1 4 xxxxxxxx...
I need the event details from item id.
For example for item with id 1, I need the following result.
skill total_count attended_users_count amount
A 3 2 300
B 1 0 100
skill - skill from user table.
total_count - total count of orders from that partical skill.
attended_users_count - total count of orders from that partical skill + this should have an entry and a NOT NULL value in tbl_signature table.
amount - sum of price(total_count)
I have the following query for getting users with skills and total count.
SELECT
U.skill as skill,
count(U.skill) as total_count,
sum( O.price ) as amount
FROM tbl_users U
INNER JOIN tbl_orders O
ON U.id = O.user_id
WHERE O.item_id = 1
GROUP BY U.skill
but when dealing with attended users count, I am getting unexpected results.
I have tried with the following query,
SELECT
U.skill as skill,
count(U.skill) as total_count,
count( S.signature ) as attended_users_count,
sum( O.price ) as amount
FROM tbl_users U
INNER JOIN tbl_orders O
ON U.id = O.user_id
LEFT JOIN tbl_signature S
ON O.item_id = S.item_id
WHERE O.item_id = 1
GROUP BY U.skill
Is there any way to get this in a single query?

This query should give you the results you want. It JOINs tbl_orders to tbl_users, and then LEFT JOINs to tbl_signature. Rows of tbl_signature which don't match, or which don't have a signature, will not get included in the count for that order:
SELECT u.skill,
COUNT(o.id) AS total_count,
COUNT(s.signature) AS attended_users_count,
SUM(o.price) AS amount
FROM tbl_orders o
JOIN tbl_users u ON u.id = o.user_id
LEFT JOIN tbl_signature s ON s.item_id = o.item_id AND s.user_id = u.id
WHERE o.item_id = 1
GROUP BY u.skill
Output:
skill total_count attended_users_count amount
A 3 2 300
B 1 0 100
Demo on dbfiddle

Related

Why the join is not working without group by statement

If I remove the group by statement, then it is showing an error.
SELECT COMPANY.COMPANY_CODE,
company.founder,
count(distinct lm.lead_manager_code),
count(distinct sm.senior_manager_code),
count(distinct m.manager_code),
count(distinct e.employee_code)
from Company
join Lead_Manager as lm on Company.company_code = lm.company_code
join Senior_Manager as sm on Company.company_code = sm.company_code
join Manager as m on Company.company_code = m.company_code
join Employee as e on Company.company_code = e.company_code
GROUP BY Company.COMPANY_CODE, Company.FOUNDER
ORDER BY Company.COMPANY_CODE ASC
Basically, you are using an aggregate function so you need to group
select count(amount) from Orders group by customer_id
Orders
order_id item amount customer_id
1 Keyboard 400 4
2 Mouse 300 4
3 Monitor 12000 3
4 Keyboard 400 1
5 Mousepad 250 2
Now using group by on customer_id so we have id 4 so need to check the count of 4 id with group by

Sum values from another table sql

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

How to join these tables?

I have three tables in a database, as follows:
users:
user_id name pbal
1 m1 100
2 m2 200
3 m3 300
4 m4 400
5 m5 500
payouts:
id user_id amount
1 1 100
2 1 200
3 2 300
4 1 400
blocked:
id user_id status
------ -------- ------
1 2 block
2 3 block
Now I want to make a list that excludes users whose user_id is in the blocked table, and that calculates a new total amount based on the pbal from users and the amount from the related rows in payouts:
name total_amount
----- ------------
m1 800
m5 500
m4 400
I have been trying for half an hour, but failed. Can someone help me?
Here's an example:
SELECT u.name, u.user_id, MAX(u.pbal) + SUM(p.amount) AS total_amount
FROM dbo.Payouts p
INNER JOIN dbo.Users u ON u.user_id = p.user_id
LEFT OUTER JOIN dbo.Blocked b ON u.user_id = b.user_id
WHERE b.user_id IS NULL
GROUP BY u.user_id, u.name
ORDER BY MAX(u.pbal) + SUM(p.amount) DESC;
Here is a possible answer:
SELECT u.name, u.user_id,
u.pbal + (
-- this takes amounts from the payouts table
SELECT SUM(p.amount)
FROM dbo.Payouts p
WHERE u.user_id = p.user_id
) AS total
FROM dbo.Users u
WHERE NOT EXISTS (
-- this excludes blocked users
SELECT *
FROM dbo.Blocked b
WHERE u.user_id = b.user_id
)
ORDER BY total;
I prefer subqueries in this case because they make it a bit more explicit

SQL join and sum of items

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.

mysql: list number of orders all customers made

I have 2 simple tables like customers and orders where a customer can have 0 to n orders. I would like to have a list like:
10 customers made 0 orders
4 customers made 1 order
5 customers made 2 orders
2 customers made 3 orders
... and so on. So far I have:
SELECT customers.id FROM customers
LEFT JOIN orders ON orders.customerId = customers.id
HAVING COUNT(orders.id) = 1;
which lists me all customers who made 1 order, but as I said I need a list with all possebilities.
SELECT COUNT(*), t.orderCount
FROM
(
SELECT u.id, COUNT(o.id) AS orderCount
FROM users u LEFT JOIN orders o
ON u.id = o.userId
GROUP BY u.id
) t
GROUP BY t.orderCount
The inner query will give each user and his order total:
user total
1 2
2 3
3 2
4 3
The outer query does a GROUP BY this total to count the number of customers who share the total:
# customers total
2 2
2 3
You can use aggregate function and group bu
SELECT ifnull(count(orders.id),0), users.id FROM users
LEFT JOIN orders ON orders.userId = users.id
group by users.id