SQL getting the average count of diagnosis based on specialty - sql

I have 2 tables one for appointments and one for doctors.
I want to select the average number of patients for each specialty, which is stored in the doctors table. The appointments table has the patients' id the doctors' id and the diagnosis, if a patient has had a diagnosis.
I tried this, but doesn't work.
SELECT AVG(patientAMKA)
FROM appointments
WHERE diagnosis IS NOT NULL
GROUP
BY doctor.specialty
EDIT: I just want to clarify that patientAMKA is the id of the patient.
EDIT2: I specifically mean how many patients (with a diagnosis) exist for each speciaity, then take the average of those numbers.

Sounds like it would be something like:
SELECT d.specialty, COUNT(*)
FROM doctor d
INNER JOIN appointments a ON d.id = a.doctor_id
WHERE diagnosis IS NOT NULL
GROUP BY d.specialty

SELECT doc.specialty, AVG(app.patientAMKA)
FROM doctor doc
JOIN appointments app ON doc.doctorid = app.doctorid
WHERE app.diagnosis IS NOT NULL
GROUP BY doc.specialty

Based on your clarifications, I believe what you want is:
SELECT
AVG(CountOfDiagnoses) as TheAverage
FROM
(
SELECT
d.specialty,
COUNT(1) as CountOfDiagnoses
FROM
appointments a
JOIN doctor d ON
d.doctor_id = a.doctor_id
WHERE
a.diagnosis IS NOT NULL
GROUP BY
d.specialty
) Counts

Related

PostgreSQL JOIN in aggregate function

Treatment table schema
id
doctor_id
location_id
patient_id
...
I need to be able to group patient treatments based on location and list all the doctors that were treating the patient for the specific location.
SELECT id,
(SELECT STRING_AGG(t.initials::text, ',') FROM (
SELECT DISTINCT treatments.doctor_id, doctors.initials FROM
treatments LEFT JOIN doctors ON doctors.id = treatments.doctor_id) t
) as treating_doctors_initials
GROUP BY treatments.patient_id, treatments.location_id
The problem is that this returns the same initials for all records -> it does perform the join I guess or maybe I am misunderstanding the aggregate function.

how to count different values from different tuples into the same sceme in sql

