SQl - find average amount per person - mysql

I have two tables
class
| id | area | students |
| 1 | area1 | 2 |
| 2 | area1 | 28 |
| 3 | area1 | 22 |
| 4 | area2 | 4 |
deliveries
| id | kg | classid |
| 1 | 120 | 1 |
| 2 | 80 | 1 |
| 3 | 20 | 1 |
| 4 | 200 | 2 |
| 5 | 150 | 3 |
| 6 | 14 | 2 |
I need to sum up the average of kg delivered per student in a each area.
For area1 that should amount to (120+80+20+200+150+14)/(2+28+22) = 11.23
But I can't figure out how to write that query. I guess I have to use some kind of subquery to first sum out students in area1 (52), before I sum kg delivered and divide on students?

This is a little tricky, because the students should be counted separately from the classes:
select c.area, sum(d.kg) / max(area_students) as avg_kg_per_student
from class c join
deliveries d
on d.classid = c.id join
(select c2.area, sum(students) as area_students
from class c2
group by c2.area
) c2
on c2.area = c.area
group by c.area;

I think you cannot use average because you need to determine the denominator yourself:
SELECT sum(kg)/ studSum AS avg
FROM _class LEFT JOIN _deliveries ON _class.id=_deliveries.classid
left join (select area, sum(students) as studSum from _class group by area) subT
ON subT.area=_class.area
GROUP BY _class.area;

Here is a very readable approach: Get students per area and kg per area, then join the two.
select stu.area, stu.students, del.kg, del.kg / stu.students
from
(
select area, sum(students) as students
from class
group by area
) stu
join
(
select c.area, sum(d.kg) as kg
from class c
join deliveries d on d.classid = c.classid
group by c.area
) del on del.area = stu.area;

Related

How can I not take in consideration values join without record on the db

I'm in front of a "minor" problem taht looks easy but I didn't suceed to resolve it.
I have three tables in my Database :
Table gp
____________
id | name |
____________
1 | Le Mans|
2 | Toulon |
3 | Rennes |
Table player
____________
id | name |
____________
1 | Thibaut|
2 | Fred |
3 | Samir |
Table Records
_____________________________
id | gp_id | player_id | time
_____________________________
1 | 1 | 1 | 17860
2 | 2 | 1 | 11311
3 | 3 | 1 | 33133
4 | 3 | 2 | 11113
5 | 2 | 2 | 44444
6 | 1 | 2 | 13131
7 | 1 | 3 | 11111
8 | 3 | 3 | 21112
I want to get a sum of time for players that have a record on every gp ( so in my case, just players Thibaut and Fred have a record on the 3 gp ( Samir has just a record on two gp ) ).
I have no idea how I can get that, of course this SQL query is retrieving a sum but from this query I want to escape the guys that don't have a record on every GPs, but I'm blocked at that point ...
SELECT p.name, sum(time)
from records r
join gp g on r.gp_id = g.id
join player p on r.player_id = p.id
group by r.player_id
Thanks in advance guys !
You could use having count to exclude the records that don't have a record on every GPs.
Try:
select p.name,
sum(`time`) as tot_sum
from records r
inner join player p on r.player_id=p.id
inner join gp g on g.id=r.gp_id
group by p.name
having count(distinct gp_id) = (select count(distinct id) from gp)
https://dbfiddle.uk/t8QwSFDY
having count(distinct gp_id) = (select count(distinct id) from gp) will match only the records in the record table that have a record on every gp.

SQL/MySQL - Select and return array column on one-to-many table join [duplicate]

