need help writing subquery - sql

I'm using a health database and trying to display patients who have visited the health facility more than two times. The basic query I have so far is
SELECT FirstName, LastName
FROM PATIENT
I know I have to use a subquery in there somehow, but I don't know if I need to use Count or any other operators to find patients visiting more than two times.

you could use a join with visit and count for distinct(VisitDate) filtering using having for the count > 1
SELECT FirstName, LastName , count(distinct VisitDate)
FROM PATIENT
inner join VISIT on VISIT.patientID = PATIENT.PatientID
group by FirstName, LastName
having count(distinct VisitDate) > 1

use aggregate function count and having clause for comparison
SELECT P.FirstName, P.LastName,COUNT(V.VisitID) as numberOfVisit
FROM VISIT V
JOIN PATIENT P ON P.PatientID = V.PatientID
GROUP BY V.PatientID, P.FirstName, P.LastName
HAVING COUNT(V.VisitID) > 2
By using sub query you can also get same result but no need that 1st query is more appropriate
select * from (
SELECT P.FirstName, P.LastName,COUNT(V.VisitID) as numberOfVisit
FROM VISIT V
JOIN PATIENT P ON P.PatientID = V.PatientID
GROUP BY V.PatientID, P.FirstName, P.LastName
) as T where T.numberOfVisit>2

select x.FirstName,x.LastName from (
SELECT a.FirstName, a.LastName,count(*) n
FROM PATIENTa,visit b
where a.patientid = b.patientid
group by a.FirstName, a.LastName having count(*) > 2
) x

Related

How do I select how many pantients every doctor has?

I have a table of Visits on the Hospital, included DoctorID, PacientID, Date....
I did like this but I recieved an error.
SELECT
d.DoctorID, COUNT(v.DoctorID)
FROM Visits v
left join Doctors d on v.DoctorID=d.DoctorID
You care missing the group by:
SELECT d.DoctorID, COUNT(v.DoctorID)
FROM Doctors d LEFT JOIN
Visits v
ON v.DoctorID = d.DoctorID
GROUP BY d.DoctorID;
In addition, you presumably want the LEFT JOIN starting with Doctors so you keep all doctors.
Your query is missing a GROUP BY clause. Also I do not see the need for a JOIN. If you want the count of (distinct) patientsIDs per doctorID, you can get that information directly from the visit table, like so:
select doctorID, count(distinct patientID) from visits group by doctorID
Or, if you also want to see doctors that have no patients:
select d.doctorID, count(distinct v.patientID)
from doctors d
left join visits v on v.doctorID = d.doctorID
group by d.doctorID
Live demo on db<>fiddle
You are missing GroupBy clause.
So you can fix it in this way
SELECT d.Name, COUNT(v.DoctorID) AS PantientCount
FROM Doctors d
LEFT JOIN Visits v ON d.DoctorId = v.DoctorId
GROUP BY d.Name
You can also using Conditional aggregation query with a group by like below.
SELECT d.Name, SUM(CASE WHEN v.CustomerId IS NOT NULL THEN 1 ELSE 0 END) AS PantientCount
FROM Doctors d
LEFT JOIN Visits v ON d.DoctorId = v.DoctorId
GROUP BY d.Name
Output

SQL having and max

