How to find total percentage of students who are absent or tardy in SQL? [closed] - mysql

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have a grade_level and total_num_students columns but not sure how to create a column to get the percentage of students who are absent/tardy. (Each student id is unique and in both tables)
Here are the two tables:
And here is my current SQL query that I have so far:
SELECT
grade_level,
COUNT(student_attendance_log.attendance_status) AS 'total_num_students'
FROM student_info
INNER JOIN student_attendance_log
ON student_info.student_id = student_attendance_log.student_id
WHERE student_attendance_log.attendance_status = 'Tardy'
OR student_attendance_log.attendance_status = 'Absent'
GROUP BY grade_level
ORDER BY grade_level;
which produces:

I recommend avg() for this calculation:
SELECT grade_level, COUNT(*) as total_num_students,
AVG(CASE WHEN sal.attendance_status = 'Tardy' THEN 1.0 ELSE 0 END) as tardy_ratio,
AVG(CASE WHEN sal.attendance_status = 'Absent' THEN 1.0 ELSE 0 END) as absent_ratio
FROM student_info si INNER JOIN
student_attendance_log sal
ON si.student_id = sal.student_id
GROUP BY grade_level
ORDER BY grade_level;
Note some changes:
Table aliases makes the query easier to write and to read.
Only use single quotes for string and date constants. Don't use them for column names.
The filtering has moved from the WHERE clause to the AVG().

Related

