SQL query in mariadb - sql

I have a task to write a SQL query to find which hospital has the most doctors and for that hospital to show all the patients and dates of their checkup.
Relations that are involved in my db are next:
Hospital (HospitalID, Name_of_the_Hospital, Place, Phone number)
Scheduling_Checkups (Hospital, Doctor, Patient, Date_of_the_checkup)
Patient (PatientID, Name, Addres, Phone_number)
Doctor (DoctorID, Name, Speciality)
I tried this:
SELECT
hospital.Name,COUNT( Scheduling_Checkups.Doctor) AS 'number'
FROM
hospital
JOIN
Scheduling_Checkups ON hospital.HospitalID = Scheduling_Checkups.Hospital
GROUP BY
Hospital.Name, Scheduling_Checkups.Doctor
ORDER BY
number DESC
But this returns only total number of the doctors that appeared in table
Scheduling_Checkups, and if someone appeared twice, it will return incorrect numbers, for example if it said 9 and I had one doctor who appeared twice in the same hospital, then it would be a wrong answer, correct answer would be 8.
Can anyone give me a point and direction how to answer this.
And the query that I tried only tries to find first part.is at all possible to find the hospital with highest number of doctors employeed and in the same query to show patients and dates of their checkups for that same hospital

Your query result with limit 1 could be the where value for set the hopital you need and the join scheduling and patient
select Patient.*, Scheduling_Checkups.*
from Scheduling_Checkups
INNER JOIN Patient on Scheduling_Checkups.Patient = Patient.PatientID
where Scheduling_Checkups.Hospital = (
SELECT hospital.HospitalID
FROM hospital
join Scheduling_Checkups ON hospital.HospitalID= Scheduling_Checkups.Hospital
GROUP BY Hospital.HospitalID, Scheduling_Checkups.Doctor
ORDER BY COUNT( Scheduling_Checkups.Doctor) DESC LIMIT 1
)

Related

How to find number of entries grouped by something and retrieve only those above average?

I have two tables: Profile and Record. In Profile, I have student names and other information, whereas, in Record, I have rows with curriculum information. In the Record table, a single student can have many rows. I need to calculate the number of rows grouped by student_name, but only retrieve those student names with more rows than the average (number of rows/total number of students). I can find the number of rows grouped by student_name, but I can't write a subquery to display only those above average. Could someone please explain a method to me?
This is what I have for now:
SELECT student_name, COUNT(*)
FROM Profile p
JOIN Record r
ON p._id = r._id
GROUP BY student_name
The desired output is only to retrieve students_name with the above avg no. of rows in the Records table:
student_name
No. of Records
Ali
556
John
244
Indeed you can use sub-query to get your desired output.
Code:
SELECT student, COUNT(*) AS no_of_records
FROM record
GROUP BY student
HAVING no_of_records > (SELECT COUNT(*)/COUNT(DISTINCT student) FROM record);
Explanation:
The sub-query here will return average row count from record table
In the outer-query, we are calculating number of rows for each student and comparing it with sub-query's result
Note: You can join it with profile table in outer query if needed.
Look at the fiddle to understand it better

SQL : Getting count of a column and then multiplying it with a column from another table

I have three tables in my database,
Students-has student id,
Instructors which has instructor id, course name and hourly pay.
Enrollment table which has student id, course name, instructor.
I need to write a query to get the max amount of money paid to an instructor. Somethings to consider
A student can enroll into multiple courses
An instructor can teach multiple courses (Instructor is paid the same for each course)
Multiple instructors can teach the same course.
I came up with the required tables to get the entries first.
select hourlyPay, ins_id, stu_id from Instructors, Enrollment where Enrollment.ins_id = Instructors.Instr_id group by hourlyPay,ins_ID,stu_id
This gives me the output:
My end goal is to multiply the hourly pay with the student count and get the maximum, Could somebody please help me do it? I want the student count per instructor multiplied with the hourly pay.
Since I don't know the data and complete requirement. You can try something below:
(This top 1 works in SQL Server). I think in Orcle you need try FETCH FIRST number ROWS ONLY;)
select top 1 ins_id,sum(hourlyPay) Pay
from(
select hourlyPay
, ins_id
, stu_id
from Instructors
Join Enrollment ON Enrollment.ins_id = Instructors.Instr_id
group by hourlyPay,ins_ID,stu_id
) a
group by ins_id
order by 2 desc

Microsoft SQL server select statements on multiple tables?

