Joins on multiple tables in Postgresql - sql

I'm practising for an upcoming database exam and I'm trying to get my head around nested and multiple joins in SQL, specifically the Postgresql syntax. I want to return all the student names and department names of all students that achieved grade A.
Here's my schema.
CREATE TABLE student1 (
student_number INTEGER NOT NULL PRIMARY KEY,
name TEXT NOT NULL,
class INTEGER NOT NULL,
major TEXT NOT NULL
);
CREATE TABLE course1 (
course_name TEXT NOT NULL,
course_number TEXT NOT NULL PRIMARY KEY,
credit_hours INTEGER NOT NULL,
department TEXT NOT NULL
);
CREATE TABLE section1 (
section_identifer INTEGER NOT NULL PRIMARY KEY,
course_number TEXT NOT NULL,
semester TEXT NOT NULL,
year INTEGER NOT NULL,
instructor TEXT NOT NULL,
FOREIGN KEY (course_number) REFERENCES course1(course_number) ON DELETE CASCADE
);
CREATE TABLE grade_report1 (
id SERIAL NOT NULL PRIMARY KEY,
student_number INTEGER NOT NULL,
section_identifer INTEGER NOT NULL,
grade TEXT NOT NULL,
FOREIGN KEY (student_number) REFERENCES student1(student_number) ON DELETE CASCADE,
FOREIGN KEY (section_identifer) REFERENCES section1(section_identifer) ON DELETE CASCADE
);
I put together a nested statement that I thought would work:
SELECT t1.name, t3.department
FROM (student1 t1 INNER JOIN grade_report1 t2 ON t1.student_number = t2.student_number) t5
INNER JOIN (course1 t3 INNER JOIN section1 t4 ON t3.course_number = t4.course_number) t6
ON t5.section_identifer = t6.section_identifer
WHERE t2.grade = 'A';
However, this gives me the error invalid reference to FROM-clause entry for table "t1". I'm guessing it is because that is not how you are supposed to name/reference JOINS. I would like a way to JOIN all of these tables together. Thanks!

Remove the parentheses and fix the aliases:
SELECT s.name, c.department
FROM student1 s INNER JOIN
grade_report1 gr
ON gr.student_number = s.student_number INNER JOIN
section1 sec
ON sec.section_identifer = gr.section_identifer INNER JOIN
course1 c
ON sec.course_number = c.course_number
WHERE gr.grade = 'A';
The parentheses are allowed, but they are not needed. When using parentheses (which is very, very rarely needed), they do not get separate aliases.

Related

how Inner join work on two foreign key from single table

I am working on Bus route management system , I made two table first one is Cities and second one is route have following queries
CREATE TABLE Cities
(
ID NUMBER GENERATED ALWAYS AS IDENTITY(START with 1 INCREMENT by 1) PRIMARY KEY,
Name Varchar(30) not null,
)
CREATE TABLE route
(
ID NUMBER GENERATED ALWAYS AS IDENTITY(START with 1 INCREMENT by 1) PRIMARY KEY,
Name Varchar(30) not null,
from NUMBER not null,
to NUMBER NOT NULL,
CONSTRAINT FROM_id_FK FOREIGN KEY(from) REFERENCES Cities(ID),
CONSTRAINT TO_id_FK FOREIGN KEY(to) REFERENCES Cities(ID),
)
i am joining the table through inner join
select CITIES.Name
from CITIES
inner join ROUTES on CITIES.ID=ROUTES.ID
but it show single column as
Name
-----------
but i want result as
from | to
------------------------
what is possible way to do this using inner join
I suspect you need something like the following:
select r.Name, cs.Name SourceCity, cd.Name DestinationCity
from routes r
join cities cs on cs.id = r.from
join cities cd on cd.id = r.to
Hope is working for you
select CITIES.Name,ROUTES.from,ROUTES.to
from CITIES inner join ROUTES on CITIES.ID=ROUTES.ID

Is left outer join equivalent to inner join for non-null foreign keys?

Each city has owning country:
create table COUNTRY
(
ID number not null,
NAME varchar,
primary key (ID)
);
create table CITY
(
ID number not null,
NAME varchar,
COUNTRY_ID number not null,
primary key (ID)
);
alter table CITY
add constraint CITY_COUNTRY_FK
foreign key (COUNTRY_ID) references COUNTRY (ID);
Is the following:
select *
from CITY c
left outer join COUNTRY ctr on ctr.ID = c.COUNTRY_ID
where ...;
equivalent to:
select *
from CITY c
inner join COUNTRY ctr on ctr.ID = c.COUNTRY_ID
where ...;
because COUNTRY_ID is foreign key and not null?
In this case, the left join is redundant based on the data model. The NOT NULL constraint means that every city has a country_id. The foreign key constraint means that the country_ids are valid and are in the country table.
Combined, these constraints say that every row in city has a matching row in country. When all keys match, the left join is equivalent to inner join.
Yes basically if you are sure all entries had an equivalent, at all cases the left will be equivalent to inner.
As you mentioned each city has owning country, so yes it's gonna be the same result

Select a product that is on all interventions