We have 3 tables :
donations
purposes
expenses
Donations :
+--------+------+
| do_id | name |
+--------+------+
| 1 | A |
| 2 | B |
| 3 | A |
| 4 | D |
| 5 | B |
| 6 | B |
| 7 | A |
| 8 | B |
+--------+----- +
purposes:
+-------+-------+--------+
| pu_id | do_id | purpose|
+-------+-------+--------+
| 1 | 2 | abc |
| 2 | 2 | def |
| 3 | 2 | gih |
| 4 | 3 | jkl |
+-------+-------+--------+
expense :
+-------+-------+---------+
| ex_id | do_id | expense |
+-------+-------+---------+
| 1 | 2 | abc |
| 2 | 2 | def |
| 3 | 2 | gih |
| 4 | 3 | jkl |
+-------+-------+---------+
Now i want to make query to get all donations for donor B and join purposes table to get all purposes related to every donation_id then join expenses table to get all expenses related to donation_id and put all of that in every loop independently something like that
Row number 0
donation_id = 1
array(purposes)
array(expenses)
Row number 1
donation_id = 2
array(purposes)
array(expenses)
Row number 2
donation_id = 3
array(purposes)
array(expenses)
Row number 3
donation_id = 4
array(purposes)
array(expenses)
This is my try :
SELECT *, (
SELECT *
FROM `donation_purposes`
WHERE `donation_purposes`.`dopu_donation_id` = 4
) AS `purposes`
FROM `donations`
WHERE `donation_id` = '4'
thanks in advance
You should be able to solive this with an aggregate query using MySQL aggregate function JSON_ARRAYAGG(), like :
SELECT
d.do_id,
JSON_ARRAYAGG(p.purpose) purposes,
JSON_ARRAYAGG(e.expense) expenses
FROM donations d
INNER JOIN purposes p ON p.do_id = d.do_id
INNER JOIN expense e ON e.do_id = d.do_id
GROUP BY d.do_id
I you want to avoid duplicate values in the array, and as JSON_ARRAYAGG() (sadly) does not support the DISTINCT option, you can move aggregation to subqueries, like :
SELECT
d.do_id,
p.agg purpose,
e.agg expenses
FROM donations d
INNER JOIN (
SELECT do_id, JSON_ARRAYAGG(purpose) agg FROM purposes GROUP BY do_id
) p ON p.do_id = d.do_id
INNER JOIN (
SELECT do_id, JSON_ARRAYAGG(expense) agg FROM expense GROUP BY do_id
) e ON e.do_id = d.do_id
This demo on DB Fiddle returns :
| do_id | purpose | expenses |
| ----- | --------------------- | --------------------- |
| 2 | ["abc", "def", "gih"] | ["abc", "def", "gih"] |
| 3 | ["jkl"] | ["jkl"] |
1st Select Query Purposes
SELECT purposes.* FROM purposes
LEFT JOIN donations
ON purposes.do_id = donations.do_id
WHERE donations.do_id = '2' //This depends on the id of the donation
ORDER BY purposes.do_id ASC
2nd Select Query Expenses
SELECT expense.* FROM expense
LEFT JOIN donations
ON expense.do_id = donations.do_id
WHERE donations.do_id = '2' //This depends on the id of the donation
ORDER BY expense.ex_id ASC
All queries generated are from the table structure you've provided, but your question is quite vague!!

How to get hotel total room and booked room in single query

