What is wrong with this JOIN statement in SQL? - sql

I am working on this tutorial about SQL. In Step 2 of 2, it is asked to use the JOIN command to link 2 people from the persons list using information from the friends list. I edited the provided code and obtained the code included below: the relevant part starts with select persons.fullname, persons2.fullname. However, the last paragraph of the code ('relevant code') does not yield any result nor error message. Am I doing something wrong?
Code
CREATE TABLE persons (
id INTEGER PRIMARY KEY AUTOINCREMENT,
fullname TEXT,
age INTEGER);
INSERT INTO persons (fullname, age) VALUES ("Bobby McBobbyFace", "12");
INSERT INTO persons (fullname, age) VALUES ("Lucy BoBucie", "25");
INSERT INTO persons (fullname, age) VALUES ("Banana FoFanna", "14");
INSERT INTO persons (fullname, age) VALUES ("Shish Kabob", "20");
INSERT INTO persons (fullname, age) VALUES ("Fluffy Sparkles", "8");
CREATE table hobbies (
id INTEGER PRIMARY KEY AUTOINCREMENT,
person_id INTEGER,
name TEXT);
INSERT INTO hobbies (person_id, name) VALUES (1, "drawing");
INSERT INTO hobbies (person_id, name) VALUES (1, "coding");
INSERT INTO hobbies (person_id, name) VALUES (2, "dancing");
INSERT INTO hobbies (person_id, name) VALUES (2, "coding");
INSERT INTO hobbies (person_id, name) VALUES (3, "skating");
INSERT INTO hobbies (person_id, name) VALUES (3, "rowing");
INSERT INTO hobbies (person_id, name) VALUES (3, "drawing");
INSERT INTO hobbies (person_id, name) VALUES (4, "coding");
INSERT INTO hobbies (person_id, name) VALUES (4, "dilly-dallying");
INSERT INTO hobbies (person_id, name) VALUES (4, "meowing");
CREATE table friends (
id INTEGER PRIMARY KEY AUTOINCREMENT,
person1_id INTEGER,
person2_id INTEGER);
INSERT INTO friends (person1_id, person2_id)
VALUES (1, 4);
INSERT INTO friends (person1_id, person2_id)
VALUES (2, 3);
/* personal contribution starts here
select persons.fullname,hobbies.name
from persons
join hobbies
on hobbies.person_id=persons.id;
/* select persons.fullname, persons2.fullname
from persons
join persons persons2
join friends
on persons.fullname=friends.person1_id and persons2.fullname=friends.person2_id; */
/* relevant code: */
select persons.fullname, persons2.fullname
from persons
join friends
on persons.fullname=friends.person1_id
join persons persons2
on persons2.fullname=friends.person2_id;
[tutorial (c) khanacademy.org]

join friends
on persons.fullname=friends.person1_id
You're only including friends whose person1_id equals a person's fullname. Since person1_id is an integer and fullname is text, those will never be equal. You probably want:
select persons.fullname, persons2.fullname
from persons
join friends
on persons.id=friends.person1_id
join persons persons2
on persons2.id=friends.person2_id;

Related

Query to find name of parents with age of youngest child

I have a table as such:
CREATE TABLE people
(
id INTEGER NOT NULL PRIMARY KEY,
motherId INTEGER,
fatherId INTEGER,
name VARCHAR(30) NOT NULL,
age INTEGER NOT NULL,
FOREIGN KEY (motherId) REFERENCES people(id),
FOREIGN KEY (fatherId) REFERENCES people(id)
);
INSERT INTO people(id, motherId, fatherId, name, age)
VALUES (1, NULL, NULL, 'Adam', 50);
INSERT INTO people(id, motherId, fatherId, name, age)
VALUES (2, NULL, NULL, 'Eve', 50);
INSERT INTO people(id, motherId, fatherId, name, age)
VALUES (3, 2, 1, 'Cain', 30);
INSERT INTO people(id, motherId, fatherId, name, age)
VALUES (4, 2, 1, 'Seth', 20);
I would like to write a query and get the name of the parents and the age of their youngest children. Not sure how to go about with this problem.
Expected output:
-- Expected output (in any order):
-- name age
-- ----------------------------
-- Adam 20
-- Eve 20
SELECT P1.name, P2.name, T.minAge
FROM (SELECT P.motherId, P.fatherId, MIN(AGE) AS minAge
FROM people P
GROUP BY P.motherId, P.fatherId) AS T JOIN people P1 ON T.motherId=P1.id
JOIN people P2 ON T.fatherId=P2.id
db<>fiddle