so I've been struggling with some of the select statements on multiple tables:
Employee table
Employee_ID
First_Name
Last_Name
Assignment table
Assignment_ID
Employee_ID
Host_Country_arrival_Date
Host_Country_departure_Date
Scheduled_End_Date
I'm being asked to display query to display employee full name, number of days between the host country arrival date and host country departure date, number of days between today's date and the assignment scheduled end date and the results sorted according to host country arrival date with the oldest date on top.
also, I'm not familiar with the sort function in SQL server..
Here's my query and I've been getting syntax errors:
SELECT
First_Name
Last_Name
FROM Employee
SELECT
Host_Country_Arrival_Date
Host_Country_Departure_Date
FROM Assignment;
So, Basically what your code is doing is 2 different queries. The first getting all the employees names, and the second one getting the dates of the assignments.
What you'll want to do here is take advantage of the relationship between the tables using a JOIN. That is basically saying "Give me all employees and all of HIS/HERS assignments". So, for each assignment that the employee has, it will bring a row in the result with his name and the assignment info.
To get the difference between days you use DATEDIFF passing 3 parameters, the timespan in which to calculate the difference, the first and the second date. It will then Subtract the first one from the second one and give you the result in the selected timespan.
And finnaly the sorting: Just add 'ORDER BY' followed by each column that you want to use for ordering and then specify if you want it ascending (ASC) or descending (DESC).
You can check how I would answer the if that question was proposed to me in a coding challenge.
SELECT
CONCAT(E.First_Name,' ', E.Last_Name) FullName,
DATEDIFF(DAY,Scheduled_End_Date,getdate()) DaysTillScheduledDate,
DATEDIFF(DAY,Host_Country_Arrival_Date,Host_Country_Departure_Date) DaysTillScheduledDate
FROM Employee As E --Is nice to add aliases
Inner Join
Assignment As A
on E.Employee_ID = A.Employee_ID -- Read a little bit about joins, there are a lot of material availabel an its going to be really necessary moving forward with SQL
order by Host_Country_Arrival_Date DESC -- Just put the field that you want to order by here, desc indicates that it should be descending
You should use a JOIN to link the tables together on Employee_ID:
SELECT
First_Name,
Last_Name,
Host_Country_Arrival_Date,
Host_Country_Departure_Date
FROM Employee
JOIN Assignment ON Assignment.Employee_ID = Employee.Employee_ID;
What this is saying basically is that for each employee, go out to the assignments table and add the assignments for that employee. If there are multiple assignments, the employee columns will be repeated on each row with the assignment columns for the assignment.
You need to look for the join and group by. Please find this link for reference tutorial
For now you may try this...
SELECT
CONCAT(Emp.First_Name,' ', Emp.Last_Name) FullName,
DATEDIFF(DAY,Scheduled_End_Date,getdate()) DaysTillScheduledDate,
DATEDIFF(DAY,Host_Country_Arrival_Date,Host_Country_Departure_Date) DaysTillScheduledDate
FROM Employee As Emp Inner Join Assignment As Assign on Emp.Employee_ID = Assign.Employee_ID
order by Host_Country_Arrival_Date DESC

SQL query number of students per school

