I am trying to do a three table join to display all columns. Only two of the tables have a key in common. Below is the code for the tables I already have:
CREATE TABLE Faculty (
FacultyID int,
FirstName varchar(30),
LastName varchar(30),
EMail varchar(60),
BirthDate DATE,
Numbr_Courses int,
PRIMARY KEY (FacultyID)
);
CREATE TABLE Courses(
CourseID int,
CourseDisc varchar(4),
CourseNum varchar(4),
NumbrCred varchar(1),
FirstYrOffered int,
CourseTitle varchar(75),
PRIMARY KEY (CourseID)
);
CREATE TABLE Faculty_Courses(
InstanceID int,
FacultyID int,
CourseDisc varchar(4),
CourseNum varchar(4),
CourseTitle varchar(75),
PRIMARY KEY (InstanceID),
FOREIGN KEY (FacultyID) REFERENCES Faculty(FacultyID)
);
The two tables that have the same key is Faculty and Faculty_Course. I have attempted one peice of code that only gave me back an error. I guess I am having real trouble understanding how to do proper code for joining tables. My attempted code is below:
SELECT Faculty.*, Faculty_Courses.*
FROM Faculty INNER JOIN Courses
ON Faculty.FacultyID=Faculty_Courses.FacultyID
This gave me back the following error:
ERROR 1066 (42000): Not unique table/alias: 'Faculty'
Any help will be appreciated.
I would change your Faculty_Courses table:
CREATE TABLE Faculty_Courses(
InstanceID int,
FacultyID int,
CourseID int,
PRIMARY KEY (InstanceID),
FOREIGN KEY (FacultyID) REFERENCES Faculty(FacultyID),
FOREIGN KEY (CourseID) REFERENCES Courses(CourseID)
);
And then join all three tables together:
SELECT F.*, FC.*, C.*
FROM Faculty F
INNER JOIN Faculty_Courses FC ON F.FacultyID = FC.FacultyID
INNER JOIN Courses C ON C.CourseID = FC.CourseID
You probably only really want some of the columns from F (Faculty) and C (Courses) and can mostly ignore the FC columns as they are just used for mapping between F and C
I'm surprised your factory_courses table doesn't have a reference to courses.
Either way, with your current query, you are selecting from faculty and courses but aliasing faculty_courses -- you cannot do that. This is what your current query should look like:
select *
from faculty f
join faculty_courses fc on f.facultyid = fc.facultyid
To join the 3rd table, if you had a courseid in your faculty_courses table, perhaps something like this:
select *
from faculty f
join faculty_courses fc on f.facultyid = fc.facultyid
join courses c on fc.courseid = c.courseid
A Visual Explanation of SQL Joins
You're doing a join on two tables without actually linking two columns from those tables; joining Faculty and Courses using columns from Faculty and Faculty_Courses.
Since no column exists with unique values linking Courses with any other table, you cannot perform a join with Courses.
So you should join Faculty and Faculty_courses:
SELECT Faculty.*, Faculty_Courses.*
FROM Faculty INNER JOIN Faculty_Courses
ON Faculty.FacultyID=Faculty_Courses.FacultyID
Related
I am new to SQL and am trying to teach myself different aspects of Oracle as a side interest. While working on a project, it asks to create a view based on the input data from other tables. How would this normally look?
I currently have four tables:
CREATE TABLE Engineers (
EID Integer Primary Key,
LastName varchar(25),
FirstName varchar(25),
Email varchar(255),
Graddate date
);
CREATE TABLE Faculty (
FID Integer Primary Key,
LastName varchar(25),
FirstName varchar(25),
Email varchar(255),
Hiredate date
);
CREATE TABLE Classes (
CID Integer Primary Key,
Subject varchar(6),
Catalognbr varchar(6),
Title varchar(120)
);
CREATE TABLE ClassEnrollments (
EnID Integer Primary Key,
CID Integer,
FID Integer,
EID Integer,
FOREIGN KEY (CID) REFERENCES CLASSES(CID),
FOREIGN KEY (FID) REFERENCES FACULTY(FID),
FOREIGN KEY (EID) REFERENCES ENGINEERS(EID)
);
I am trying to make a view that contains the first and last name of the engineer, last name and email of the faculty member and the subject of a class for a set of inserted data into the ClassEnrollment table which looks like:
INSERT INTO ClassEnrollments
(EnID, CID, FID, EID)
Values (EnID_inc.NEXTVAL, 1, 1, 4);
What I have tried to do was:
CREATE VIEW Testers AS
SELECT e.Lastname, e.Firstname, f.Lastname, f.Email, c.Subject, c.title, en.EnID
FROM Engineers e, Faculty f, Classes c, ClassEnrollments en
WHERE e.EID = en.EID AND f.FID = en.FID AND c.CID = en.CID
ORDER By en.ENID;
However, with this I get a duplicate column name error.
Well, you are not allowed to have duplicate column names in the view. You can use the AS to rename the duplicate columns.
CREATE VIEW Testers AS
SELECT e.Lastname as EngLastname, EngFirstname as FacLastname, f.Lastname as fac_lastname, f.Email, c.Subject, c.title, en.EnID
FROM Engineers e, Faculty f, Classes c, ClassEnrollments en
WHERE e.EID = en.EID AND f.FID = en.FID AND c.CID = en.CID
ORDER By en.ENID;
Your base query would look better if you use a JOIN clause:
SELECT e.Lastname as EngLastname
,e.Firstname as EngFirstname
,f.Lastname as FacLastname
,f.Email
,c.Subject
,c.title
,en.EnID
FROM Engineers e
JOIN Faculty f
ON Faculty.FID = ClassEnrollments.FID
JOIN Classes C
ClassEnrollments.CID = Classes.CID
JOIN ClassEnrollments en
ON ClassEnrollments.EID = Engineers.EID
I'm currently taking a database class and I am stuck on a homework problem due tonight
Find the courses given in the ‘Sloan’ building which have enrolled more students than their enrollment limit. Return the courseno, enroll_limit, and the actual enrollment for those courses.
I'm stuck trying to count how many students are in each course.
CREATE TABLE Course (
courseno VARCHAR(7),
credits INTEGER NOT NULL,
enroll_limit INTEGER,
classroom VARCHAR(10),
PRIMARY KEY(courseNo), );
CREATE TABLE Student (
sID CHAR(8),
sName VARCHAR(30),
major VARCHAR(10),
trackcode VARCHAR(10),
PRIMARY KEY(sID),
FOREIGN KEY (major,trackcode) REFERENCES Tracks(major,trackcode) );
CREATE TABLE Enroll (
courseno VARCHAR(7),
sID CHAR(8),
grade FLOAT NOT NULL,
PRIMARY KEY (courseNo, sID),
FOREIGN KEY (courseNo) REFERENCES Course(courseNo),
FOREIGN KEY (sID) REFERENCES Student(sID) );
My current very broken attempt is
SELECT sloancourse.courseno
FROM course sloancourse
WHERE
sloancourse.classroom = 'Sloan'
and sloancourse.courseno IN (
SELECT c.courseno
FROM student s, enroll e, course c
WHERE
c.courseno = e.courseno
and s.sid = e.sid
and sloancourse.courseno = c.courseno
)
;
Find the courses given in the ‘Sloan’ building which have enrolled more students than their enrollment limit. Return the courseno, enroll_limit, and the actual enrollment for those courses.
You would typically join courses and enrollment (using stanard join syntax, with the on keyword), group by course, and finally filter on courses whose student count with a having clause.
select
c.courseno,
c.enroll_limit,
count(*) actual_enrollment
from course c
inner join enroll e on e.courseno= c.courseno
where c.classroom = 'Sloan'
group by c.courseno, c.enroll_limit
having count(*) > c.enroll_limit
Note that you don't need to bring in the student table to get the desired results.
You could try something like this:
SELECT
Course.courseno,
Course.enroll_limit,
Couse.classroom
FROM Course, Enroll
WHERE Course.courseno = Enroll.courseno
AND Course.classroom = 'Sloan'
GROUP BY Course.courseno
HAVING count(*) > Course.enroll_limit
Postgres docs have an example on these aggregate functions: https://www.postgresql.org/docs/current/tutorial-agg.html
Basically, when you group by one or multiple properties, the resulting table will result in a unique row for the property/combination of properties. In this example, you would have one row for each of the courseno unique values (as they are grouped by this value).
I have the following tables:
CREATE TABLE Subject
(
Subject_Code INTEGER,
Subject_Year VARCHAR (8),
PRIMARY KEY (Subject_Code, Subject_Year),
Teacher_ID INTEGER REFERENCES
);
CREATE TABLE Teacher
(
TeacherID INTEGER PRIMARY KEY,
FirstName TEXT,
Department_ID INTEGER References Academic Department(Department_ID)
);
CREATE TABLE Subject-taken
(
Marks_Obtained INTEGER,
Subject_Code INTEGER REFERENCES subject (Subject_Code),
Candidate_ID INTEGER REFERENCES Candidate (Candidate_ID),
PRIMARY KEY (Subject_Code, Candidate_ID)
);
CREATE TABLE Academic_Department
(
Department_ID INTEGER PRIMARY KEY,
Department_Name TEXT
);
I've already tried the following select statement
SELECT m.subject_code,
MIN (marks_obtained) AS Min_Marks,
MAX (marks_obtained) AS Max_Marks
FROM Subject-taken m, Subject a
GROUP BY m.Subject_Code;
Want to use the join function any suggestions on where to use it in order to join the departments with subjects and students
Make use of joins to link your data between tables. Use group by to make statistics by some fields. You can try something like this:
SELECT
Subjects.Subject_Code,
Subjects.Subject_Name,
Teachers.TeacherID,
Academic_Department.Department_ID,
min(Subject-taken.Marks_Obtained) as min_marks,
max(Subject-taken.Marks_Obtained) as max_marks,
avg(Subject-taken.Marks_Obtained) as avg_marks,
stddev_samp(subject-taken.Marks_Obtained) as stddev_marks
FROM
Subjects LEFT JOIN
Teachers ON Subjects.TeacherID = Subjects.TeacherID LEFT JOIN
Academic_Department ON Teachers.Department_ID = Academic_Department.Department_ID LEFT JOIN
Subject-taken ON Subjects.Subject_Code = Subject-taken.Subject_Code
GROUP BY
Subjects.Subject_Code,
Subject.Subject_Name,
Teacher.TeacherID,
Academic_Department.Department_ID
I don't really know if stddev_samp is the aggregate function you need, stddev_pop is also available. Please refer to this PostgreSQL documentation table to find out.
I want to SELECT STAFF_ID, STAFF_NAME and PROJECT_ID. STAFF_ID and PROJECT_ID are linked in a table ASSIGNMENTS, but I want to show that link while also showing the STAFF_NAME for each STAFF_ID from the STAFF table. Here is my code:
CREATE TABLE PROJECT
(PROJECT_ID CHAR(5) NOT NULL,
PROJECT_NAME CHAR(20),
PROJECT_TYPE CHAR(20),
START_DATE DATE,
END_DATE DATE,
PRIMARY KEY (PROJECT_ID));
CREATE TABLE STAFF
(STAFF_ID CHAR(5) NOT NULL,
STAFF_NAME CHAR(20),
JOB_TYPE CHAR(20),
JOB_GRADE CHAR(20),
PRIMARY KEY (STAFF_ID));
CREATE TABLE ASSIGNMENTS
(ASSIGNMENT_ID CHAR(5) NOT NULL,
PROJECT_ID CHAR(5),
STAFF_ID CHAR(5),
PRIMARY KEY (ASSIGNMENT_ID),
FOREIGN KEY (PROJECT_ID) REFERENCES PROJECT(PROJECT_ID),
FOREIGN KEY (STAFF_ID) REFERENCES STAFF(STAFF_ID));
All the tables have been populated with data, and this is the query I've used so far which shows which employees work on a given project (but only with STAFF_ID, not with STAFF_NAME included):
SELECT STAFF_ID, PROJECT_ID
FROM ASSIGNMENTS
WHERE PROJECT_ID = 'B0005';
How can I show the links like this while also including the STAFF_NAME linked to the STAFF_ID from the STAFF table?
Here is some data for a row of each table:
INSERT INTO PROJECT (PROJECT_ID, PROJECT_NAME, PROJECT_TYPE, START_DATE, END_DATE)
VALUES ('B0001','BIKESHOP.COM','WEB DEVELOPMENT',TO_DATE('15/01/17','DD/MM/YY'),TO_DATE('15/02/17','DD/MM/YY'));
INSERT INTO STAFF (STAFF_ID, STAFF_NAME, JOB_TYPE, JOB_GRADE)
VALUES ('ST001','JOHN MASON','WEB DEVELOPER','1');
INSERT INTO ASSIGNMENTS (ASSIGNMENT_ID, PROJECT_ID, STAFF_ID, HARDWARE_ID, SOFTWARE_ID)
VALUES ('A0001','B0001','ST001','H0001','S0001');
What I want to show is PROJECT_ID, STAFF_ID, STAFF_NAME. Just three columns showing those 3 values.
You just need to add join to STAFF table. Something like this
SELECT STAFF.STAFF_ID, STAFF.STAFF_NAME, ASSIGNMENTS.PROJECT_ID
FROM ASSIGNMENTS
INNER JOIN STAFF ON ASSIGNMENTS.STAFF_ID = STAFF.STAFF_ID
WHERE ASSIGNMENTS.PROJECT_ID = 'B0005';
i think this select can solve your problem
select PROJECT_ID, STAFF_ID, STAFF_NAME from ASSIGNMENTS
inner join STAFF on STAFF.STAFF_ID=ASSIGNMENTS.STAFF_ID
For achieving this need, Join the three tables as next approach:
Generic Syntax:
select *
from
tableA a
inner join
tableB b
on a.common = b.common
inner join
TableC c
on b.common = c.common
so follow the next query:
select a.PROJECT_ID, b.STAFF_ID, c.STAFF_NAME
from PROJECT a inner join ASSIGNMENTS b
on a.PROJECT_ID = b.PROJECT_ID
inner join STAFF c
on c.STAFF_ID = b.STAFF_ID
Result:
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;