While combining tables, how to make a column distinct when it has multiple entries?

I'm trying to display course numbers from table student_enrollment and student names from table students, based on a distinct last_name from table professors. For example, there is a professor named "Wilson" - I would like to only display the courses Wilson's teaching and the students that are enrolled in these classes.
What I have so far is the following, which displays the unique course numbers that each student is enrolled in but does not take into consideration of professors.last_name:
SELECT students.student_name, student_enrollment.course_no
FROM students, student_enrollment, teach
WHERE students.student_no=student_enrollment.student_no
AND student_enrollment.course_no=teach.course_no
GROUP BY student_name,student_enrollment.course_no
Please see the four queried tables (students, student_enrollment, teach, professors) below for more information:
create table students
(
student_no integer,
student_name varchar(20),
age integer
);
insert into students values (1, 'Harpreet', 19);
insert into students values (2, 'Doug', 18);
insert into students values (3, 'Abdul', 21);
insert into students values (4, 'Mohammad', 20);
insert into students values (5, 'Ralph', 19);
insert into students values (6, 'Prateek', 22);
insert into students values (7, 'Michael', 19);
insert into students values (8, 'Jack', 19);
insert into students values (9, 'Chin', 17);
insert into students values (10, '', 20);
create table courses
(
course_no varchar(5),
course_title varchar(20),
credits integer
);
insert into courses values ('CS110', 'Pre Calculus', 4);
insert into courses values ('CS180', 'Physics', 4);
insert into courses values ('CS107', 'Intro to Psychology', 3);
insert into courses values ('CS210', 'Art History', 3);
insert into courses values ('CS220', 'US History', 3);
create table student_enrollment
(
student_no integer,
course_no varchar(5)
);
insert into student_enrollment values (1, 'CS110');
insert into student_enrollment values (1, 'CS180');
insert into student_enrollment values (1, 'CS210');
insert into student_enrollment values (2, 'CS107');
insert into student_enrollment values (2, 'CS220');
insert into student_enrollment values (3, 'CS110');
insert into student_enrollment values (3, 'CS180');
insert into student_enrollment values (4, 'CS220');
insert into student_enrollment values (5, 'CS110');
insert into student_enrollment values (5, 'CS180');
insert into student_enrollment values (5, 'CS210');
insert into student_enrollment values (5, 'CS220');
insert into student_enrollment values (6, 'CS110');
insert into student_enrollment values (7, 'CS110');
insert into student_enrollment values (7, 'CS210');
create table professors
(
last_name varchar(20),
department varchar(12),
salary integer,
hire_date date
);
insert into professors values ('Chong', 'Science', 88000, '2006-04-18');
insert into professors values ('Brown', 'Math', 97000, '2002-08-22');
insert into professors values ('Jones', 'History', 67000, '2009-11-17');
insert into professors values ('Wilson', 'Astronomy', 110000, '2005-01-15');
insert into professors values ('Miller', 'Agriculture', 82000, '2008-05-08');
insert into professors values ('Williams', 'Law', 105000, '2001-06-05');
create table teach
(
last_name varchar(20),
course_no varchar(5)
);
insert into teach values ('Chong', 'CS180');
insert into teach values ('Brown', 'CS110');
insert into teach values ('Brown', 'CS180');
insert into teach values ('Jones', 'CS210');
insert into teach values ('Jones', 'CS220');
insert into teach values ('Wilson', 'CS110');
insert into teach values ('Wilson', 'CS180');
insert into teach values ('Williams', 'CS107');
Note that there may be multiple professors teaching the same course (and there are students enrolled in the same course more than once).
If anyone has a pointer as to what I am missing here, please let me know! I'm new to SQL and have tried a few ideas unsuccessfully.
A simple and quick way to organize the sql is to use sub clause.
select s.*, c.*
from student_enrollment se
inner join student s on se.student_no = s.student_no
inner join course c on se.course_no = c.course_no
where course_no in (select course_no from teach where last_name = 'Wilson')

Oracle simple list results to comma separated list with quotes?