I have a table of students and schools. How do I select the total students per school?
I'm sure this is a very simple query, however I'm not sure how to proceed on from this:
SELECT tblSchools.name
FROM tblStudentDetails
INNER JOIN tblSchools
ON tblStudentDetails.schoolId = tblSchools.id
Group by the school and use count() to count the students
SELECT s.name, count(d.id) as students_count
FROM tblSchools s
INNER JOIN tblStudentDetails d ON d.schoolId = s.id
GROUP BY s.name
I want to add on to the accepted answer as well. Working for a school district and continuously having to pull counts of students there are a few additional things to keep in mind. What students are you looking for?
Do you want active students, inactive students, or active and inactive students.
Do you want to include students that have been no showed (were going to come to your school, but ended up not coming for even a day, this is recorded in most student information systems.
Is the student attending multiple schools, in which case you want to exclude them from counting in their second or third school.
I've built the script with the idea of a normalized school district database, where things are broken out by school year, and enrollment.
Often a basic script for me looks a little like this.
SELECT s.SCHOOL_NAME, COUNT(stu.STUDENT_GU) AS STUDENT_COUNT
FROM STUDENT stu
JOIN STUDENT_YEAR sy ON sy.STUDENT_ID = stu.STUDENT_ID
JOIN SCHOOL_YEAR scy ON scy.SCHOOL_YEAR_ID = sy.SCHOOL_YEAR_ID
JOIN SCHOOL s ON s.SCHOOL_ID = scy.SCHOOL_ID
JOIN YEAR y ON y.YEAR_ID = sy.YEAR_ID
WHERE y.SCHOOL_YEAR = 2017
AND (sy.CONCURRENT IS NULL OR sy.CONCURRENT OR != 'Not Concurrent')
AND sy.ENTER_DATE IS NOT NULL
AND sy.STATUS IS NULL
GROUP BY s.SCHOOL_NAME
Because each school year is a new year, students, and schools usually have a table for the basic data that doesn't change. But also tables that are school year specific. In my example STUDENT_YEAR and SCHOOL_YEAR is where we get into the specifics regarding which kids we are actually getting, and where they currently are. I utilize the YEAR table to identify which school year I want to look at.
The STUDENT_YEAR table is where we store the students concurrency flag, enter date, and so within that table I can use in the WHERE clause a way to filter out Inactive Students, Concurrent Students, and ensure each student is counted only once.
If those year values aren't included, at least in my database, I would get all students ever enrolled for every year we've got stored.

Compute Users average weight

I have two tables, Users and DoctorVisit
User
- UserID
- Name
DoctorsVisit
- UserID
- Weight
- Date
The doctorVisit table contains all the visits a particular user did to the doctor.
The user's weight is recorded per visit.
Query: Sum up all the Users weight, using the last doctor's visit's numbers. (then divide by number of users to get the average weight)
Note: some users may have not visited the doctor at all, while others may have visited many times.
I need the average weight of all users, but using the latest weight.
Update
I want the average weight across all users.
If I understand your question correctly, you should be able to get the average weight of all users based on their last visit from the following SQL statement. We use a subquery to get the last visit as a filter.
SELECT avg(uv.weight) FROM (SELECT weight FROM uservisit uv INNER JOIN
(SELECT userid, MAX(dateVisited) DateVisited FROM uservisit GROUP BY userid) us
ON us.UserID = uv.UserId and us.DateVisited = uv.DateVisited
I should point out that this does assume that there is a unique UserID that can be used to determine uniqueness. Also, if the DateVisited doesn't include a time but just a date, one patient who visits twice on the same day could skew the data.
This should get you the average weight per user if they have visited:
select user.name, temp.AvgWeight
from user left outer join (select userid, avg(weight)
from doctorsvisit
group by userid) temp
on user.userid = temp.userid
Write a query to select the most recent weight for each user (QueryA), and use that query as an inner select of a query to select the average (QueryB), e.g.,
SELECT AVG(weight) FROM (QueryA)
I think there's a mistake in your specs.
If you divide by all the users, your average will be too low. Each user that has no doctor visits will tend to drag the average towards zero. I don't believe that's what you want.
I'm too lazy to come up with an actual query, but it's going to be one of these things where you use a self join between the base table and a query with a group by that pulls out all the relevant Id, Visit Date pairs from the base table. The only thing you need the User table for is the Name.
We had a sample of the same problem in here a couple of weeks ago, I think. By the "same problem", I mean the problem where we want an attribute of the representative of a group, but where the attribute we want isn't included in the group by clause.
I think this will work, though I could be wrong:
Use an inner select to make sure you have the most recent visit, then use AVG. Your User table in this example is superfluous: since you have no weight data there and you don't care about user names, it doesn't do you any good to examine it.
SELECT AVG(dv.Weight)
FROM DoctorsVisit dv
WHERE dv.Date = (
SELECT MAX(Date)
FROM DoctorsVisit innerdv
WHERE innerdv.UserID = dv.UserID
)
If you're using SQL Server 2005 you don't need the sub query on the GROUP BY.
You can use the new ROW_NUMBER and PARTION BY functionality.
SELECT AVG(a.weight) FROM
(select
ROW_NUMBER() OVER(PARTITION BY dv.UserId ORDER BY Date desc) as ID,
dv.weight
from
DoctorsVisit dv) a
WHERE a.Id = 1
As someone else has mentioned though, this is the average weight across all the users who have VISITED the doctor. If you want the average weight across ALL of the users then anyone not visiting the doctor will give a misleading average.
Here's my stab at the solution:
select
avg(a.Weight) as AverageWeight
from
DoctorsVisit as a
innner join
(select
UserID,
max (Date) as LatestDate
from
DoctorsVisit
group by
UserID) as b
on a.UserID = b.UserID and a.Date = b.LatestDate;
Note that the User table isn't used at all.
This average omits entirely users who have no doctors visits at all, or whose weight is recorded as NULL in their latest doctors visit. This average is skewed if any users have more than one visit on the same date, and if the latest date is one of those date where the user got wighed more than once.