what will be the sql query code of this "Healthcare" database? - mysql

SQL Query:
Write a SQL statement to display the SSN & name of patients who are younger than the average of all patients.
Write a SQL statement to display the name and age of the oldest patients along with his or her doctor's name.
write a SQL statement to display all of the patients who are prescribed with vitamins and below 50 years old.
display the name of most experienced heart specialist.
Solution: I have completed these answers of those questions but not sure it's okay or not. Please help me if there is any wrong or need any correction.
1.)
select SSN, Name
from patient
where age < (
select avg(age)
from Patient
);
2.)
select patient.name, max(patient.age), patient.DName
from Patient
join Doctor
where patient.primary_DoctorID = Doctor.DoctorID;
3.)
SELECT Patient.Name, Patient.age
from Patient
where patient.age < '50' and Patient.Primary_DoctorID = (
SELECT Prescription.DoctorID
from Prescription
where Prescription.P_ID = (
select Prescription_Medicine.P_ID
FROM Prescription_Medicine
where Prescription_Medicine.Tradename = 'Vitamin' )
);
Q3 returns
subquery returns more than one row
SELECT dname
FROM doctor
IN speciality = 'Heart' AND experience = (
SELECT MAX(doctor.experience)
FROM doctor
GROUP BY speciality;
);

Update your 3rd query to -
SELECT Patient.Name, Patient.age
from Patient
where patient.age < '50'
and EXISTS (
SELECT Prescription.DoctorID
from Prescription
where Patient.Primary_DoctorID = Prescription.DoctorID
and Prescription.P_ID = (
select Prescription_Medicine.P_ID
FROM Prescription_Medicine
where Prescription_Medicine.Tradename = 'Vitamin' )
);
And update your 4th query to -
SELECT dname
FROM doctor d
JOIN (SELECT speciality, MAX(doctor.experience)
FROM doctor
GROUP BY speciality) d1 on d.speciality = d1.speciality
WHERE speciality = 'Heart'

--USING MS-SQL SERVER FOR THE 4TH QUERY
--YOU CAN ALSO USE WINDOW FUNCTION TO SOLVE THE FOURTH
--QUERY.
--USING CTE (COMMON TABLE EXPRESSION)
WITH CTE
AS
(
SELECT
D.DNAME,
DENSE_RANK() OVER (PARTITION BY D.DNAME ORDER BY
D.EXPERIENCE DESC) AS RNK
FROM DOCTOR
WHERE SPECIALITY = 'HEART'
)
SELECT DNAME FROM CTE
WHERE RNK = 1

Related

SUM(DISTINCT) on the same table?

I currently have table as below:
By executing the code as:
SELECT FromLedger, SUM(TransactionVal)
FROM Journal
WHERE FromGroup = 'Asset'
GROUP BY FromLedger
I get the result as:
Simlarly, I get the another set by executing:
SELECT ToLedger, SUM(TransactionVal)
FROM Journal
WHERE ToGroup = 'Asset'
GROUP BY ToLedger
I want to get a single table combining the both table with Group By Ledger Id and another column as the difference between the SUM of the above 2 table. In other words, I am looking for table as below
How do I get it please?
You can join the 2 queries like this:
SELECT t.ToLedger UniqueLedgerId, t.total - f.total ClosingBalance
FROM (SELECT ToLedger, SUM(TransactionVal) total FROM Journal WHERE ToGroup = 'Asset' GROUP BY ToLedger) t
INNER JOIN (SELECT FromLedger, SUM(TransactionVal) total FROM Journal WHERE FromGroup = 'Asset' GROUP BY FromLedger) f
ON f.FromLedger = t.ToLedger
or use UNION ALL and then aggregate:
SELECT t.UniqueLedgerId, SUM(t.TransactionVal) ClosingBalance
FROM (
SELECT ToLedger UniqueLedgerId, TransactionVal FROM Journal WHERE ToGroup = 'Asset'
UNION ALL
SELECT FromLedger, -TransactionVal FROM Journal WHERE FromGroup = 'Asset'
) t
GROUP BY t.UniqueLedgerId

joint three tables in Mysql