SQL Code working but not giving the right numbers [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 months ago.
Improve this question
SELECT
bikers.id AS 'Biker ID',
bikers.first_name AS 'Biker Name',
SUM(offline_bookings.total_price) AS 'Offline Revenue',
SUM(offline_bookings.main_service_count) AS 'Offline Cars' ,
SUM(offline_bookings.extra_service_count) AS 'Extra Service Count',
COUNT(bookings.id) AS 'Online Cars', SUM(bookings.paid) AS 'Online Revenue'
FROM bikers
JOIN offline_bookings ON bikers.id = offline_bookings.biker_id
JOIN bookings ON bookings.biker_id = bikers.id
WHERE offline_bookings.`date` = '2022-10-10'
AND bookings.booking_date = '2022-10-10'
AND offline_bookings.`status` = TRUE
GROUP BY bikers.id , bikers.first_name
ORDER BY bikers.id , bikers.first_name;
In the request comments you say that bookings and offline_bookings are only related by belonging to the same biker. But you are joining them on the biker ID. This means for a biker with 4 bookings and 5 offline_bookings you generate 4 x 5 = 20 rows. If you then aggregate and build sums or counts you get every booking five-fold and every offline_booking four-fold.
You don't want to join booking rows with offline_booking rows. You want to join totals instead. So, aggregate your data before joining.
SELECT
b.id AS biker_id,
b.first_name AS biker_name,
obk.offline_revenue,
obk.offline_cars,
obk.extra_service_count,
bk.online_cars,
bk.online_revenue
FROM bikers b
LEFT OUTER JOIN
(
SELECT
biker_id,
SUM(total_price) AS offline_revenue,
SUM(main_service_count) AS offline_cars,
SUM(extra_service_count) AS extra_service_count
FROM offline_bookings
WHERE `date` = DATE '2022-10-10'
AND status = TRUE
GROUP BY biker_id
) obk ON ON obk.biker_id = b.id
LEFT OUTER JOIN
(
SELECT
biker_id,
COUNT(*) AS online_cars,
SUM(paid) AS online_revenue
FROM bookings
WHERE `date` = DATE '2022-10-10'
GROUP BY biker_id
) bk ON ON bk.biker_id = b.id
ORDER BY b.id;
I've made this outer joins for the case a biker lacks a booking or offline_booking that day. If you only want biker that have both, just make these inner joins again.
I've also removed the invalid single quotes for your column aliases. Single quotes are for string literals. Use standard SQL double quotes or MySQL's propriatary backticks for names instead. Or use names that need no quotes, like I did. If you want column headers with spaces in your app or website, you can care care about that there where it belongs.

I also want to see the count of zero [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I also want to show the count of zero in this sql.
SELECT diaries.id, emotion_id, image_url, color, summary, public, is_completed, diaries.created_at, diaries.is_deleted, likes.is_deleted, users.nickname, likes.diary_id, COUNT(likes.user_id) AS cnt FROM diaries
INNER JOIN emotions ON diaries.emotion_id = emotions.id
INNER JOIN users ON diaries.user_id = users.id
LEFT OUTER JOIN likes ON diaries.id = likes.diary_id
WHERE diaries.is_deleted = 0 AND public = 1 AND is_completed = 1 AND likes.is_deleted = 0
GROUP BY diary_id
ORDER BY cnt DESC
I also want to see the count of zero.....
The where clause cannot include any fields from the table that you use LEFT JOIN on. This causes the LEFT JOIN to convert into an INNER JOIN.
You need to move this clause into the LEFT JOIN statement:
AND likes.is_deleted = 0
This will then return a COUNT(likes = 0)

How to add two tables having sum of amounts on the basis of year in SQL(toad)? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
First Table :
SELECT A.BU,A.PROJECT,SUM(A.BUDGET_AMOUNT),SUBSTR(A.BUDGET_PERIOD,3,2)
FROM BUDGET_SUMMARY A
GROUP BY A.BU,A.PROJECT,SUBSTR(A.BUDGET_PERIOD,3,2)
And the second table:
SELECT B.BU,A.PROJECT,SUM(B.ACTUAL_AMOUNT),SUBSTR(B.ACTUAL_PERIOD,3,2)
FROM ACTUAL_SUMMARY B
GROUP BY B.BU,B.PROJECT,SUBSTR(B.ACTUAL_PERIOD,3,2)
Now,I want to join the both above mentioned table into one table in the form of
BU|PROJECT|SUM(BUDGET_AMOUNT)|SUBSTR(A.BUDGET_PERIOD,3,2)|SUM(B.ACTUAL_AMOUNT)|SUBSTR(B.ACTUAL_PERIOD,3,2)
SELECT A.BU,A.PROJECT, SUM(A.BUDGET_AMOUNT), SUBSTR(A.BUDGET_PERIOD,3,2), SUM(B.ACTUAL_AMOUNT)
FROM BUDGET_SUMMARY A
GROUP BY A.BU,A.PROJECT,SUBSTR(A.BUDGET_PERIOD,3,2)
Or of the two table are not for the same value you can use JOIN (inner join for amtching values)
SELECT A.BU,A.PROJECT,SUM(A.BUDGET_AMOUNT),SUBSTR(A.BUDGET_PERIOD,3,2), T.SUM_BUDGET_AMOUNT, T.SUB_ACTUAL_PERIOD
FROM BUDGET_SUMMARY A
INNER JOIN (
SELECT B.BU,A.PROJECT,SUM(B.ACTUAL_AMOUNT) sum_BUDGET_AMOUNT,SUBSTR(B.ACTUAL_PERIOD,3,2) SUB_ACTUAL_PERIOD
FROM ACTUAL_SUMMARY B
GROUP BY B.BU,B.PROJECT,SUBSTR(B.ACTUAL_PERIOD,3,2)
) T ON T.BU = A.BY
AND T.PROJECT = A.PROJECT,SUBSTR(A.BUDGET_PERIOD,3,2)
AND T.SUB_ACTUAL_PERIOD = ,SUBSTR(A.BUDGET_PERIOD,3,2)
GROUP BY A.BU,A.PROJECT,SUBSTR(A.BUDGET_PERIOD,3,2)
left join if you have aprtila match
SELECT A.BU,A.PROJECT,SUM(A.BUDGET_AMOUNT),SUBSTR(A.BUDGET_PERIOD,3,2), T.SUM_BUDGET_AMOUNT, T.SUB_ACTUAL_PERIOD
FROM BUDGET_SUMMARY A
LEFT JOIN (
SELECT B.BU,A.PROJECT,SUM(B.ACTUAL_AMOUNT) sum_BUDGET_AMOUNT,SUBSTR(B.ACTUAL_PERIOD,3,2) SUB_ACTUAL_PERIOD
FROM ACTUAL_SUMMARY B
GROUP BY B.BU,B.PROJECT,SUBSTR(B.ACTUAL_PERIOD,3,2)
) T ON T.BU = A.BY
AND T.PROJECT = A.PROJECT,SUBSTR(A.BUDGET_PERIOD,3,2)
AND T.SUB_ACTUAL_PERIOD = ,SUBSTR(A.BUDGET_PERIOD,3,2)
GROUP BY A.BU,A.PROJECT,SUBSTR(A.BUDGET_PERIOD,3,2)
just guessing, your description is hard to read and not executable. named-sub-queries should help to get your desired result (assuming "project" can be used as join-column)
with budget as
(
SELECT A.BU,A.PROJECT,SUM(A.BUDGET_AMOUNT) sum_amount,SUBSTR(A.BUDGET_PERIOD,3,2) m_period FROM BUDGET_SUMMARY A GROUP BY A.BU,A.PROJECT,SUBSTR(A.BUDGET_PERIOD,3,2)
), actual as
(
SELECT B.BU,B.PROJECT,SUM(B.ACTUAL_AMOUNT) sum_amount,SUBSTR(B.ACTUAL_PERIOD,3,2) m_period FROM ACTUAL_SUMMARY B GROUP BY B.BU,B.PROJECT,SUBSTR(B.ACTUAL_PERIOD,3,2)
)
select budget.BU,budget.PROJECT,budget.sum_amount,budget.m_period,actual.sum_amount,actual.m_period
from budget
join actual on budget.project=actual.project
(possibly a left-join is needed)

SQL QUERY: Want to query how many viewers per movie_type; (where comedy = comedy & dramatic comedy) [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
made up table
Basically I want to group by the movie_type, but I want comedy & dramatic comedy to just be counted as one category = Comedy.
You can use case expression then do aggregation in the outer query
select
movie_type,
count(*) as total_viewer
from
(
select
case
when movie_type = 'dramatic comedy' or movie_type = 'comedy' then 'comedy'
else movie_type
end as movie_type,
viewer_id
from yourTable
) subq
group by
movie_type
You can replace dramatic with null and fetch the results. Below is the query,
select ltrim(rtrim(replace(movie_type, 'dramatic ', ''))) as movie_type , count(1) from
table
group by ltrim(rtrim(replace(movie_type, 'dramatic ', '')));

Better way to re-write this query? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 3 years ago.
Improve this question
I have two tables, TableA and TableBNew. Here is the link for the image that shows the table and its content:
One of the optimization rules is:
- try to reduce the amount of manipulated data as much as you can.
This is a bit more efficient but it's not shorter.
The difference here is that I do the join only on the years I need (a.k.a: filter then join), instead of joining everything and filtering later.
SELECT AB.PART_TYPE, BC.AVG_2012_PRICE
FROM (SELECT TableA.partName AS PART_TYPE, AVG(TableBNew.price) AS AVG_price_2011
FROM TableA
INNER JOIN (SELECT * FROM TableBNew WHERE TableBNew.year=2011)
ON TableA.partID = TableBNew.partID
GROUP BY TableA.partName
HAVING AVG(TableBNew.price) < 1000) AB
INNER JOIN
(SELECT TableA.partName AS PART_TYPE, AVG(TableBNew.price) AS AVG_price_2012 FROM TableA INNER JOIN (SELECT * FROM TableBNew WHERE TableBNEw.year=2012) ON
TableA.partID = TableBNew.partID
GROUP BY TableA.partName) BC
ON AB.PART_TYPE=BC.PART_TYPE
Your query seems way over complicated. You can simplify it using conditional aggregation:
SELECT b.PartName,
AVG(CASE WHEN n.year = 2012 THEN n.price END) AS AVG_price_2012
FROM TableA a JOIN
TableBNew n
ON a.PartID = n.PartId
WHERE n.year IN (2011, 2012)
GROUP BY a.partName
HAVING AVG(CASE WHEN n.year = 2011 THEN n.price END) < 1000;
I am not sure why you are renaming PartName to PartType. That doesn't seem useful.