A join retrieve null column - sql

I have 2 tabels
create table Students(
SerialNumber int primary key identity,
Name varchar(50) not null,
Surname varchar(50) not null,
AcademicProgram int foreign key references AcademicProgrammes(Id)
)
Create table AcademicProgrammes(
Id int primary key identity,
Name varchar (20) not null
)
and I want to get from students table all the students, but instead the AcademicProgram reference foreign key I want the name of the AcademicProgrammes.
my join looks like this :
select Students.SerialNumber,Students.Name, Students.Surname, AcademicProgrammes.Name
from Students left join
AcademicProgrammes on Students.SerialNumber=AcademicProgrammes.Id
if i have 2 academic programs master's and undergraduate
as a result I get all ste students but as the academic program name column only the first 2 students have the name of de academic program, and the rest of them have null
Vasile Magdalena-Maria Licenta
Ciotmonda Oana-Maria Master
Rus Diana NULL
Turcu Gabriel NULL
I can't find what I'm doing wrong
Thanks !

I believe you need to join by
Students.AcademicProgram=AcademicProgrammes.Id
instead of
Students.SerialNumber=AcademicProgrammes.Id
Because of that you're getting names of academic programs for only students with serial numbers 1 and 2 (since you have only two programs).
Therefore try following
SELECT s.SerialNumber,
s.Name,
s.Surname,
a.Name AS Program
FROM Students s LEFT JOIN
AcademicProgrammes a ON s.AcademicProgram=a.Id

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

I need to create a view that pre-joins the three tables, including all of the records from student and course tables ( shown below) [duplicate]

This question already has answers here:
Error report - ORA-25155: column used in NATURAL join cannot have qualifier 25155. 00000 - "column used in NATURAL join cannot have qualifier"
(2 answers)
Closed 2 years ago.
-- I am trying to create a view for the tables shown below but my attempt is not successfull. I am using Oracle SQL Developer!! Where is the mistake here
CREATE VIEW student_view AS
SELECT Student.*, Course.*, Grade.* FROM (Student NATURAL LEFT OUTER JOIN Grade NATURAL LEFT OUTER JOIN Course)
UNION ALL
SELECT Student.*, Course.*, Grade.* FROM (Course NATURAL LEFT OUTER JOIN Grade NATURAL LEFT OUTER JOIN Student) WHERE Student.StudentID is NULL
;
CREATE TABLE Student(
StudentID INT PRIMARY KEY NOT NULL,
Name CHAR(50),
Address CHAR(50),
GradYear INT
);
-- create table Grade
CREATE TABLE Grade(
CName CHAR(50) NOT NULL,
StudentID INT NOT NULL,
CGrade CHAR(2),
PRIMARY KEY(CName, StudentID)
);
-- create table Course
CREATE TABLE Course(
CName CHAR(50) PRIMARY KEY NOT NULL,
Department CHAR(50),
Credits INT
);
You should create the underlying tables before composing them into a view.
Please follow below sequence,
CREATE TABLE Student(
StudentID INT PRIMARY KEY NOT NULL,
Name CHAR(50),
Address CHAR(50),
GradYear INT
);
-- create table Grade
CREATE TABLE Grade(
CName CHAR(50) NOT NULL,
StudentID INT NOT NULL,
CGrade CHAR(2),
PRIMARY KEY(CName, StudentID)
);
-- create table Course
CREATE TABLE Course(
CName CHAR(50) PRIMARY KEY NOT NULL,
Department CHAR(50),
Credits INT
);
CREATE VIEW student_view AS
SELECT Student.StudentID , Student.Name, Student.Address, Student.GradYear,
Course.CName, Course.CGrade, Grade.Department, Grade.Credits FROM Student
LEFT OUTER JOIN Grade
on (Student.StudentID = Grade.StudentID)
LEFT OUTER JOIN Course
on (Grade.CName = Course.CName);
Corrected version:
Defined tables in the right order
Changed CHAR to VARCHAR2
Added foreign key constraints (inheriting data types)
Removed table aliases not allowed by NATURAL JOIN syntax
Removed redundant brackets from view.
Tables:
create table student
( studentid integer primary key not null
, name varchar2(50) not null
, address varchar2(50)
, gradyear integer );
create table course
( cname varchar2(50) primary key not null
, department varchar2(50)
, credits integer );
create table grade
( cname references course not null
, studentid references student not null
, cgrade varchar2(2) not null
, primary key(cname, studentid) );
View:
create or replace view student_view as
select studentid, name, address, gradyear
, cname, department, credits
, cgrade
from student
natural left outer join grade
natural left outer join course
union all
select studentid, name, address, gradyear
, cname, department, credits
, cgrade
from course
natural left outer join grade
natural left outer join student
where studentid is null;
And just to add, NATURAL JOIN is never a good idea in real code.