I have a table of hospitals details, department details linked to it, types of workers (the staff) in different tables, and their salary information.
I want to extract the following for each hospital: the average and the sum of the salaries, the number of nurses, the number of research doctors and the number of beds in all the departments of a specific hospital.
I built this view of all the workers salary information:
CREATE VIEW workers AS
SELECT hospcod, docsal as sal, 'treatdoc' as typework
FROM doc NATURAL JOIN treatdoc NATURAL JOIN dept
UNION
SELECT hospcod, nursal, 'nurse'
FROM nurse NATURAL JOIN dept
UNION
SELECT hospcod, docsal, 'rsrchdoc'
FROM doc NATURAL JOIN rsrchdoc NATURAL JOIN lab;
the departments and the labs have the hospital code column to correlate a worker information to a specific hospital.
so I have one sceme for all the staff with their rules workers(hospital_code, salary, type_of_worker)
here is the query I'm trying to build:
SELECT hospname, sum(workers.sal), avg(workers.sal), count(dept.numbed),
(SELECT count(typework) from workers where typework = 'nurse') nurse_num,
(SELECT count(typework) from workers where typework = 'rsrchdoc') rsrchdoc_num
FROM hosp NATURAL JOIN dept NATURAL JOIN workers
GROUP BY hospname;
I want to count for each hospital, the number of nurses and the number of research doctors
but it should be correlated somehow to the different hospitals (in the above it gives me the same number of nurses / rsrchdocs for each hospital) , there should be columns that is grouped by hospnames and should get all the tuples like the salary info (avg, sum), as I got properly, but the workers information should be grouped HAVING typework = 'nurse' for the nurse_num, and for the column rsrchdoc_numit should be HAVING typework = 'rsrchdoc_num'
does someone have an idea how can I combine thouse columns in one query?
thank you!
There is an error in your query, I will try to explain.
When you do:
(SELECT count(typework) from workers where typework = 'nurse') nurse_num,
You are getting a constant, that is not affected by the "group by" you are doing after.
What you have to do is a JOIN (like you did in the view) and link the nurse and the rsrchdoc to an specific hospital.
I will give an example is pseudo code
SELECT hosp_name, sum(nurse.salary) , avg(nurse.salary)
FROM hosp
JOIN nurse ON nurse.hosp_name = hosp.hosp_name
GROUP BY hosp.hosp_name
This query will give you 1 row for each nurse in each hospital (assuming that a nurse may work in more than one hospital).
Then you have to do the same thing also for doctors, in a different operation.
SELECT hosp_name, sum(doctors.salary) , avg(doctors.salary)
FROM hosp
JOIN doctors ON doctors.hosp_name = hosp.hosp_name
GROUP BY hosp.hosp_name
And finally you will have to join both ( you may perform the sum first to make it more readable.
SELECT hosp_name, sum_sal_doc, avg_sal_doc, sum_nur_doc, avg_nur_doc
FROM hosp
LEFT JOIN ( SELECT doctors.hosp_name, sum(doctors.salary) as sum_sal_doc, avg(doctors.salary) as avg_sal_doc
FROM doctors
GROUP BY doctors.hosp_name
) t1 ON t1.hosp_name = hosp.hosp_name
LEFT JOIN ( SELECT nurses.hosp_name, sum(nurses.salary) as sum_nur_doc, avg(nurses.salary) as avg_nur_doc
FROM nurses
GROUP BY nurses.hosp_name
) t2 ON t2.hosp_name = hosp.hosp_name
There must be 1 to many relationship between hosp --> dept and hosp --> workers so if you join these 3 tables then you will definitely find the duplicates for dept and workers so you must have to create sub-query for one of the dept or workers to fetch single grouped record group by hospital as follows:
SELECT h.hospname,
sum(w.sal) total_all_worker_sal,
avg(w.sal) avg_all_workers_sal,
d.numbed,
count(case when w.typework = 'nurse' then 1 end) nurse_num,
count(case when w.typework = 'rsrchdoc' then 1 end) rsrchdoc_num
FROM hosp h
JOIN (select hospital_code , sum(numbed) numbed
-- used SUM as numbed must be number of bed in department
-- COUNT will give you only number of department if you use count(d.numbed)
from dept
group by hospital_code) d ON h.hospital_code = d.hospital_code
JOIN workers w ON h.hospital_code = d.hospital_code
GROUP BY h.hospital_code , h.hospname, d.numbed;
-- used h.hospital_code to separate the records if two hospitals have same name

SQL Subquery or Join?

Desired result is to have all patients that have more than 1 allergy displayed with their PatientId (From Patient table, NOT Allergy table) and PatientName
2 Tables:
Patient table contains PatientId (Represented as P_), PatientName.
Allergy table contains PatientId (Represented as p_), AllergyName.
So far, I have 2 queries that I want to connect together but dont know how:
SELECT PatientId, PatientName
FROM Patient;
SELECT COUNT(AllergyName)
FROM Allergy
GROUP BY AllergyName
HAVING COUNT(AllergyName) >1;
I want to complete a calculation in the "background" without it being shown in the table. PatientId's are the same, just that for Patient table it is an uppercase P and lowercase p for Allergy table.
SELECT PatientId, PatientName
FROM Patient INNER JOIN (SELECT COUNT(*) as allergy_count, PatientId
FROM Allergy
GROUP BY PatientId
HAVING COUNT(*) >1) aggr ON Patient.PatientId=aggr.PatientId
I assume this is what you are asking for:
SELECT Patient.PatientId, Patient.PatientName
FROM Patient
INNER JOIN Allergy ON Patient.PatientId = Allergy.patientId
GROUP BY Allergy.patientId
HAVING COUNT(Allergy.AllergyName)>1;
EDIT:
all patients that have more than 1 allergy displayed with their
PatientId (From Patient table, NOT Allergy table) and PatientName
I guess from that you don't need to display the count.
Below code should solve the purpose for you:
SELECT P.PatientID, P.PatientName from Patient P
JOIN Allergy A ON A.PatientID = P.PatientID
GROUP BY A.AllergyName
HAVING COUNT(A.PatiendID) > 1
Inner queries can cost you performance degrade in case of large datasets so joins are recommended to optimise query performance.
This should work.
SELECT PatientId, PatientName from (
SELECT PatientId, PatientName, (SELECT COUNT(AllergyName)
FROM Allergy A
WHERE A.PatientId= P.PatientId
GROUP BY patientID
HAVING COUNT(AllergyName) >1)
FROM Patient P)
Assuming you require only patient id and name the below query is suitable for your requirement.

SQL table select

I have two tables:
Patients where I have patient_ID as primary key and other details.
Patients_Treatments where I have patient_ID from Patients as foreign key, treatment_code, and other columns.
I am requested to find all the patient's treatment codes that have the same treatment_code as patient whose id is 999.
I'm sitting for two days trying to find a solution and I just can't manage to think of something. It seems simple but I just can't find a solution.
Example:
The expected output are the details (Details means first name, last name, and patient ID) of: Tal Shalom Dan Shabtay Elad Gigi
If you are looking for the Treatment_Code and Patient information for the patients that share a Treatment_Code belonging to Patient_Id: 999, this should get you those results:
Select T.Treatment_Code, P.First_Name, P.Last_Name, P.Patient_Id
From Patients_Treatments T
Join Patients P On P.Patient_Id = T.Patient_Id
Where T.Patient_Id In
(
Select T1.Patient_Id
From Patients_Treatments T
Join Patients_Treatments T1 On T1.Treatment_Code = T.Treatment_Code
And T1.Patient_ID <> T.Patient_Id
Where T.Patient_Id = 999
)

Cross records between tables

I have this query:
select pa.id,pa.name
from patients pa
where (select count(distinct co.doctorID)
from consults co
where co.patientID=pa.id) = (select count(do.id)
from doctors do);
In which I select the patients who had consults with all the doctors.
I am counting the number of distinct doctors and see if is equal to the total of doctors.
But how can I do this with an exists and/or in without using count
You can use a nested NOT EXISTS:
select pa.id,pa.name
from patients pa
where NOT EXISTS
(
select 1 FROM doctors do
where NOT EXISTS
(
SELECT 1 FROM consults co
WHERE co.doctorID=do.id
AND pa.id=co.patientID
)
)
In other words, select all patients without a doctor that was not consulted. At least it should give you the idea.
I think you can try even better solution with NOT EXISTS that will not require counts at all:
SELCT pa.id,pa.name
FROM patients pa
WHERE NOT EXISTS (SELECT *
FROM doctors do
LEFT JOIN consults co
ON co.doctorID ON do.id
WHERE co.patientID=pa.id
AND co.doctorID IS NULL
)
In sub-query we get all the doctors and see whether all of them have consult for current patient. If co.doctorID IS NULL, that doctor was not visited by patient.