Trying to figure out a sql query to fetch the right data from multiple tables - sql

So I have a database and I have 4 tables (admin, appointment, doctor, patient).
I only care about appointment, doctor and patient.
Diagram of these 3 tables:
What I want is based on a patients amka(int) to find all his appointments and show his name, surname and doctors name, surname.
I made this query:
(SELECT doctor.name, doctor.surname
FROM public.doctor
INNER JOIN public.appointment ON doctor.username = 'alouisot2')
union
(SELECT patient.name, patient.surname
FROM public.patient
INNER JOIN public.appointment ON patient.amka = '713783001');
The problem with this query is that it will only show appointments between this specific doctor and I just want to get all the doctors names and surnames.
Also I use postgresql.
I was trying to figure it out but I couldn't. I need to restructure the query but I cannot think how I would solve this problem.
If you have any idea on how to do achieve this I would really appreciate it.

Try this - properly join the three tables together (doctor to appointment based on the common username column, appointment to patient on the common amka column), and define the WHERE clause with your desired values:
SELECT
doctor.name, doctor.surname,
patient.name, patient.surname
FROM
public.doctor
INNER JOIN
public.appointment ON doctor.username = appointment.username
INNER JOIN
public.patient ON appointment.amka = patient.amka
WHERE
doctor.username = 'alouisot2'
AND patient.amka = '713783001';

this query just needs simple joins; you seem to have overcomplicated it a lot for some reason...
SELECT
patient.name,
patient.surname,
doctor.name,
doctor.surname
FROM public.patient
INNER JOIN public.appointment
ON patient.amka = appointment.amka
INNER JOIN public.doctor
ON appointment.username = doctor.username
WHERE patient.amka = '713783001'

Related

Sub Queries, Group By's, and Joins

I am new to sql and am trying to complete an assignment for a class where were practicing using subqueries and joins.
The question I'm struggling with is: Provide a list of the airport city names and the travelers (last name) who have traveled to each airport via a flight.
Here are the tables in the database:Database Tables
Here is what I have so far:
SELECT Airport.CityName
FROM AIRPORT
GROUP BY AirportID
INNER JOIN FLIGHT
ON FLIGHT.AirportID = AIRPORT.AirportID
INNER JOIN TRAVELER
ON TRAVELER.TravelerID = FLIGHT.TravelerID
SELECT TravLastName
FROM TRAVELER
but I'm getting an error on the first "Inner" and I know I'm probably nowhere close to being right. Any help would be appreciated.
The joins look fine but there should only be one select at the beginning and the group by should come at the end
SELECT
Airport.CityName,
TRAVELER.TravLastName
FROM AIRPORT
INNER JOIN FLIGHT
ON FLIGHT.AirportID = AIRPORT.AirportID
INNER JOIN TRAVELER
ON TRAVELER.TravelerID = FLIGHT.TravelerID
GROUP BY
Airport.CityName,
TRAVELER.TravLastName;
Or, as we are not using any aggregate functions we can use DISTINCT. It is simpler and can run quicker.
SELECT DISTINCT
Airport.CityName,
TRAVELER.TravLastName
FROM AIRPORT
INNER JOIN FLIGHT
ON FLIGHT.AirportID = AIRPORT.AirportID
INNER JOIN TRAVELER
ON TRAVELER.TravelerID = FLIGHT.TravelerID;
You don't want GROUP BY, you want DISTINCT:
SELECT DISTINCT
AIRPORT.CityName,
TRAVELER.TravLastName
FROM AIRPORT
JOIN FLIGHT ON FLIGHT.AirportID = AIRPORT.AirportID
JOIN TRAVELER ON TRAVELER.TravelerID = FLIGHT.TravelerID
Some tidy ups:
INNER is the default join type, so you can leave it out
DISTINCT means remove duplicates
FROM starts the list of tables to be joined. You can't add tables to the query in other places
A further tidy up would be to use table aliases, which rename the table in the context of the query - often using just the first letter of the table, to make the query smaller overall:
SELECT DISTINCT
a.CityName,
t.TravLastName
FROM AIRPORT a
JOIN FLIGHT f ON f.AirportID = a.AirportID
JOIN TRAVELER t ON t.TravelerID = f.TravelerID
The keyword AS may optionally be put between a table and its alias, eg FROM AIRPORT AS a.

On an SQL Select, how do i avoid getting 0 results if I want to query for optional data in another table?