Hello my question is simple for some of yours ^^
I've a table product, reference, and intervention. When there is an intervention the table reference make the link between products that we need for the interventions and the intervention.
I would like to know how to do to search products that have made part of all interventions.
This are my tables :
--TABLE products
create table products (
reference char(5) not null check ( reference like 'DT___'),
designation char(50) not null,
price numeric (9,2) not null,
primary key(reference) );
-- TABLE interventions
create table interventions (
nointerv integer not null ,
dateinterv date not null,
nameresponsable char(30) not null,
nameinterv char(30) not null,
time float not null check ( temps !=0 AND temps between 0 and 8),
nocustomers integer not null ,
nofact integer not null ,
primary key( nointerv),
foreign key( noclient) references customers,
foreign key (nofacture) references facts
);
-- TABLE replacements
create table replacements (
reference char(5) not null check ( reference like 'DT%'),
nointerv integer not null,
qtereplaced smallint,
primary key ( reference, nointerv ),
foreign key (reference) references products,
foreign key(nointerv) references interventions(nointerv)
);
--EDIT :
This is a select from my replacement table
We can see in this picture that the product DT802 is used in every interventions
Thanks ;)
This will show 1 line intervention - products. Is this you are expecting for?
select interventions.nointerv, products.reference
from interventions
inner join replacements on interventions.nointerv = replacements.nointerv
inner join products on replacements.reference = products.reference;
This one?
select products.reference, products.designation
from interventions
inner join replacements on interventions.nointerv = replacements.nointerv
inner join products on replacements.reference = products.reference
group by products.reference, products.designation
having count(*) = (select count(*) from interventions);
Your question is hard to follow. If I interpret it as all nointerv in replacements whose reference contains all products, then:
select nointerv
from replacements r
group by nointerv
having count(distinct reference) = (select count(*) from products);

views/ queries for multiple foreign keys referencing same primary keys

Hello I have got two tables and the staff_id from the risk table is used to look up the name of the owner and contact person. I was wondering if it is possible to create a view which includes both the owner name and staff name. I tried to create a view as shown below but I could only include either owner name or contact name in the view. (For reference I am using derby). Thanks in advance.
CREATE VIEW public_view AS
SELECT r.risk_id, r.risk_name s.staff_name
FROM risk r, staff s
AND r.owner_id = s.staff_id;
CREATE TABLE STAFF
(
staff_id varchar(8) NOT NULL,
staff_name varchar(100),
staff_email_addr varchar(30),
staff_position varchar(30),
staff_sect_elem varchar(60),
CONSTRAINT pk_staff_id PRIMARY KEY (staff_id)
);
CREATE TABLE RISK
(
risk_id varchar(6) NOT NULL,
risk_name varchar(20) NOT NULL,
risk_desc varchar(20),
owner_id varchar(8),
contact_id varchar(8),
CONSTRAINT pk_risk_id PRIMARY KEY (risk_id),
CONSTRAINT fk_owner_id FOREIGN KEY (owner_id) REFERENCES STAFF(staff_id),
CONSTRAINT fk_contact_id FOREIGN KEY (contact_id) REFERENCES STAFF(staff_id)
);
Use table aliases:
select *
from RISK r
LEFT OUTER JOIN STAFF o ON r.owner_id = o.staff_id
LEFT OUTER JOIN STAFF c ON r.contact_id = c.staff_id
You were close. You need to create a table with data from both tables using a join, in this case joining on fk:
CREATE VIEW public_view AS
SELECT r.risk_id, r.risk_name s.staff_name
FROM risk r
LEFT JOIN staff s
ON r.owner_id = s.staff_id;
Left join will not pull data that is in Staff table but not in Risk table.
This is what I ended up doing
CREATE VIEW public_view1 (risk_id, risk_name, owner_name, contact_name) AS
SELECT r.risk_id, r.risk_name, o.staff_name, c.staff_name
FROM risk r
LEFT OUTER JOIN staff o ON r.owner_id = o.staff_id
LEFT OUTER JOIN staff c ON r.contact_id = c.staff_id;

SQLite3 INNER JOIN with 3 tables

I'm trying to select from 3 tables with an INNER JOIN:
The tables:
CREATE TABLE tracks (
'track_id' INTEGER PRIMARY KEY NOT NULL,
'name' TEXT NOT NULL,
'length' REAL DEFAULT '0.00',
'city' TEXT
);
CREATE TABLE heats (
'heat_id' INTEGER PRIMARY KEY NOT NULL,
'track_id' INTEGER UNSIGNED NOT NULL,
'heat_pos' INTEGER UNSIGNED NOT NULL,
'day_pos' INTEGER UNSIGNED NOT NULL,
'type' TEXT NOT NULL DEFAULT 'training',
'average' REAL,
'date' TEXT,
'comment' TEXT,
FOREIGN KEY ('track_id') REFERENCES tracks ('track_id')
);
CREATE TABLE laps (
'lap_id' INTEGER PRIMARY KEY NOT NULL,
'heat_id' INTEGER UNSIGNED NOT NULL,
'laptime' REAL UNSIGNED NOT NULL,
FOREIGN KEY ('heat_id') REFERENCES heats ('heat_id')
);
When selecting information from 2 tables (laps and heats) it works like I expected:
select
laps.lap_id,
laps.laptime,
heats.heat_pos
from laps
inner join heats on laps.heat_id = heats.heat_id;
But now I want to select the corresponding tracknames from the track table:
select
laps.lap_id,
laps.laptime,
heats.heat_pos,
tracks.name
from laps, tracks, heats
inner join heats on laps.heat_id = heats.heat_id and
inner join heats on tracks.track_id = heats.track_id;
This gives me the following error:
ambiguous column name: heats.heat_pos
I'm completely lost, but I have a feeling it's just a small mistake.
Anyone knows what I'm doing wrong?
select
laps.lap_id,
laps.laptime,
heats.heat_pos,
tracks.name
from laps
inner join heats on laps.heat_id = heats.heat_id
inner join tracks on tracks.track_id = heats.track_id;
select
laps.lap_id,
laps.laptime,
heats.heat_pos,
tracks.name
from laps
inner join heats on laps.heat_id = heats.heat_id
inner join heats on tracks.track_id = heats.track_id
ORDER BY laps.lap_id