How to get hotel total room and booked room in single query.
I used 2 queries get result. I need this in single query.
The issue I am experiencing since all counts are in this table htl_room_information.id_hotel
Booked room:
SELECT x.hotel_name
, count(i.id_hotel) room
FROM htl_booking_detail d
JOIN htl_branch_info_lang x
ON x.id=d.id_hotel
JOIN htl_room_information i
ON d.id_room=i.id
group
by x.hotel_name;
+------------------------------------------+------+
| hotel_name | room |
+------------------------------------------+------+
| hotel | 3 |
| hotel1 | 1 |
| hotel2 | 4 |
| hotel3 | 13 |
| hotel4 | 9 |
| hotel5 | 3 |
| hotel6 | 3 |
| hotel7 | 2 |
+------------------------------------------+------+
Total Rooms
SELECT (htl_branch_info_lang.hotel_name) as hotel_name,count(htl_room_information.id_hotel) as total_room FROM htl_room_information ,htl_branch_info_lang where htl_room_information.id_hotel=htl_branch_info_lang.id group by htl_branch_info_lang.hotel_name;
+------------------------------------------+------------+
| hotel_name | total_room |
+------------------------------------------+------------+
| hotel | 219 |
| hotel2 | 25 |
| hotel3 | 16 |
| hotel4 | 5 |
| hotel5 | 55 |
| hotel6 | 27 |
| hotel7 | 56 |
| hotel8 | 52 |
+------------------------------------------+------------+
Use dependent subqueries.
SELECT x.hotel_name,
(
SELECT count(i.id_hotel)
FROM htl_booking_detail d
JOIN htl_room_information i
ON d.id_room=i.id
WHERE x.id=d.id_hotel
) as room,
(
SELECT count(i.id_hotel)
FROM htl_room_information i
WHERE i.id_hotel=x.id
) as total_room
FROM htl_branch_info_lang x
I assume that the hotel_name is unique in the htl_branch_info_lang table. If not, you have to put distinct behind the first SELECT.
Hoping, I understood your question correctly.
Please check below query.
select b.hotel_name hotel_name, a.room ,
b.total_room
from
(SELECT htl_branch_info_lang.hotel_name,
count(htl_room_information.id_hotel) as room FROM htl_booking_detail,
htl_branch_info_lang, htl_room_information WHERE
htl_branch_info_lang.id=htl_booking_detail.id_hotel and
htl_booking_detail.id_room=htl_room_information.id group by
htl_branch_info_lang.hotel_name ) a RIGHT join (SELECT (htl_branch_info_lang.hotel_name) as
hotel_name,count(htl_room_information.id_hotel) as total_room
FROM htl_room_information ,htl_branch_info_lang
where htl_room_information.id_hotel=htl_branch_info_lang.id
group by htl_branch_info_lang.hotel_name) b
on a.hotel_name = b.hotel_name
;
You can use subquery
try this:
SELECT (a.hotel_name) as
hotel_name,count(htl_room_information.id_hotel) as total_room, (SELECT
count(htl_room_information.id_hotel) as room FROM htl_booking_detail,
htl_branch_info_lang b, htl_room_information WHERE
b.id=htl_booking_detail.id_hotel and
htl_booking_detail.id_room=htl_room_information.id and
b.hotel_name = a.hotel_name), count(htl_room_information.id_hotel) - (SELECT
count(htl_room_information.id_hotel) as room FROM htl_booking_detail,
htl_branch_info_lang b, htl_room_information WHERE
b.id=htl_booking_detail.id_hotel and
htl_booking_detail.id_room=htl_room_information.id and
b.hotel_name = a.hotel_name) as available FROM htl_room_information
,htl_branch_info_lang
a where htl_room_information.id_hotel=a.id group by
a.hotel_name;

Add column in query using LEFT JOIN

I have three tables.
tblcandidates
candidateid | candidatename
1 | Abc
2 | Def
tbljudges
judgeid | judgename
1 | Stack
2 | Overflow
tblscores
scoreid | candidateid | judgeid | swimsuit
1 | 1 | 1 | 100
2 | 1 | 2 | 99
3 | 2 | 1 | 100
4 | 2 | 2 | 93
I am using this query to get the average of each candidate.
SELECT DISTINCT
(c.candidateid) AS c,
candidatename AS NAME,
j1.swimsuit AS j1,
j2.swimsuit AS j2,
(
j1.swimsuit + j2.swimsuit
) / 2 AS average
FROM
tblscores,
tblcandidates c
LEFT JOIN tblscores j1 ON c.candidateid = j1.candidateid
AND j1.judgeid = 1
LEFT JOIN tblscores j2 ON c.candidateid = j2.candidateid
AND j2.judgeid = 2
WHERE tblscores.candidateid = c.candidateid;
Output
c | name | j1 | j2 | average
1 | Abc | 100 | 99 | 99.5
2 | Def | 100 | 93 | 96.5
My problem is what if the judges become 3. I want to make my query dynamic depending on the number of judges. My query is limited to 2 judges only. I also want to display the judges scores like in my output for the proof that they have a score.
You are re-inventing the wheel here by implementing the average calculation yourself. Instead, you could use MySQL's builtin aggregate avg function. If you really want all the scores too, you could use group_concat to display them:
SELECT c.candidateid AS id,
candidatename AS name,
GROUP_CONCAT(swimsuit) AS all_scores,
AVG(swimsuit) AS average_score
FROM tblcandidates c
JOIN tblscores s ON c.candidateid = s.candidateid
GROUP BY c.candidateid, candidatename