My query:
SELECT P.lastname, P.firstname, MAX(MD.movie_id)
FROM Person AS P
INNER JOIN Movie_Directors AS MD ON P.person_id = MD.person_id
INNER JOIN Movie AS M ON M.movie_id = MD.movie_id
GROUP BY P.firstname, P.lastname, MD.movie_id
HAVING MAX(MD.movie_id);
I get this error:
An expression of non-boolean type specified in a context where a condition is expected, near ';'
I need to get a SQL select for the next question, I don't understand the error can anyone help?
The query needs to display the director who has produced the most films so far [firstname, lastname].
You need to provide a logical condition in the HAVING clause, like
HAVING MAX(MD.movie_id) > 100
The ROW_NUMBER clause can help you. Hopefully I don't have any typos in this. Also, if you have a person_id, I recommend you use that instead of the firstname, lastname for the partition.
WITH MaxMovies AS
(
SELECT P.lastname, P.firstname, ROW_NUMBER OVER (PARTITION BY firstname, lastname ORDER BY movie_id DESC) MOVIE_NUMBER
FROM Person AS P
inner join Movie_Directors AS MD ON P.person_id=MD.person_id
inner join Movie AS M ON M.movie_id=MD.movie_id
GROUP BY P.firstname, P.lastname
)
SELECT * FROM MAXMOVIES WHERE MOVIE_NUMBER=1
Reference: https://learn.microsoft.com/en-us/sql/t-sql/functions/row-number-transact-sql?view=sql-server-2017

DB2 SQL nested queries

I need to list the first name and last name of the youngest patient that is prescribed penicillin, using nested queries. Here is what I have
SELECT P.FIRST_NAME, P.LAST_NAME, MIN(P.AGE) AS AGE
FROM PATIENT AS P
WHERE P.PATIENT_NO IN(
SELECT PRE.PATIENT_NO
FROM PRESCRIPTION AS PRE
WHERE MEDICATION_CODE IN (
SELECT M.MEDICATION_CODE
FROM MEDICATION AS M
WHERE MEDICATION_DESC = 'Penicillin'))
GROUP BY P.FIRST_NAME, P.LAST_NAME
HAVING MIN(P.AGE);
The results come back with the two people that are prescribed penicillin, not just the youngest.
Why do you have to use nested queries?
In any case, the having clause is not doing what you want. You can get what you want by doing this:
SELECT P.FIRST_NAME, P.LAST_NAME, MAX(P.AGE) as AGE
FROM PATIENT AS P
WHERE P.PATIENT_NO IN (
SELECT PRE.PATIENT_NO
FROM PRESCRIPTION AS PRE
WHERE MEDICATION_CODE IN (
SELECT M.MEDICATION_CODE
FROM MEDICATION AS M
WHERE MEDICATION_DESC = 'Penicillin'
)
)
GROUP BY P.FIRST_NAME, P.LAST_NAME
ORDER BY MAX(P.AGE)
FETCH FIRST 1 ROWS ONLY;
EDIT:
Actually, I agree with FloChanz, and the group by is probably not necessary (unless you need to remove duplicates):
SELECT P.FIRST_NAME, P.LAST_NAME, P.AGE
FROM PATIENT AS P
WHERE P.PATIENT_NO IN (
SELECT PRE.PATIENT_NO
FROM PRESCRIPTION AS PRE
WHERE MEDICATION_CODE IN (
SELECT M.MEDICATION_CODE
FROM MEDICATION AS M
WHERE MEDICATION_DESC = 'Penicillin'
)
)
ORDER BY P.AGE
FETCH FIRST 1 ROWS ONLY;
I guess that some inner join might be better like this :
SELECT P.FIRST_NAME, P.LAST_NAME, P.AGE
FROM MEDICATION AS M
INNER JOIN PRESCRIPTION AS PRE on PRE.MEDICATION_CODE = M.MEDICATION_CODE
INNER JOIN PATIENT AS P on P.PATIENT_NO = PRE.PATIENT_NO
WHERE M.MEDICATION_DESC = 'Penicillin'
ORDER BY P.AGE
FETCH FIRST 1 ROWS ONLY;
Figured it out. Thanks for all the suggestions
SELECT P.FIRST_NAME, P.LAST_NAME
FROM PATIENT AS P
WHERE P.AGE IN (
SELECT MIN(P.AGE)
FROM PATIENT AS P
WHERE P.PATIENT_NO IN(
SELECT PRE.PATIENT_NO
FROM PRESCRIPTION AS PRE
WHERE MEDICATION_CODE IN (
SELECT M.MEDICATION_CODE
FROM MEDICATION AS M
WHERE MEDICATION_DESC = 'Penicillin')));

