How to get total appointment durations from this table using sql - mysql

I have 3 mysql tables:
appointments
id slot_id patient_name doctor_id deleted_at
1 11 Tasin 23 2019-10-10
2 12 Nawaz 22 null
3 13 Rakib 23 null
4 14 Hossen 23 null
5 15 Aritra 24 null
6 16 Anik 22 null
7 17 Manik 22 null
doctors
id status doctor_name
22 1 Khaled
23 1 Hasan
24 0 Rumi
slots
id date duration time
11 2019-10-10 2900 01:01
12 2019-10-11 1200 02:01
13 2019-10-18 1100 03:01
14 2019-09-08 200 11:01
15 2019-08-01 500 01:31
16 2019-10-07 300 02:31
17 2019-10-02 1200 03:31
Now, I want to show a list of doctors with their total appointment durations in decreasing order using SQL query.
Unfortunately, I don't have any idea about this SQL query. Can you assist me?

SELECT DOCTOR_NAME, SUM(DURATION) FROM APPOINTMENTS A
JOIN DOCTORS D ON D.ID = A.DOCTOR_ID
JOIN SLOTS S ON S.ID = A.SLOT_ID
GROUP BY D.ID, DOCTOR_NAME
ORDER BY SUM(DURATION) DESC;

select d.doctor_id, d.doctor_name, sum(apt.duration) as total_duration from
doctors as d
join appointments as apt on apt.doctor_id = d.doctor_id
join slots as s on s.id = apt.slot_id
group by d.doctor_id, d.doctor_name
The above query should work fine.
There might be some typo as I didn't write it in the SQL management studio.

Related

GROUP BY with MAX(date), but the date is in two separate columns

I'm trying to get the list of IDs of all the rows with latest posting date for each author in a table, for example:
id author_id date
1 12 2020-12-23
2 12 2021-01-06
3 12 2021-04-12
4 12 2021-02-10
5 17 2021-09-16
6 17 2021-05-20
7 17 2021-02-23
8 17 2021-07-02
9 24 2021-03-24
10 24 2021-02-10
11 24 2020-08-18
12 24 2020-12-14
The desired result should be:
id
3
5
9
I used this query and it works perfect:
SELECT a.id
FROM (
SELECT author_id, MAX(`date`) as MaxDate
FROM `posts_log`
GROUP BY author_id
) b
INNER JOIN `posts_log` a
ON a.author_id = b.author_id AND a.date = b.MaxDate
But let's imagine that situation changed. Now author is allowed to post only once per month. So the table changed too and 'date' column became separated:
id author_id month year
1 12 12 2020
2 12 1 2021
3 12 4 2021
4 12 2 2021
5 17 9 2021
6 17 5 2021
7 17 2 2021
8 17 7 2021
9 24 3 2021
10 24 2 2021
11 24 8 2020
12 24 12 2020
Yeah, I know, looks a little bit stupid, but this wasn't my decision. Now I have such table and I'm not allowed to change the structure.
The question is: How to get the same result with this new table. Is it possible in MySQL?
You can use similar logic. Just instead of the date, use a calculated value from year and month:
SELECT a.id
FROM (
SELECT p.author_id, MAX(p.year*100+p.month) as MaxMonth
FROM posts_log p
GROUP BY p.author_id
) b
INNER JOIN posts_log a
ON a.author_id = b.author_id AND a.year*100+a.month = b.MaxMonth;

Getting result for latest row(based on timestamp column) for each user and each day