select query to calculate number of occurrence as well as total cost

I have one report page which displays summarized data of other report.I have used php and mysqli. Let me explain you in deep.
I have a web application of store, where you can add product details. Using these product details you can generate packaging list report of products. And based on the generated packaging list report I need to generate one other report which contains summarized data of the packaging list.
below are my tables:
product table:
id | name | desc_id | purity | style_no | type | duty
1 | ABC | 1 | 18 | TEST123 | R | 100
2 | XYZ | 2 | 14 | TEST456 | B | 80
3 | DEF | 1 | 14 | TEST122 | R | 80
4 | PQR | 1 | 18 | TEST124 | R | 120
5 | HJK | 3 | 18 | TEST134 | B | 300
Description table:
id | descrip
1 | Gold Diamond Ring
2 | Gold Diamond Pendant
3 | Gold Diamond Earring
packaging_master table
id | name
1 | pkg_1
2 | pkg_2
packging_details table
id | pkg_id | prod_id
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 1 | 4
5 | 1 | 5
I have used below query to generate the packaging list report for specific id, which works correctly.
SELECT id, (SELECT descrip FROM description WHERE id = desc_id ) AS descrip,
style_no, type , purity, duty FROM product WHERE id IN ( SELECT prod_id FROM packaging_list_details WHERE pkg_id =1 ) ORDER BY descrip ASC , purity ASC
which displays below result:
id | descrip | style_no | type | purity | duty
1 |Gold Diamond Ring | TEST123 | R | 18 | 100
4 |Gold Diamond Ring | TEST124 | R | 18 | 120
3 |Gold Diamond Ring | TEST122 | R | 14 | 80
2 |Gold Diamond Pendant| TEST456 | B | 14 | 80
5 |Gold Diamond Earring| TEST134 | B | 18 | 300
Now I want summarized data of above result using query.
Like:
id | descrip | purity | qty | duty
1 |Gold Diamond Ring | 18 | 2 | 220
2 |Gold Diamond Ring | 14 | 1 | 80
3 |Gold Diamond Pendant| 14 | 1 | 80
4 |Gold Diamond Earring| 18 | 1 | 300
How can I achieve this?
You need to use the GROUP_BY statement - See MySql docs for more info.
This will translate the query to such
SELECT d.descrip, p.purity, count(p.purity) as qty, sum(p.duty)
FROM product p
INNER JOIN Description d ON p.desc_id = d.id
LEFT OUTER JOIN packaging_details pg on pg.prod_id = p.id
GROUP BY d.descrip, p.purity
ORDER BY d.descrip desc, p.purity desc
You can also use the sub select methodology you were using, but I prefer using joins. INNER JOIN will link both tables so that all their records are returned. OUTER JOIN will return all rows from the tables on the LEFT of the statement and matches them to values from the tables on the RIGHT.
See a full SQL Fiddle sample.
NOTE: I am not sure where you are getting the values for Id in your sample - Are they simply row numbers?
I think you should rewrite your query using JOINs:
SELECT
P.id
,D.descrip
,P.style_no
,P.type
,P.purity
,P.duty
FROM
packaging_list_details PLD
JOIN
product P ON
(P.id = PLD.prod_id)
LEFT JOIN
description D on
(D.desc_id = P.id)
WHERE
(PLID.pkg_id = 1)
That should give you the same result you already have. To get the totals, you can write a new query, similar to the above:
SELECT
P.id
,D.descrip
,P.type
,P.purity
,COUNT(p.id) as total_products
,SUM(P.duty) as total_duty
FROM
packaging_list_details PLD
JOIN
product P ON
(P.id = PLD.prod_id)
LEFT JOIN
description D on
(D.desc_id = P.id)
WHERE
(PLID.pkg_id = 1)
GROUP BY
P.id
,D.descrip
,P.type
,P.purity
The second query gives you the totals you are looking for.