SQL Find all courses who have more students enrolled then the allowed enroll_limit for the course

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).

Multi-table, multi-row SQL select

How would I list all of the info about a freelancer given the schema below? Including niche, language, market, etc. The issue I am having is that every freelancer can have multiple entries for each table. So, how would I do this? Is it even possible using SQL or would I need to use my primary language (golang) for this?
CREATE TABLE freelancer (
freelancer_id SERIAL PRIMARY KEY,
ip inet NOT NULL,
username VARCHAR(20) NOT NULL,
password VARCHAR(100) NOT NULL,
email citext NOT NULL UNIQUE,
email_verified int NOT NULL,
fname VARCHAR(20) NOT NULL,
lname VARCHAR(20) NOT NULL,
phone_number VARCHAR(30) NOT NULL,
address VARCHAR(50) NOT NULL,
city VARCHAR(30) NOT NULL,
state VARCHAR(30) NOT NULL,
zip int NOT NULL,
country VARCHAR(30) NOT NULL,
);
CREATE TABLE market (
market_id SERIAL PRIMARY KEY,
market_name VARCHAR(30) NOT NULL,
);
CREATE TABLE niche (
niche_id SERIAL PRIMARY KEY,
niche_name VARCHAR(30) NOT NULL,
);
CREATE TABLE medium (
medium_id SERIAL PRIMARY KEY,
medium_name VARCHAR(30) NOT NULL,
);
CREATE TABLE format (
format_id SERIAL PRIMARY KEY,
format_name VARCHAR(30) NOT NULL,
);
CREATE TABLE lang (
lang_id SERIAL PRIMARY KEY,
lang_name VARCHAR(30) NOT NULL,
);
CREATE TABLE freelancer_by_niche (
id SERIAL PRIMARY KEY,
niche_id int NOT NULL REFERENCES niche (niche_id),
freelancer_id int NOT NULL REFERENCES freelancer (freelancer_id)
);
CREATE TABLE freelancer_by_medium (
id SERIAL PRIMARY KEY,
medium_id int NOT NULL REFERENCES medium (medium_id),
freelancer_id int NOT NULL REFERENCES freelancer (freelancer_id)
);
CREATE TABLE freelancer_by_market (
id SERIAL PRIMARY KEY,
market_id int NOT NULL REFERENCES market (market_id),
freelancer_id int NOT NULL REFERENCES freelancer (freelancer_id)
);
CREATE TABLE freelancer_by_format (
id SERIAL PRIMARY KEY,
format_id int NOT NULL REFERENCES format (format_id),
freelancer_id int NOT NULL REFERENCES freelancer (freelancer_id)
);
CREATE TABLE freelancer_by_lang (
id SERIAL PRIMARY KEY,
lang_id int NOT NULL REFERENCES lang (lang_id),
freelancer_id int NOT NULL REFERENCES freelancer (freelancer_id)
);
SELECT *
FROM freelancer
INNER JOIN freelancer_by_niche USING (freelancer_id)
INNER JOIN niche USING (niche_id)
INNER JOIN freelancer_by_medium USING (freelancer_id)
INNER JOIN medium USING (medium_id)
INNER JOIN freelancer_by_market USING (freelancer_id)
INNER JOIN market USING (market_id)
INNER JOIN freelancer_by_format USING (freelancer_id)
INNER JOIN format USING (format_id)
INNER JOIN freelancer_by_lang USING (freelancer_id)
INNER JOIN lang USING (lang_id);
And if you want to lose the unnecessary attributes from join tables like freelancer_by_format, then you can do this
SELECT a.ip, a.username, a.password, a.email, a.email_verified,
a.fname, a.lname, a.phone_number, a.address, a.city,
a.state, a.zip, a.country,
b.niche_name, c.medium_name, d.market_name, e.format_name, f.lang_name
FROM freelancer a
INNER JOIN freelancer_by_niche USING (freelancer_id)
INNER JOIN niche b USING (niche_id)
INNER JOIN freelancer_by_medium USING (freelancer_id)
INNER JOIN medium c USING (medium_id)
INNER JOIN freelancer_by_market USING (freelancer_id)
INNER JOIN market d USING (market_id)
INNER JOIN freelancer_by_format USING (freelancer_id)
INNER JOIN format e USING (format_id)
INNER JOIN freelancer_by_lang USING (freelancer_id)
INNER JOIN lang f USING (lang_id);
And if you want to change the column names, for example change "market_name" to just "market", then you go with
SELECT a.ip, ... ,
d.market_name "market", e.format_name AS "format", ...
FROM ...
Remarks
In your join tables (for example freelancer_by_niche) there is not UNIQUE constraint on freelancer_id, which means that you could have the same freelancer in multiple markets (that's ok and probably intended).
But then you also don't have a UNIQUE constraint on both attributes (freelancer_id, niche_id), which means that every freelancer could be in the SAME niche multiple times. ("Joe is in electronics. Three times").
You could prevent that by making (freelancer_id, niche_id) UNIQUE in freelancer_by_niche.
This way you would also not need a surrogate (artificial) PRIMARY KEY freelancer_by_id (id).
So what could go wrong then?
For example imagine the same information about a freelancer in the same niche three times (the same data parts of the row three times):
freelancer_by_niche
id | freelancer_id | niche_id
1 | 1 | 1 -- <-- same data (1, 1), different serial id
2 | 1 | 1 -- <-- same data (1, 1), different serial id
3 | 1 | 1 -- <-- same data (1, 1), different serial id
Then the result of the above query would return each possible row three (!) times with the same (!) content, because freelancer_by_niche can be combined three times with all the other JOINs.
You can eliminate duplicates by using SELECT DISTINCT a.id, ... FROM ... above with DISTINCT.
What if you get many duplicate rows, for example 10 data duplicates in each of the 5 JOIN tables (freelancer_by_niche, freelancer_by_medium etc)? You would get 10 * 10 * 10 * 10 * 10 = 10 ^ 5 = 100000 duplicates, which all have the exact same information.
If you then ask your DBMS to eliminate duplicates with SELECT DISTINCT ... then it has to sort 100000 duplicate rows per different row, because duplicates can be detected by sorting only (or hashing, but never mind). If you have 1000 different rows for freelancers on markets, niches, languages etc, then you are asking your DBMS to SORT 1.000 * 100.000 = 100.000.000 rows to reduce the duplicates down to the unique 1000 rows.
That is 100 million unnecessary rows.
Please make UNIQUE (freelancer_id, niche_id) for freelancer_by_niche and the other JOIN tables.
(By data duplicates i mean that the data (niche_id, freelancer_id) is the same, and only the id is auto incremented serial.)
You can easily reproduce the problem by doing the following:
-- this duplicates all data of your JOIN tables once. Do it many times.
INSERT INTO freelancer_by_niche
SELECT (niche_id, freelancer_id) FROM freelancer_by_niche;
INSERT INTO freelancer_by_medium
SELECT (medium_id, freelancer_id) FROM freelancer_by_medium;
INSERT INTO freelancer_by_market
SELECT (market_id, freelancer_id) FROM freelancer_by_market;
INSERT INTO freelancer_by_format
SELECT (format_id, freelancer_id) FROM freelancer_by_format;
INSERT INTO freelancer_by_lang
SELECT (lang_id, freelancer_id) FROM freelancer_by_lang;
Display the duplicates using
SELECT * FROM freelancer_by_lang;
Now try the SELECT * FROM freelancer INNER JOIN ... thing.
If it still runs fast, then do all the INSERT INTO freelancer_by_niche ... again and again, until it takes forever to calculate the results.
(or you get duplicates, which you can remove with DISTINCT).
Create UNIQUE data JOIN tables
You can prevent duplicates in your join tables.
Remove the id SERIAL PRIMARY KEY and replace it with a multi-attribute PRIMARY KEY (a, b):
CREATE TABLE freelancer_by_niche (
niche_id int NOT NULL REFERENCES niche (niche_id),
freelancer_id int NOT NULL REFERENCES freelancer (freelancer_id),
PRIMARY KEY (freelancer_id, niche_id)
);
(Apply this for all your join tables).
The PRIMARY KEY (freelancer_id, niche_id) will create a UNIQUE index.
This way you cannot insert duplicate data (try the INSERTs above, the will be rejected, because the information is already there once. Adding another time will not add more information AND would make your query runtime much slower).
NON-unique index on the other part of the JOIN tables
With PRIMARY KEY (freelancer_id, niche_id), Postgres creates a unique index on these two attributes (columns).
Accessing or JOINing by freelancer_id is fast, because it's first in the index. Accessing or JOINing into freelancer_by_niche.niche_id will be slow (Full Table Scan on freelancer_by_niche).
Therefore you should create an INDEX on the second part niche_id in this table freelancer_by_niche, too.
CREATE INDEX ON freelancer_by_niche (niche_id) ;
Then joins into this table on niche_id will also be faster, because they are accelerated by an index. The index makes queries faster (usually).
Summary
You have a very good normalized database schema! It's very good. But small improvements can be made (see above).

SELECT value from a second level foreign key table

Greetings fellow Earthlings,
I have a problem. Let me start by laying out my table structure:
CREATE TABLE Person
(
id varchar(50) NOT NULL PRIMARY KEY,
name varchar(50) NOT NULL,
adress varchar(50) NOT NULL references Adress(id)
)
CREATE TABLE Adress
(
id varchar(50) NOT NULL PRIMARY KEY,
addressName varchar(50),
city varchar(50),
aState varchar(50),
linkToCountry varchar(50) references Country(id)
)
CREATE TABLE Country
(
id varchar(50) NOT NULL PRIMARY KEY,
countryName varchar(50)
)
What I want to achieve is: select a person 'name' along with their 'addressName' and the 'countryName' they're from.
I know that this is a joining related issue but I can't seem to figure this one out.
So any help from people who are well versed on SQL?
Would appreciate it very very much any one has links to advance sql joining so I can familiarize myself with it.
You can get the result using simple join as below. This will retrun the person name with address name, and country name. However it returns only those person names which has an address record in the address table and country record in the country table. If you want to retrieve all the persons irrespective of whether address/country exists or not, you need to use left join.
SELECT Person.Name, Address.addressname,Country.countryName
FROM Person
JOIN Address on Person.address = Address.Id
JOIN Country ON Address.linkToCountry = Country.id
Try this:
SELECT p.name, a.addressName, c.countryName
FROM Person p
INNER JOIN Adress a ON p.adress = a.id
LEFT OUTER JOIN Country c ON a.linkToCountry = c.id