I have a table called play_progress.
play_progress
id user_id coins timecreated
1 1 20 2016-01-23 06:55:09
2 1 24 2016-01-23 06:59:22
3 1 28 2016-01-23 07:05:34
4 2 4 2016-01-23 07:10:58
5 2 10 2016-01-23 07:12:08
6 1 32 2016-01-24 00:07:48
7 2 14 2016-01-24 00:12:08
8 1 35 2016-01-24 00:44:48
9 2 18 2016-01-24 00:55:08
I like to get the latest row( based on timecreated) for each day for each user.
I have tried the following query;
SELECT user_id, coins, MAX(timecreated)
FROM player_progress
GROUP BY user_id, DATE(timecreated);
It gives the result for each day but it gives wrong timecreatd value.
Where I am going wrong?
Result details like
id user_id coins timecreated
1 1 28 2016-01-23 07:05:34
5 2 10 2016-01-23 07:12:08
8 1 35 2016-01-24 00:44:48
9 2 18 2016-01-24 00:55:08
I have searched through SO, but couldn't find a solution to my problem.
If you need to fetch more columns then the ones used for grouping (user_id and timecreatd) you need a more complex query:
SELECT p.user_id, p.id, coins, p.timecreated
FROM play_progress p INNER JOIN
(SELECT user_id, MAX(timecreated) as max_time
FROM play_progress
GROUP BY user_id, DATE(timecreated)) pp
ON p.user_id = pp.user_id
AND p.timecreated = pp.max_time;
Here you have a sample

count occurence of rows with specific status without using subquery

Here is my table
loan_id bid_id lender_id borrower_id amount interest duration loan_status
1 1 60 63 300.00 12.00 3 'completed'
2 2 61 63 300.00 12.00 3 'completed'
3 3 62 63 300.00 12.00 3 'pending',
4 1 62 63 300.00 12.00 3 'pending'
7 4 60 63 300.00 12.00 3 'completed'
I want to pull only those bid_id whose loan_status of all records is completed. It means if there is any record of bid_id with status pending then it will not pull that record.
I am using the followin query that is working fine:
SELECT bid_id
FROM loan
WHERE bid_id NOT IN (
SELECT l.bid_id
FROM loan l
WHERE l.`loan_status` = 'pending'
AND l.bid_id = bid_id
GROUP BY l.`bid_id`
HAVING COUNT(l.`bid_id`)>= 1
)
GROUP BY bid_id
Is there any other way in which we can get desired result without using sub query.
You can readily do this with group by and having:
select bid_id
from loan
group by bid_id
having sum(loand_status = 'pending') = 0

Count two tables in MySQL, and display results based on the dates from another table

I want to count the number of records in two tables, and group them together based on the dates from one of the counted tables.
At the moment, I have this query:
SELECT COUNT(DISTINCT efu.id) AS TotalCollections, COUNT(DISTINCT ccs.id) AS TotalCases, efu.completion_date
FROM enviro_figures_upload efu
LEFT JOIN customer_cases_upload ccs ON ccs.customer_site = efu.customer_site
WHERE efu.customer_site = "TGI Friday's Glasgow"
GROUP BY DATE_FORMAT(efu.completion_date, '%m-%Y') DESC
ORDER BY YEAR(efu.completion_date) ASC, MONTH(efu.completion_date) ASC
Which outputs the following results:
TotalCollections TotalCases completion_date
52 8 2014-05-21
73 8 2014-06-23
83 8 2014-07-02
89 8 2014-08-22
87 8 2014-09-21
68 8 2014-10-06
85 8 2014-11-20
59 8 2014-12-10
17 8 2015-01-05
However, the TotalCases column isn't being counted properly. There are 8 records altogether in that table, but in the query the number of cases should be counted based on the date (also called completion_date). There will be cases that TotalCases will return 0, but should be included against the TotalCollections and completion_date.
So really it should be:
TotalCollections TotalCases completion_date
52 2 2014-05-21
73 1 2014-06-23
83 1 2014-07-02
89 0 2014-08-22
87 0 2014-09-21
68 1 2014-10-06
85 0 2014-11-20
59 2 2014-12-10
17 1 2015-01-05
How can I do this?
EDIT
Here is some sample data from the enviro_figures_upload table:
id completion_date
124114 2014-09-30
124134 2014-10-31
124146 2014-05-23
124148 2014-05-24
124149 2014-05-26
124150 2014-05-27
124151 2014-05-28
124152 2014-05-25
124153 2014-05-29
124193 2014-05-31
124194 2014-05-24
124195 2014-05-26
124196 2014-05-27
124197 2014-05-28
Here is some sample data from the customer_cases_upload:
id completion_date
2519 2014-10-17
2520 2014-12-15
2521 2014-07-28
2522 2014-12-12
2523 2014-09-27
2524 2014-11-03
2525 2014-05-30
2526 2014-05-22
TotalCases is showing 8 because there is no constraint on customer_cases_upload.completion_date.
Try:
SELECT COUNT(DISTINCT efu.id) AS TotalCollections, COUNT(DISTINCT ccs.id) AS TotalCases, efu.completion_date
FROM enviro_figures_upload efu
LEFT JOIN customer_cases_upload ccs ON ccs.customer_site = efu.customer_site
and year(efu.completion_date) = year(css.completion_date)
and month(efu.completion_date) = month(css.completion_date)
WHERE efu.customer_site = "TGI Friday's Glasgow"
GROUP BY DATE_FORMAT(efu.completion_date, '%m-%Y')
ORDER BY YEAR(efu.completion_date) ASC, MONTH(efu.completion_date) ASC
I'm not quite sure what the customer_site column is, as the column is not included in your sample data, but I think your LEFT JOIN needs to be more specific. It looks like there are 8 total records in the customer_cases_upload table for the customer_site referenced in your WHERE clause. The LEFT JOIN is joining all 8 records to each row of the enviro_figures_upload table, regardless of the completion_date. Does the customer_cases_upload completion_date match the corresponding enviro_figures_upload completion_date? If so, include this in your LEFT JOIN's ON clause to only join the customer_cases_upload rows to enviro_figures_upload rows with the same completion_date.

