I'm having issues trying to figure out how to group and sum subitem with parent item rows.
I have a SQL query that looks like this:
select
topics.name,
sum(commission_amount) as commission
from orders
left join topics
on topics.id = orders.topic_id
group by 1
This works, however I'm trying to group and use only parent topic names.
Topics table:
id
name
topic_id
1
Meal Delivery
NULL
2
Vegan Meal Delivery
1
3
Vegetarian Meal Delivery
1
4
Mattresses
NULL
5
Hybrid Mattress
4
6
Memory Foam Mattress
4
So a parent topic is when topic_id = NULL
Orders table:
id
topic_id
commission_amount
1
1
10
2
2
20
3
3
30
4
4
40
5
5
50
6
6
60
Desired output is this:
name
commission
Meal Delivery
60
Mattresses
150
Join with topics again.
SELECT name, SUM(commission) AS commission
FROM (
-- subtopic commissions
SELECT t1.name, IFNULL(SUM(o.commission_amount), 0) AS commission
FROM topics AS t1
LEFT JOIN topics AS t2 ON t1.id = t2.topic_id
LEFT JOIN orders AS o ON o.topic_id = t2.id
WHERE t1.topic_id IS NULL -- only show parent topics
GROUP BY t1.name
UNION ALL
-- parent topic commissions
SELECT t.name, IFNULL(SUM(o.commission_amount), 0) AS commission
FROM topics AS t
LEFT JOIN orders AS o ON o.topic_id = t.id
WHERE t.topic_id IS NULL
GROUP BY t.name
) AS x
GROUP BY name
Here is a simpler look of the answer using self-join.
SELECT t1.name, SUM(o.commision_amount) AS commision
FROM topics t1
INNER JOIN topics t2 ON t1.id = t2.topic_id OR t1.id = t2.id
INNER JOIN orders o ON t2.id = o.topic_id
WHERE t1.topic_id IS NULL
GROUP BY t1.name;
See db<>fiddle
You can do a self-join to bring all parent topics, and children to the same level:
select TPnt.Name, sum(O.Commission_amount) as Commission_amount
from
Topics TPnt
inner join
Topics TChld
on TPnt.Id=coalesce(TChld.topic_id, TChld.id)
inner join
Orders O
on O.topic_id=TChld.id
group by TPnt.Name
Related
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
Table : O
ID Date
1 2016-01-10
2 2016-01-10
3 2016-01-11
Table : OD
ODI ID Quantity
1 1 1
2 1 2
3 2 1
4 3 1
Table: OH
OHI ID
1 1
2 2
3 1
4 3
I have three table O,OD,OH. I need to join these three table and get the sum of quantity For each day.
Tried
SELECT O.date,SUM(od.Quantity),group_concat(OHI) FROM O
INNER JOIN OD ON OD.ID = O.ID
INNER JOIN OH ON OH.ID = O.ID
GROUP BY O.date;
But the resulting quantity sum was different due to joining the OH Table.Now How do i get the proper Sum.
Expected Result :
Date SUM(od.Quantity)
2016-01-10 4
2016-01-10 1
Sorry For Change In The Question.
You don't need to join OH table, this can be done with below query:
SELECT O.ID,SUM(od.Quantity) FROM O
INNER JOIN OD ON OD.ID = O.ID
GROUP BY O.ID;
You don't need to join with the OH table.
select O.ID, SUM(OD.Quantity) total_qty
from O inner join OD
on O.ID = OD.ID
group by O.ID;
If you need join with OH, then do it after aggregation.
select *
from OH inner join (
select O.ID, SUM(OD.Quantity) total_qty
from O inner join OD
on O.ID = OD.ID
group by O.ID
) t on t.ID = OH.ID;
Aggregate over the OD table first in a subquery, then join this to the other two tables:
SELECT t1.Date,
t2.Quantity,
t3.OHI -- and possibly other columns from OH
FROM O t1
INNER JOIN
(
SELECT ID, SUM(Quantity) AS Quantity
FROM OD
GROUP BY ID
) t2
ON t1.ID = t2.ID
INNER JOIN OH t3
ON t1.ID = t3.ID
I have database with following data structure with sample data. Each company have multiple members. The relationship is in the company_member table. Please note only required fields I have given below.
company
id title
1 company-1
2 company-2
company_member
companyid memberid
1 1
1 2
1 3
2 4
2 5
2 6
member
id firstname member_type_id
1 Name-1 2
2 Name-2 3
3 Name-3 3
4 Name-4 3
5 Name-5 2
6 Name-6 1
member_type
id user_level
1 0
2 1
3 2
I want list of unique companies with one member from each. But the member should be the lowest user_level within the company. i.e, following result should come;
result
companyid company_title memberid member_name user_level
1 company-1 1 Name-1 1
2 company-2 6 Name-6 0
I want to know how to get one member with lowest user level among the same company.
This is a bit complicated one, however this is one way of doing it using not exists, for bigger tables its wise to use not exits since using pivot tables it will not use index.
select
c.id,
c.title,
m.id as member_id,
m.firstname,
mt.user_level
from company_member_map cmp
join company c on c.id = cmp.companyid
join member m on m.id = cmp.memberid
join member_type mt on mt.id = m.member_type_id
where not exists
(
select 1 from company_member_map t1
join member t2 on t2.id = t1.memberid
join member_type t3 on t3.id = t2.member_type_id
where
t1.companyid = cmp.companyid
and t3.user_level < mt.user_level
)
DEMO
Finally I found solution:
select c.id companyid, c.title company_title, m.firstname member_name, mt.user_level
from company c
inner join company_member cm on cm.companyid = c.id
inner join member m on m.id = cm.memberid
inner join member_type mt on mt.id = m.member_type_id
inner join
(select c1.id companyid, mt1.user_level
from company c1
join company_member cm1 on cm1.companyid = c1.id
join member m1 on m1.id = cm1.memberid
join member_type mt1 on mt1.id = m1.member_type_id
group by c1.id,m1.id
order by user_level asc
) sq on c.id = sq.companyid and sq.user_level = mt.user_level
group by c.id;
Correct this, if anyone have better solution or simplified solution.
Check this SQL Fiddle
I have two tables one containg offer information and the other containg products
something like this:
OFFER PRODUCTS
ID Number Version poID offer_id Product how_many
========================== ========================================
1 123 1 1 1 Apple 1
2 123 2 2 1 Banana 2
3 124 1 3 1 Orange 1
4 2 Apple 1
5 2 Banana 2
6 2 Orange 2
7 2 Kiwi 1
8 3 Apple 2
9 3 Banana 3
I would like a list of how many products that are currently offered.
Since OFFER(id = 2) is an update of (id = 1) only (id = 2) should be counted.
How should I best query this?
First you need to get all the latests offers:
select o.id
from offer o
where version = (select max(version)
from offer o2
where o2.number = o.number);
Based on the above you can then get all the products:
select p.*
from products p
where offer_id in (select o.id
from offer o
where version = (select max(version)
from offer o2
where o2.number = o.number));
If id and version correlate:
select sum(how_many) from products p
join offer on p.offer_id=offer.id
join (
select number, max(version) version from offer group by number
) x
on offer.id=x.id and offer.version = x.version
SELECT *
FROM products
WHERE offer_id = (SELECT MAX(id) FROM offer)
or, if you prefer the join syntax
SELECT p.*
FROM products p
INNER JOIN (SELECT MAX(id) id FROM offer) o ON p.offer_id = o.id
Edit (still not completely sure this is what you want without seeing your desired results)
SELECT p.*
FROM products p
INNER JOIN offer o on p.offer_id = o.id
INNER JOIN
(SELECT number, max(version)
FROM offer
GROUP BY number
) oMax ON o.number = oMax.number AND o.version = oMax.version
Try this:
select [list columns here]
from products p
join (select offernumber, max(id) as ID from offer group by offernumber) a
on a.id = p.offer_id
If you need addtional columns from offer other than the offernumber and the id:
select [list columns here]
from products p
join (select offernumber, max(id) as ID from offer group by offernumber) a
on a.id = p.offer_id
join offer o on o.id = a.id
I have two tables:
parent-child 'categories':
id name parent_id
1 Food NULL
2 Pizza 1
3 Pasta 2
'transactions':
id amount category_id
1 100 1
2 50 2
3 25 2
I want to return all the Categories along with two total columns:
total = The sum of the amount for all transactions with this category_id
parentTotal = total + the total of all its child categories
Example (using the tables above):
id name parent_id total parentTotal
1 Food NULL 100 175
2 Pizza 1 0 0
3 Pasta 2 75 0
EDIT:
Code updated (based on code from Nedret Recep below) and works fine...
SELECT
tmp1.id, tmp1.name, tmp1.parent_id, tmp1.total, IFNULL(tmp1.total, 0) + IFNULL(tmp2.s, 0) AS parenttotal
FROM
(SELECT
ca.id, ca.name, ca.parent_id, SUM(tr.amount) as total
FROM
categories ca
LEFT JOIN
transactions tr
ON
tr.category_id = ca.id
GROUP BY
ca.id)
AS tmp1
LEFT JOIN
(SELECT
c.id, c.parent_id as categoryid, SUM(t.amount) AS s
FROM
transactions t
RIGHT JOIN
categories c
ON
t.category_id = c.id
GROUP BY
c.parent_id)
AS tmp2
ON tmp2.categoryid = tmp1.id
order by coalesce(tmp1.parent_id, tmp1.id), tmp1.parent_id
I'd really appreciate some help - thanks!
With one inner join we calculate the totals in category which is standard. Then with another inner join we calculate the sums but this time grouping by parent_id. Then we join the two result tables to have both sums in one row. This query will be slow with large tables so an alternative approach on application level would do better.
SELECT
tmp1.id, tmp1.name, tmp1.parent_id, tmp1.total, tmp1.total + tmp2.s AS parenttotal
FROM
(SELECT
ca.id, ca.name, ca.parent_id, SUM(tr.amount) as total
FROM
transactions tr
INNER JOIN
categories ca
ON
tr.categoru_id = ca.id
GROUP BY
ca.id)AS tmp1
LEFT OUTER JOIN
(
SELECT
c.parent_id as categoryid, SUM(t.amount) AS s
FROM
transactions t
INNER JOIN
categories c
ON
t.category_id = c.i
GROUP
BY c.id ) AS tmp2
ON
tmp2.categoryid = tmp.id