I would like to get results of this simple query
select PersonID from Persons where city ='Miami'
as a flat comma separated list with quotes.
desired results should be '3','5','7','8'
http://sqlfiddle.com/#!4/95e86d/1/0
I tried list_add but im getting: ORA-00904: "STRING_AGG": invalid identifier
CREATE TABLE Persons (
PersonID NUMBER,
FirstName varchar(255),
City varchar(255)
);
INSERT INTO Persons (PersonID, FirstName, City)
VALUES (1, 'Tom B.','Stavanger');
INSERT INTO Persons (PersonID, FirstName, City)
VALUES (2, 'Jerry M.','Train City');
INSERT INTO Persons (PersonID, FirstName, City)
VALUES (3, 'Eric g.','Miami');
INSERT INTO Persons (PersonID, FirstName, City)
VALUES (4, 'Bar Y.','Manhattan');
INSERT INTO Persons (PersonID, FirstName, City)
VALUES (5, 'John K.','Miami');
INSERT INTO Persons (PersonID, FirstName, City)
VALUES (6, 'Foo F.','Washington');
INSERT INTO Persons (PersonID, FirstName, City)
VALUES (7, 'Alen D.','Miami');
INSERT INTO Persons (PersonID, FirstName, City)
VALUES (8, 'John K.','Miami');
select listagg( '''' || PersonID || '''', ',' )
within group (order by personID)
from Persons
where city ='Miami'
should work.
I'd have to question why you're trying to produce this particular result. If you're going to generate this string so that you can subsequently use it in the IN list of another dynamically generated SQL statement, you're probably better off taking a step back because there are much better ways to solve the problem.
SQL Fiddle example

Two joins change case size

My question is why double joins in SQLite change case size in result.
Please look in fiddle:
http://sqlfiddle.com/#!7/88671/3
As you can see when I query "select * from user" I have upper size name A123456, but when I do double join I have only lower size name a123456.
Can someone explain why?
Schema below:
CREATE TABLE user (id integer primary key, n_login varchar(64), name varchar(128), CONSTRAINT a UNIQUE (n_login, name) ON CONFLICT IGNORE);
CREATE TABLE role (id integer primary key, name text unique, description text);
CREATE TABLE user_to_role (user_id integer REFERENCES user(id), role_id integer REFERENCES role(id), PRIMARY KEY (user_id, role_id));
CREATE TABLE role_to_database (id integer, role_id integer REFERENCES role(id), database_id integer REFERENCES databases(id), PRIMARY KEY (role_id, database_id));
insert into user (n_login, name) values ("a123456", "A123456");
insert into user (n_login, name) values ("a123456", "a123456");
insert into user (n_login, name) values ("a000000", "A000000");
insert into user_to_role (user_id, role_id) values (2, 1);
insert into user_to_role (user_id, role_id) values (2, 2);
insert into user_to_role (user_id, role_id) values (3, 3);
insert into role_to_database (role_id, database_id) values (1, 3);
insert into role_to_database (role_id, database_id) values (2, 8);
insert into role_to_database (role_id, database_id) values (3, 1);
With this query I have A123456:
select * from user;
With this query I have also A123456:
select * from role_to_database inner join user_to_role ON role_to_database.role_id = user_to_role.role_id inner join user;
But with this query I only have a123456:
select * from role_to_database inner join user_to_role ON role_to_database.role_id = user_to_role.role_id inner join user ON user.id = user_to_role.user_id;
The query returns exactly the data inserted:
insert into user_to_role (user_id, role_id) values (2, 1);
insert into user_to_role (user_id, role_id) values (2, 2);
insert into user_to_role (user_id, role_id) values (3, 3);
as user_id=1 takes no role.
Did you mean
insert into user_to_role (user_id, role_id) values (1, 1); -- 1
insert into user_to_role (user_id, role_id) values (2, 2);
insert into user_to_role (user_id, role_id) values (3, 3);
? Then you'll get 'A123456' too.
its a random process without using order by. so to get data in order you have to use order by in your query
select * from user order by name

Identifying the next unwatched episode in a series

I need to write a query in SQL that will identify the next unwatched episode in a series by a user. I have tables containing user history (userID, episodeID and show titleID) and Episode (episodeID(PK), episodeName and playCount), where the history table stores the episodeIDs of all watched episodes and the episode table contains all possible episodes.
I had hoped to do some sort of join between the two selecting by 'userID, titleID but i'm going in circles.
I've been learning SQL for about 5 hours in total so have no idea where to begin on this, any help gratefully received. I'm aware the code below is horrible and very clunky (please don't assume any prior knowledge!)
I've tried a left join, but this will return all data irrespective of user.
Create table Actor(
actorID integer primary key,
first_name text not null,
last_name text not null
);
create table AppearsIn(
actorID integer,
seriesID integer primary key
);
create table Series(
seriesID text,
titleID text,
episodeID text,
releaseDate date
);
create table Episode(
episodeID text primary key,
episodeName text,
playCount integer,
actorID integer
);
create table title(
titleID text primary key,
actorID integer,
titleName text,
genre text,
ageRating integer,
releaseDate date
);
create table history(
userID integer,
titleID text,
episodeID text
);
create table user (
userID integer not null,
fullName text not null,
Email text not null,
dateOfBirth date not null,
subscriptionEndDate date not null
);
insert into Actor (actorID, first_name, last_name)
values (76547, 'tom', 'cruise');
insert into Actor (actorID, first_name, last_name)
values (345, 'val', 'kilner');
insert into AppearsIn (actorID, seriesID)
values (345, 1);
insert into Series (seriesID, titleID, episodeID, releaseDate)
values ('WDS2', 'WalkingDead', 'WDS2E1', '1991-02-02');
insert into Series (seriesID, titleID, episodeID, releaseDate)
values ('WDS2', 'WalkingDead', 'WDS2E2', '1991-02-02');
insert into Series (seriesID, titleID, episodeID, releaseDate)
values ('WDS2', 'WalkingDead', 'WDS2E3', '1991-02-02');
insert into Series (seriesID, titleID, episodeID, releaseDate)
values ('WDS2', 'WalkingDead', 'WDS2E4', '1991-02-02');
insert into Series (seriesID, titleID, episodeID, releaseDate)
values ('WDS2', 'WalkingDead', 'WDS2E5', '1991-02-02');
insert into Series (seriesID, titleID, episodeID, releaseDate)
values ('WDS2', 'WalkingDead', 'WDS2E6', '1991-02-02');
insert into Series (seriesID, titleID, episodeID, releaseDate)
values ('WDS2', 'WalkingDead', 'WDS2E7', '1991-02-02');
insert into Series (seriesID, titleID, episodeID, releaseDate)
values ('WDS2', 'WalkingDead', 'WDS2E8', '1991-02-02');
insert into Episode (episodeID, episodeName, actorID, playCount)
values ('WDS2E1', 'A', 76547, 1);
insert into Episode (episodeID, episodeName, actorID, playCount)
values ('WDS2E2', 'B', 76547, 1);
insert into Episode (episodeID, episodeName, actorID, playCount)
values ('WDS2E3', 'C', 76547, 1);
insert into Episode (episodeID, episodeName, actorID, playCount)
values ('WDS2E4', 'D', 76547, 0);
insert into Episode (episodeID, episodeName, actorID, playCount)
values ('WDS2E5', 'E', 76547, 0);
insert into history (userID, titleID, episodeID)
values (8924, 'Walking Dead','WDS2E1');
insert into history (userID, titleID, episodeID)
values (8924, 'Walking Dead', 'WDS2E2');
insert into history (userID, titleID, episodeID)
values (8924, 'Walking Dead', 'WDS2E3');
insert into user (userID, fullName, Email, dateOfBirth, subscriptionEndDate)
values (8924, 'bill123', 'bill123#warmpost.com', '1970-02-12', '2019-06-05');
insert into title (titleID, actorID, titleName, genre, ageRating, releaseDate)
values ('WalkingDead', 123455, 'The Walking Dead', 'Drama', 15, '2015-01-01');
This is the query I tried:
SELECT * FROM Episode
LEFT JOIN history ON history.episodeID = Episode.EpisodeID
Where playcount <1
limit 1;
It sounds like you're just having issues with the join. Here's a page on how joins work. From that page:
(INNER) JOIN: Returns records that have matching values in both tables
LEFT (OUTER) JOIN: Return all records from the left table, and the matched records from the right table
RIGHT (OUTER) JOIN: Return all records from the right table, and the matched records from the left table
FULL (OUTER) JOIN: Return all records when there is a match in either left or right table
So, if you want only movies that user has seen, you could try replacing LEFT JOIN with RIGHT JOIN, or change the order in which you specify the tables.
I'm currently not able to test this myself, but hopefully this is what you're looking for.
SELECT * FROM Episode
RIGHT JOIN history ON history.episodeID = Episode.EpisodeID
WHERE playcount < 1
LIMIT 1;