How to write this query to display a COUNT with other fields

I have following two tables:
Person {PersonId, FirstName, LastName,Age .... }
Photo {PhotoId,PersonId, Size, Path}
Obviously, PersonId in the Photo table is an FK referencing the Person table.
I want to write a query to display all the fields of a Person , along with the number of photos he/she has in the Photo table.
A row of the result will looks like
24|Ryan|Smith|28|6
How to write such query in tsql?
Thanks,
You need a subquery in order to avoid having to repeat all the columns from Person in your group by clause.
SELECT
p.PersonId,
p.FirstName,
p.LastName,
p.Age,
coalesce(ph.PhotoCount, 0) as Photocount
FROM
Person p
LEFT OUTER JOIN
(SELECT PersonId,
COUNT(PhotoId) as PhotoCount
FROM Photo
GROUP BY PersonId) ph
ON p.PersonId = ph.PersonId
SELECT
p.PersonId,
p.FirstName,
p.LastName,
p.Age,
CASE WHEN
t.ThePhotoCount IS NULL THEN 0 ELSE t.ThePhotoCount END AS TheCount
--the above line could also use COALESCE
FROM
Person p
LEFT JOIN
(SELECT
PersonId,
COUNT(*) As ThePhotoCount
FROM
Photo
GROUP BY PersonId) t
ON t.PersonId = p.PersonID
SELECT P.PersonId, FirstName, LastName,Age, COUNT(PhotoId) AS Num
FROM Person P
LEFT OUTER JOIN PHOTO PH ON P.PersonId = PH.PersonId
GROUP BY P.PersonId, FirstName, LastName,Age
select Person.*, count(PhotoId) from Person left join Photo on Person.PersonId = Photo.PersonId
IMO GROUP BY should be the solution, something like this works for me even with other table joins:
SELECT meetings.id, meetings.location, meetings.date, COUNT( users.id ) AS attendees
FROM `meetings`
LEFT JOIN users ON meetings.id = users.meeting_id
WHERE meetings.moderator_id = 'XXX'
GROUP BY meetings.id

Compare subselect value with value in master select

In MS Access, I have a query where I want to use a column in the outer query as a condition in the inner query:
SELECT P.FirstName, P.LastName, Count(A.attendance_date) AS CountOfattendance_date,
First(A.attendance_date) AS FirstOfattendance_date,
(SELECT COUNT (*)
FROM(SELECT DISTINCT attendance_date
FROM tblEventAttendance AS B
WHERE B.event_id=8
AND B.attendance_date >= FirstOfattendance_date)
) AS total
FROM tblPeople AS P INNER JOIN tblEventAttendance AS A ON P.ID = A.people_id
WHERE A.event_id=8
GROUP BY P.FirstName, P.LastName
;
The key point is FirstOfattendance_date - I want the comparison deep in the subselect to use the value in each iteration of the master select. Obviously this doesn't work, it asks me for the value of FirstOfattendance_date when I try to run it.
I'd like to do this without resorting to VB code... any ideas?
How about:
SELECT
p.FirstName,
p.LastName,
Count(a.attendance_date) AS CountOfattendance_date,
First(a.attendance_date) AS FirstOfattendance_date,
c.total
FROM (
tblPeople AS p
INNER JOIN tblEventAttendance AS a ON
a.people_id = p.ID)
INNER JOIN (SELECT people_id, Count (attendance_date) As total
FROM (
SELECT DISTINCT people_id,attendance_date
FROM tblEventAttendance)
Group By people_id) AS c ON
p.ID = c.people_id
GROUP BY
p.ID, c.total;
Can you change
B.attendance_date >= FirstOfattendance_date
to
B.attendance_date >= First(A.attendance_date)