I have three tables employee, promotion and punishment
Employee’s table structure something like this
Id int
Fullname varchar
...............
promotionDate date
Promotion’s table structure is like this
id int
emp_id int
directorateDate date
And punishment’s table structure is like this
id int
emp_id int
direcotorateDate date
Let’s say employee table has 200 records, each month a group of employees have promotion (after serving one year), I want to get the list of all employees in the current month that get promotion
I can easily get the list by this query
SELECT *
FROM employee
WHERE MONTH(promotionDate) = MONTH(CURRENT_DATE())
AND YEAR(promotionDate) = YEAR(CURRENT_DATE())
My question is
I want to count number of punishments and promotions each employee got in the current year from punishment and promotion table respectively
I did this query but it did not get right results
SELECT e.fullname , COUNT(punish.emp_id) as siza ,COUNT(pro.emp_id) as supas
FROM emp_employee as e
LEFT JOIN emp_punishment as punish on punish.emp_id=e.id
LEFT JOIN emp_promotion as pro on e.id=pro.emp_id
WHERE ((MONTH(e.promotionDate) = MONTH(CURRENT_DATE())
AND YEAR(e.promotionDate) = YEAR(CURRENT_DATE()))
AND ( YEAR(punish.directorate_date) = YEAR(CURRENT_DATE()) )
AND ( YEAR(pro.directorate_date) = YEAR(CURRENT_DATE()) )
GROUP BY e.fullname;
Any help please.
By joining directly the 3 tables you get duplicate rows.
Group by emp_id and aggregate separately each of the tables emp_punishment and emp_promotion and join the results to the table emp_employee.
select e.fullname, coalesce(pu.siza, 0) siza, coalesce(pr.supas, 0) supas
from emp_employee as e
left join (
select emp_id, count(*) siza
from emp_punishment
where year(directorate_date) = year(CURRENT_DATE)
group by emp_id
) pu on pu.emp_id = e.id
left join (
select emp_id, count(*) supas
from emp_promotion
where year(directorate_date) = year(CURRENT_DATE)
group by emp_id
) pr on pr.emp_id = e.id
I used only the condition:
where year(directorate_date) = year(CURRENT_DATE())
because in your question you say:
I want to count number of punishments and promotions each employee got in the current year from punishment and promotion
Removing MONTH() function, and moving each condition to their respective place, instead of within the WHERE clause should resolve the issue (Since, they're considered as if INNER JOINs with the current style ).
Only keep common column e.promotionDate within the WHERE clause :
SELECT e.fullname,
COUNT(punish.emp_id) as siza ,
COUNT(pro.emp_id) as supas
FROM emp_employee as e
LEFT JOIN emp_punishment as punish
ON punish.emp_id=e.id
AND YEAR(punish.directorate_date) = YEAR(CURRENT_DATE())
LEFT JOIN emp_promotion as pro
ON e.id=pro.emp_id
AND YEAR(pro.directorate_date) = YEAR(CURRENT_DATE()))
WHERE YEAR(e.promotionDate) = YEAR(CURRENT_DATE())
GROUP BY e.fullname;

Using select from another select in MySQL

I have the following query where I will have finally a 205 patient IDs to work with:
select
patient_id
FROM
visit
WHERE
month(visit.date_of_visit)=3
AND
year(visit.date_of_visit)=2018
AND
visit.visit_status='Active'
GROUP BY patient_id
I want to get all the 205 IDs and run them into other query to see how many diseases we have as cardio-vascular and then as respiratory disease.
My database structure is as the following:
What I want is to get for each patient id, what they are diagnosed at ONLY their first visit to the hospital (so here we will work with min(visit.date_of_visit))
The desired result for `diagnosis_name LIKE '%Cardio%':
E.g>:
Patients: 150 (Or something)
And the query is changed to get the respiratory info.
I tried the following for the Cardio diseases where I use select from select:
SELECT count(*)
FROM
(
select
min(visit.date_of_visit), visit_id, patient_id, count(*) as patientId
FROM
visit
WHERE
month(visit.date_of_visit)=3
AND
year(visit.date_of_visit)=2018
AND
visit.visit_status='Active'
GROUP BY patient_id
) as vid
LEFT JOIN
consultation ON consultation.visit_id=vid.visit_id
LEFT JOIN
diagnosis ON diagnosis.diagnosis_id=consultation.diagnosis_id
WHERE diagnosis.diagnosis_name LIKE '%Cardio%'
The result was: 5 which is a wrong number.
This can be done easily with PHP and MYSQL together but this will exhaust the server by repeating the same query for 205 times and increment a counter. So the desired result should be only done with MySQL.
Data example:
Visit Table
visit_id= 1; date_of_visit=2018-03-03; visit_reason=Active; ...;
patient_id=1234;
visit_id= 2; date_of_visit=2018-03-04; visit_reason=Active; ...;
patient_id=1239;
visit_id= 3; date_of_visit=2018-03-07; visit_reason=Active; ...;
patient_id=1234;
Consultation Table
consultation_id=1; ...; diagnosis_id=12; visit_id=1;...;
consultation_id=2; ...; diagnosis_id=12; visit_id=2;...;
Diagnosis Table
diagnosis_id=12; diagnosis_name: hypertension (cardio disease);
diagnosis_id=13; diagnosis_name: renal disease
By running the query to see patients who came to hospital and that they were diagnosed as having cardio disease in their initial first visit, the result should be in the example as 2 as you can see from the example where patient_id=1234 had 2 visits but I need to know what he had in his first one.
You can use window functions in MySQL 8+. But in older versions you need to calculate the value some other way.
The question for you is what you are counting:
SELECT COUNT(*) as num_diagnoses, COUNT(DISTINCT patient_id) as num_patients
FROM visit v JOIN
(SELECT patient_id,
MIN(v.date_of_visit) as min_dov
FROM visit v
WHERE v.date_of_visit >= '2018-03-01' AND
v.date_of_visit < '2018-04-01' AND
v.visit_status = 'Active'
) vf
ON v.patient_id = vf.patient_id AND v.date_of_visit = vf.min_dov JOIN
consultation c
ON c.visit_id = v.visit_id JOIN
diagnosis d
ON d.diagnosis_id = c.diagnosis_id
WHERE d.diagnosis_name LIKE '%Cardio%';
When working with dates, it is best to compare column values directly to dates, rather than dissecting them.
BRO, it works fine. Test it now on the live scenario.
SELECT count(*)
FROM
(
select
min(visit.date_of_visit) first_date, patient_id, count(*) as patientId
FROM
visit
WHERE
month(visit.date_of_visit)=3
AND
year(visit.date_of_visit)=2018
AND
visit.visit_status='Active'
GROUP BY patient_id
) as vid
INNER JOIN visit b ON
B.patient_id = vid.patient_id AND
B.date_of_visit = vid.first_date and
month(B.date_of_visit)=3 AND
year(B.date_of_visit)=2018 AND
B.visit_reason='Active'
INNER JOIN consultation ON
consultation.visit_id = B.visit_id
INNER JOIN diagnosis ON
diagnosis.diagnosis_id = consultation.diagnosis_id AND
diagnosis.diagnosis_name LIKE '%Cardio%'

The query is not giving a desired output which I want

Query with OR which outputs wrong
SELECT DISTINCT
sm___employees.id,
sm___employees.employee_code,
sm___employees.leaving_date,
sm___employees.name_of_employee,
sm___employees.position,
sm___employees.rating,
sm___employees.entry_date
FROM
sm___employees
JOIN
sm___employee_skills
ON
sm___employees.id=sm___employee_skills.employee_id
WHERE
((sm___employee_skills.skill_id=1 AND sm___employee_skills.ans LIKE '%MBA%')
**OR**
(sm___employee_skills.skill_id=5 AND sm___employee_skills.ans IN (3)))
AND
sm___employees.rating IN (1)
ORDER BY
sm___employee_skills.date DESC
But I want it by And
SELECT DISTINCT
sm___employees.id,
sm___employees.employee_code,
sm___employees.leaving_date,
sm___employees.name_of_employee,
sm___employees.position,
sm___employees.rating,
sm___employees.entry_date
FROM
sm___employees
JOIN
sm___employee_skills
ON
sm___employees.id=sm___employee_skills.employee_id
WHERE
((sm___employee_skills.skill_id=1 AND sm___employee_skills.ans LIKE '%MBA%')
**AND**
(sm___employee_skills.skill_id=5 AND sm___employee_skills.ans IN (3)))
AND
sm___employees.rating IN (1)
ORDER BY
sm___employee_skills.date DESC
When am using first query with OR of MBA or 3, It gives me result for both which is correct as per OR operation
I want only those records which are having MBA AND 3 which gives me blank records when there are records available with this comparison
So please help me to resolve this.
Thank you in advance
To start with: DISTINCT often indicates a badly written query. This is the case here. You are joining records only to dismiss them later. If you want employee records, then select from the employee table. If you have criteria on the skills table check this in the WHERE clause. Don't join.
Then the WHERE clause looks at one row at a time. So neither skill_id = ... AND skill_id = ... nor skill_id = ... OR skill_id = ... can work for you. You must look up the skills table twice:
SELECT
id,
employee_code,
leaving_date,
name_of_employee,
position,
rating,
entry_date
FROM sm___employees
WHERE rating IN (1)
AND id IN
(
SELECT employee_id
FROM sm___employee_skills
WHERE skill_id = 1 AND ans LIKE '%MBA%'
)
AND id IN
(
SELECT employee_id
FROM sm___employee_skills
WHERE skill_id = 5 AND ans IN (3)
);
And here is a way to look up skills just once:
SELECT
id,
employee_code,
leaving_date,
name_of_employee,
position,
rating,
entry_date
FROM sm___employees
WHERE rating IN (1)
AND id IN
(
SELECT employee_id
FROM sm___employee_skills
WHERE (skill_id = 1 AND ans LIKE '%MBA%')
OR (skill_id = 5 AND ans IN (3))
GROUP BY employee_id
HAVING COUNT(DISTINCT skill_id) = 2 -- both skills
);
It seems strange though that you consider ans to be a string in one place (ans LIKE '%MBA%') and a number in another (ans IN (3)).
UPDATE: If you want to sort by skill date, you should consider by which skill's date. For this to happen, you would join, but not join the skills table, but the skills aggregate result. E.g.:
SELECT
e.id,
e.employee_code,
e.leaving_date,
e.name_of_employee,
e.position,
e.rating,
e.entry_date
FROM sm___employees e
JOIN
(
SELECT employee_id, MAX(date) AS max_date
FROM sm___employee_skills
WHERE (skill_id = 1 AND ans LIKE '%MBA%')
OR (skill_id = 5 AND ans = 3)
GROUP BY employee_id
HAVING COUNT(DISTINCT skill_id) = 2 -- both skills
) s ON s.employee_id = e.id
WHERE e.rating = 1
ORDER BY s.max_date;
Please try this :
SELECT DISTINCT
sm1.id,
sm1.employee_code,
sm1.leaving_date,
sm1.name_of_employee,
sm1.position,
sm1.rating,
sm1.entry_date
FROM sm___employees sm1
LEFT JOIN sm___employee_skills sm2 ON sm1.id = sm2.employee_id
WHERE ((sm2.skill_id=1 AND sm2.ans LIKE '%MBA%')
AND (sm2.skill_id=1 AND sm2.ans=3))
AND sm1.rating IN (1)
ORDER BY sm2.date DESC;

Inner query is difficult to write

I have two tables:
customer with schema_id
Schema table has: schema_id, period, amt, updated_date
I need to take join of customer and schema but only retrieve the latest record joined and not the others.
customer table
cust_id name schema_id
1 ABC 1
Schema table
schema_id period amt updated_date
1 1 100 2010-4-1
1 2 150 2011-4-1
If you need the max(updated_date) for each schema_id, then you can use an subquery:
select c.cust_id, c.name, c.schema_id, s.period, s.amt, s.updated_date
from customer c
inner join
(
select s1.schema_id, s1.period, s1.amt, s1.updated_date
from `schemas` s1
inner join
(
select schema_id, max(updated_date) MaxDate
from `schemas`
group by schema_id
) s2
on s1.schema_id = s2.schema_id
and s1.updated_date = s2.maxdate
) s
on c.schema_id = s.schema_id
See SQL Fiddle with Demo
The subquery is then used in a join back to your table to return the rows that have the matching date and schema_id.
If I understood your problem, you need to take lastest register of the "schema".
I think you need to use max() function. So, try the query below:
select *
from customer c,
schema s
where c.schema_id = s.schema_id
and s.updated_date = ( select max(s2.updated_date)
from schema s2
where s2.schema_id = s.schema_id
)
Regards!
Edmilton