I have a table with Customers which includes their contact person in the helpdesk. I have another table that lists all vacancies of the helpdesk employees - if they are currently sick or on vacation etc.
I need to get the helpdesk contact and the start/end time of their vacation IF there is an entry.
I currently have this (simplified):
SELECT *
FROM dbo.Customers, dbo.Projects, dbo.Vacations
WHERE ($Phone = dbo.Customers.Phone)
AND dbo.Customers.CustomerID = dbo.Projects.CustomerID
AND dbo.Projects.HDContactID = dbo.Vacations.HDContactID
So if there is a vacation listed in the Vacations table, it works fine, but if there is no vacation at all, this will not return anything - what i want is that if there is no vacation, it simply returns the other data, and ignores the missing data (returns NULL, doesn't return anything, not important)
In any case, I need to get the Customers and Project data, even if the query can't find an entry in the Vacations table. How would I do this? I pretty new to SQL and couldn't find a similar question on this site
EDIT: I'm using SQL Server, currently using HeidiSQL
Try below query:
SELECT * FROM dbo.Customers, dbo.Projects
left join dbo.Vacations on dbo.Projects.HDContactID = dbo.Vacations.HDContactID
WHERE ($Phone = dbo.Customers.Phone)
AND dbo.Customers.CustomerID = dbo.Projects.CustomerID
Use left join as mentioned by #Flying Thunder,
Example of the left join:
SELECT country.country_name_eng, city.city_name, customer.customer_name
FROM customer
LEFT JOIN city ON customer.city_id = city.id
LEFT JOIN country ON city.country_id = country.id;
You can find a nice guide for the joins and SQL here:
https://www.sqlshack.com/learn-sql-join-multiple-tables/
You should be using LEFT JOIN. In fact, you should never be using commas in the FROM clause. That is just archaic syntax and closes the powerful world of JOINs from your queries.
I also recommend using table aliases that are abbreviations of table names. The best are abbreviations for the table names:
SELECT *
FROM dbo.Customers c LEFT JOIN
dbo.Projects p
ON c.CustomerID = p.CustomerID LEFT JOIN
dbo.Vacations v
ON p.HDContactID = v.HDContactID
WHERE c.Phone = $Phone;
Have you try this to skip vacation record if not present like this:
SELECT * FROM dbo.Customers, dbo.Projects, dbo.Vacations
WHERE ($Phone = dbo.Customers.Phone)
AND dbo.Customers.CustomerID = dbo.Projects.CustomerID
AND (dbo.Vacations.HDContactID IS NULL OR dbo.Projects.HDContactID = dbo.Vacations.HDContactID)

SQL for many to one to many table

I have three tables in an Access database that I am using in java via ucanaccess.
Patients (PK Pt_ID)
Endoscopy (PK Endo_ID, FK Pt_ID)
Histology (PK Histol_ID, FK Pt_ID)
1 patient can have many endoscopies
1 patient can have many histologies
Endoscopy and histology are not related
I want to retrieve all the Endoscopies and histologies for a single patients in a single SQL query. Although I can write select statements for two tables I don't know how to do this across the three tables. Is it something like this
Select *.Endoscopy,*.Histology from Patients INNER JOIN Endoscopy, Histology ON Patient.Pt_Id=Endoscopy.Pt_ID, Patient.Pt_Id=Histology.Pt_ID
I'm sure that's a mess though...
What kind of SQL DB are you using?
I believe this works on most.
SELECT * FROM Patients, Endoscopy, Histology
WHERE Patient.Pt_Id=Endoscopy.Pt_ID
AND Patient.Pt_Id=Histology.Pt_ID
Also, I belive you have these switched around *.Endoscopy,*.Histology If you need to use that it should be Endoscopy.*, Histology.*
You can use the following query to select both endoscopies and histologies :
SELECT p.Pt_ID
, e.Endo_ID
, h.Histol_ID
FROM Patients p
INNER JOIN Endoscopy e ON p.Pt_Id = e.Pt_ID
INNER JOIN Histology h ON p.Pt_Id = h.Pt_ID
But I'm not sure this is really what you want. You might need to map the tables Patients, Endoscopy and Histology into Java classes ? In this case, you can consider the Java Persistence API (JPA). It helps you to handle these tables in your java code. Here is a JPA Quick Guide.
First idea is to use inner join (with correct syntax) but this is wrong. inner join returns patients who have both procedure. Pure left join returns additionally patients who have none. So this is the solution:
SELECT Patients.Pt_PK, Endoscopy.*, Histology.*
FROM Patients
LEFT JOIN Endoscopy ON Patients.Pt_Id = Endoscopy.Pt_ID
LEFT JOIN Histology ON Patients.Pt_Id = Histology.Pt_ID
--exclude patients who don't have any
where coalesce(Endoscopy.Endo_ID, Histology.Histol_ID) is not null
If you have multiple Endoscopy records or multiple Histology records for the same Patient then you will receive duplicate/repeated records in your SELECT. I do no think there is a way around that unless you use 2 SELECT statements instead of 1.
SELECT Endoscopy.*, Histology.*
FROM Patients
INNER JOIN Endoscopy ON Patients.Pt_Id = Endoscopy.Pt_ID
INNER JOIN Histology ON Patients.Pt_Id = Histology.Pt_ID
To select all records on a table in the select its table name/table alias .*
INNER JOIN will only select records where there is a relationship, once one of these tables does not contain a Pt_ID where it is contained in any one of the other tables then no record will be displayed with that Pt_ID
To add additional tables continue to add additional join statements
You used Patients (with S) in one location and Patient (no S) in another, make sure you use the correct naming. I am guessing its Patients but maybe its Patient.
This statement does almost the same as the above but uses LEFT JOIN syntax so that you will always get records for both tables even if one of the two tables does not have a record for a patient.
SELECT Endoscopy.*, Histology.*
FROM Patients
LEFT JOIN Endoscopy ON Patients.Pt_Id = Endoscopy.Pt_ID
LEFT JOIN Histology ON Patients.Pt_Id = Histology.Pt_ID
WHERE Histology.Histol_ID IS NOT NULL OR Endoscopy.Endo_ID IS NOT NULL
The added WHERE clause ensures that you do not get a record with all NULL values where there is a patient but no records in either of those tables.

sql multiple attribute join

I'm creating a test database on medical practices. Here is a picture of my er diagram for reference. ER diagram
So basically my question is how to do joins properly. I'm trying to give a list of patients seen from a given practice (e.g practice id 1) but i also want to show the practice name and details. I also want to show a list of the patients and and gp's who work or have been to that practice (keep in mind i have only populated my tables with 10 rows of test data)
I have got so far
select patient.firstname, patient.surname
from patient
Join appointment on patient.patientid = appointment.patientid
where appointment.practiceid IN (1)
ORDER BY firstname;
`How would i also include the practice details and the gp details also who are associated with this practice. What's confusing me is how i add more select statements if they are not from the patient table. Any help would be great!
You can just add more join clauses:
SELECT patient.firstname, patient.surname, practice.name, practice.address
FROM patient
JOIN appointment ON patient.patientid = appointment.patientid
JOIN practice ON appointment.practiceid = practice.practiceid
WHERE appointment.practiceid IN (1)
ORDER BY firstname;
I like aliasing my SQL statements. Saves on typing.
SELECT p.firstname, p.surname, pr.Details
FROM patient p
JOIN appointment a ON p.patientid = a.patientid
JOIN Practice pr ON pr.PracticeId = a.PracticeId
WHERE a.practiceid IN (1)
ORDER BY p.firstname;
I've included how to show the Practice_Name in your query, if you use the same join logic approach for each of the other queries you mention, you will work it out. I think that's a better way to learn rather than solving every question above in one answer.
SELECT PR.Practice_Name, P.firstname, P.surname
FROM patient AS P
INNER JOIN appointment AS A ON P.patientid = A.patientid
INNER JOIN Practice AS PR ON A.practiceid = PR.practiceid
WHERE A.practiceid IN (1)
ORDER BY P.firstname;

How do you combine multiple rows of data on same line

Basically I want to take all the names (RequiredAccount, RequiredContact, RequiredOwner) for all the rows with a matching activityid and put them in there own column. So in short, I want to take multiple rows of data and put them in a Column. Basically I want to do what this person is doing (http://www.sqlprof.com/blogs/sqldev/archive/2008/03/31/how-to-list-multiple-rows-of-data-on-same-line.aspx) but I can't seem to get it to work.
SELECT DISTINCT
Appointment.ActivityId, Appointment.ScheduledStart, Appointment.OwnerIdName, Contact.AccountIdName, Appointment.new_ContactPersonName,
Appointment.Subject, Appointment.new_ColderNotes, Account.AccountId, Contact_1.ContactId, SystemUser.SystemUserId, SystemUser.FullName AS OptionalOwner,
Contact_1.FullName AS OptionalContact, Account.Name AS OptionalAccount, ActivityParty.PartyId, ActivityParty.ParticipationTypeMask,
Contact_1.FullName AS RequiredContact, Account.Name AS RequiredAccount, SystemUser.FullName AS RequiredOwner, Account.new_BusinessUnit
FROM
Contact AS Contact_1 RIGHT OUTER JOIN
Account RIGHT OUTER JOIN
SystemUser RIGHT OUTER JOIN
Appointment INNER JOIN
ActivityParty ON Appointment.ActivityId = ActivityParty.ActivityId ON SystemUser.SystemUserId = ActivityParty.PartyId ON Account.AccountId = ActivityParty.PartyId ON
Contact_1.ContactId = ActivityParty.PartyId LEFT OUTER JOIN
Contact ON Appointment.new_ContactPerson = Contact.ContactId
And what I want if for the three Required columns to be in one column if there ActivityID Matches. So the first two rows would have two names in the new column.
Any ideas, help, etc.
Big Thanks!
Simulating group_concat in sql server 2005
There are a couple of working examples in that thread, none of them are very pretty though :-/