Get intersection of 2 tables in MySQL

Id MedId ShipId AvailableQuant DefaultQuant MinQuant MedExpiry LastUsed
------ ------ ------ -------------- ------------ -------- ------------------- ---------------------
1 1 2918 20 30 15 2015-02-05 11:37:24 2014-12-01 11:37:32
4 2 2918 50 55 30 2015-03-26 11:57:14 2014-12-03 11:57:22
5 3 2918 15 40 20 2014-12-10 16:58:58 2014-12-10 16:59:02
6 4 2918 30 75 30 2015-03-31 11:58:26 2014-12-03 11:58:32
7 5 2918 22 50 20 2015-01-01 11:59:05 2014-12-03 11:59:09
9 6 3095 5 35 10 2014-12-03 11:59:51 2014-09-01 11:59:55
10 7 2918 30 60 35 2014-12-01 12:00:43 2014-10-22 12:00:57
11 8 3095 25 30 20 2014-12-31 17:48:58 2014-12-01 17:49:12
And there are 2 queries that i have written
1)To give me count of critical Items
SELECT SUM(IF(m.AvailableQuant <= m.MinQuant,1, 0)) AS criticalFROM tbl_vesselmaster vs
INNER JOIN comp_login cl ON vs.co_id = cl.id
INNER JOIN m_shipinv m ON vs.id = m.ShipId
WHERE vs.co_id=$co_id;
2)To give me medicine that have excedeed expiry date
SELECT COUNT(MedId) as count FROM `m_shipinv` WHERE DATE(MedExpiry) < DATE(NOW());
i want a query to get the count intersection of this both query. means if the item is critical and its medicine is expired then it should count only 1
this should be the output
count
-------
4
I think you can just add the where clause to the first query:
SELECT SUM(m.AvailableQuant <= m.MinQuant) AS critical
FROM tbl_vesselmaster vs INNER JOIN
comp_login cl
ON vs.co_id = cl.id INNER JOIN
m_shipinv m
ON vs.id = m.ShipId
WHERE vs.co_id = $co_id OR DATE(MedExpiry) < DATE(NOW());
Note that I simplified the SUM() calculation. The if is not needed because MySQL treats booleans as integers in a numeric context.
Can't you just put the two conditions in the where clause ?
I don't understand all you inner joins as you only describe one table. I just altered the select of Gordon Linoff:
SELECT count(*) AS critical
FROM tbl_vesselmaster vs
INNER JOIN comp_login cl ON vs.co_id = cl.id
INNER JOIN m_shipinv m ON vs.id = m.ShipId
WHERE vs.co_id = $co_id
AND DATE(MedExpiry) < DATE(NOW())
AND m.availableQuant <= m.minQuant;
I think the result should be 3: only records 5, 9 and 10 meet both criteria.