Query to find name of parents with age of youngest child - sql

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

Related

How to list total number of scholarships per department in SQL

I have 2 tables that look like this where I want to query how many scholarships (from Tuition table) each department (from Student table) has distributed:
I am thinking a join is necessary but am not sure how to do so.
Create tables
create table students (
sid int auto_increment primary key,
name varchar(100),
email varchar(100),
department varchar(100)
);
create table tutions (
id int auto_increment primary key,
sid int,
cost int,
scholarships int,
duedate timestamp default current_timestamp
);
Sample data
insert into students (name, email, department)
values
('John Doe', 'john#abc.xyz', 'B'),
('Jane Doe', 'jane#abc.xyz', 'A'),
('Jack Doe', 'jack#abc.xyz', 'C'),
('Jill Doe', 'jill#abc.xyz', 'B');
insert into tutions (sid, cost, scholarships)
values
(1, 1000, 2),
(2, 1000, 1),
(3, 1000, 7),
(4, 1000, 2);
Query (department-wise total scholarships)
SELECT department, sum(scholarships) as scholarships
FROM students s
JOIN tutions t ON s.sid = t.sid
GROUP BY department
Output
Running SQL Fiddle
Not sure It's something you want? And not sure scholarships is a number or name of scholarship? So I doubt it's a name as varchar string type.
### dummy record
CREATE TABLE students (
psu_id INTEGER PRIMARY KEY,
firstname VARCHAR NOT NULL,
lastname VARCHAR NOT NULL,
email VARCHAR NOT NULL,
department VARCHAR NOT NULL
);
CREATE TABLE tuition (
tuition_id INTEGER PRIMARY KEY,
student_id INTEGER NOT NULL,
semeter_cost INTEGER NOT NULL,
scholarships VARCHAR NOT NULL,
due_date DATE NOT NULL
);
INSERT INTO students VALUES (1, 'John', 'Hello', 'Jonh#email.com', 'Engineering');
INSERT INTO students VALUES (2, 'Bella', 'Fuzz', 'Bella#email.com', 'Computer');
INSERT INTO students VALUES (3, 'Sunny', 'World', 'Sunny#email.com', 'Science');
INSERT INTO tuition VALUES (1, 1, 4000, 'first_class_en', '2022-05-09' );
INSERT INTO tuition VALUES (2, 2, 3000, 'nobel', '2022-05-09' );
INSERT INTO tuition VALUES (3, 3, 5000, 'hackathon', '2022-05-09' );
INSERT INTO tuition VALUES (4, 1, 4500, 'second_class_en', '2022-05-09' );
-----------------
### query
SELECT s.department, count(t.scholarships)
FROM students s
JOIN tuition t
ON s.psu_id = t.student_id
GROUP BY s.department
### output
department, total_scholarships
Computer|1
Engineering|2
Science|1

AVG() inside LISTAGG()

I need to group two columns, one of them with an average, AVG() inside an LISTAGG().
I have the following code:
CREATE OR REPLACE VIEW countryTimes AS
SELECT
LISTAGG(claOL.odCode||'-'||(AVG(claOL.timeCla) GROUP BY(claOl.timeCla))) WITHIN GROUP (ORDER BY c.cCode) AS ProvaTempsMig,
c.cDescription AS País,
c.cCode AS CodiPaís
FROM countries c
JOIN athletes a ON c.cCode = a.country
JOIN classificationOL claOL ON a.idCode = claOL.idAth;
But this throws this error:
ORA-00907: missing right parenthiesis erecho 00907. 00000 - "missing right parenthesis" *Cause: *Action:
I'm using Oracle.
UPDATE:
What I need to do is create a view where appears cCode, cDescription and a last column with the AVG of all the times for a single country. So I need to create from multiple rows, a single row for each country.
Code:
CREATE TABLE Countries (
cCode VARCHAR(5) NOT NULL,
cdescription VARCHAR(100) NOT NULL,
CONSTRAINT couPK PRIMARY KEY (cCode)
);
CREATE TABLE athletes (
idCode NUMBER NOT NULL,
Name VARCHAR(200) NOT NULL,
Surname VARCHAR(200) NOT NULL,
country VARCHAR(5) NOT NULL,
CONSTRAINT athPK PRIMARY KEY (idCode),
CONSTRAINT countryFK FOREIGN KEY (country) REFERENCES Countries (cCode)
);
CREATE TABLE olympicDisciplines (
oCode VARCHAR(10) NOT NULL,
odName VARCHAR(200) NOT NULL,
discipline VARCHAR(200) NOT NULL,
CONSTRAINT olympicPK PRIMARY KEY (oCode)
);
CREATE TABLE classificationOL(
idAth NUMBER NOT NULL,
odCode VARCHAR(10) NOT NULL,
timeCla INTEGER,
CONSTRAINT classifPK PRIMARY KEY (idAth, odCode),
CONSTRAINT claAthFK FOREIGN KEY (idAth) REFERENCES athletes (idCode),
CONSTRAINT claDFK FOREIGN KEY (odCode) REFERENCES olympicDisciplines (oCode)
);
UPDATE 2:
Data:
INSERT INTO Countries VALUES ('UK', 'United Kingdom');
INSERT INTO Countries VALUES ('AND', 'Andorra');
INSERT INTO Countries VALUES ('FR', 'France');
INSERT INTO athletes VALUES (1, 'Jack', 'Johnson', 'UK');
INSERT INTO athletes VALUES (2, 'Pau', 'Márquez', 'AND');
INSERT INTO athletes VALUES (3, 'Pierre', 'Dubois', 'FR');
INSERT INTO athletes VALUES (4, 'Christophe', 'Dubois', 'FR');
INSERT INTO athletes VALUES (5, 'Adolphe', 'Moreau', 'FR');
INSERT INTO olympicDisciplines VALUES ('ATH', 'Athletics', 'Athletics');
INSERT INTO olympicDisciplines VALUES ('CYC', 'Cycling', 'Cycling');
INSERT INTO olympicDisciplines VALUES ('CCC', 'Cycling CC', 'Cross Country Cycling');
INSERT INTO classificationOL VALUES (1, 'ATH', 120);
INSERT INTO classificationOL VALUES (2, 'ATH', 119);
INSERT INTO classificationOL VALUES (3, 'CCC', 38);
INSERT INTO classificationOL VALUES (4, 'CCC', 37);
INSERT INTO classificationOL VALUES (5, 'ATH', 122);
Reading your first UPDATE, if you're allowed to, you can transform your tables to object to solve your necessity, instead of using LISTAGG(). I'll show you:
CREATE TYPE average AS OBJECT(
name VARCHAR(200),
avgerageTime NUMBER);
CREATE TYPE results AS TABLE OF average;
CREATE TYPE countriesResults AS OBJECT(
cName VARCHAR(100),
cCode VARCHAR(5),
classifications results
);
CREATE VIEW countriesAverages OF countriesResults
WITH OBJECT OID (coName)
AS
SELECT c.cdescription, c.ccode,
CAST (MULTISET (SELECT
olympicDisciplines.name, avg(classificationOL.timeCla)
FROM athletes a, countries, classificationOL, olympicDisciplines
WHERE countries.cCode = c.cCode
AND a.idCode = classificationOL.idAth
AND a.country = countries.cCode
AND olympicdisciplines.oCode = classificationOL.oCode
GROUP BY olympicdisciplines.odName) AS results )
FROM countries c;

Get value from table to use it in insert

I suppose this question was already asked somewhere here, but I have no idea how to name (and look for) it correctly.
The database:
CREATE TABLE department (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(100) NOT NULL UNIQUE
);
CREATE TABLE employee (
id INTEGER PRIMARY KEY AUTOINCREMENT,
department_id INTEGER NOT NULL,
chief_id INTEGER,
name VARCHAR(100) NOT NULL UNIQUE,
salary INTEGER NOT NULL,
FOREIGN KEY (department_id) REFERENCES department (id),
FOREIGN KEY (chief_id) REFERENCES employee (id)
);
INSERT INTO department (name) VALUES ('sales'), ('it'), ('management');
INSERT INTO employee (department_id, chief_id, name, salary) VALUES
(3, NULL, 'Owner', 1000000),
(2, 1, 'Team manager', 9000),
(2, 3, 'Senior dev #1', 7000),
(2, 3, 'Senior dev #2', 7000);
Now in insert I should calculate chief_id on my own, but I'm curious if there is a possibility to get id by name, something like
SELECT id FROM employee WHERE name = 'Owner'
and use this value instead of hardcoded id in insert.
I've tried putting select statement instead of id but that does not work.
I am using SQLite.
You can do it with a subquery as yours, but the data has to be in the table before you can select it. Otherwise the subquery returns null. So you need to break the one INSERT into multiple INSERTs.
INSERT INTO employee (department_id, chief_id, name, salary) VALUES
(3, NULL, 'Owner', 1000000);
INSERT INTO employee (department_id, chief_id, name, salary) VALUES
(2, (SELECT id FROM employee WHERE name = 'Owner'), 'Team manager', 9000);
INSERT INTO employee (department_id, chief_id, name, salary) VALUES
(2, (SELECT id FROM employee WHERE name = 'Team manager'), 'Senior dev #1', 7000),
(2, (SELECT id FROM employee WHERE name = 'Team manager'), 'Senior dev #2', 7000);
But note, that the subquery must return only one row. So the column you're checking in it's WHERE clause must contain unique values. Usually a name is not unique, there are a lot of John Smith. Usually the ID is the unique identifier. So in a general inserting the ID directly is the right approach.

What is wrong with this JOIN statement in 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;

joining three tables together using Inner Joins

Using Table aliases, list the first name, last name and start date of students enrolled on the java fundamentals module:
I am having some trouble when running the query below.
SELECT stu.StudFName, stu.StudLName, enrol.StartDate
From Student stu
INNER JOIN Enrolment enrol
ON stu.StudID = enrol.StudID
INNER JOIN Module mod
ON enrol.ModCode = mod.ModCode
WHERE mod.ModName = 'Java Fundamentals'
Structure:
CREATE TABLE Student
(StudID INTEGER PRIMARY KEY,
StudFName VARCHAR(10) NOT NULL,
StudLName VARCHAR(10) NOT NULL,
DoB DATE NOT NULL,
Sex CHAR(1) NOT NULL CHECK (Sex IN ('M', 'F')),
Email VARCHAR(30) UNIQUE);
CREATE TABLE Staff
(StaffID INTEGER PRIMARY KEY,
Title VARCHAR(4) CHECK (Title IN ('Prof', 'Dr', 'Mr', 'Mrs', 'Miss')),
StaffFName VARCHAR(10) NOT NULL,
StaffLName VARCHAR(10) NOT NULL,
Email VARCHAR(30) UNIQUE,
Department VARCHAR(25) DEFAULT 'Not Assigned',
Extension INTEGER CHECK (Extension BETWEEN 0001 AND 9999));
CREATE TABLE Module
(ModCode CHAR(4) PRIMARY KEY,
ModName VARCHAR(25) NOT NULL,
ModCredits INTEGER NOT NULL CHECK (ModCredits IN (15, 30, 45, 60)),
ModLevel CHAR(3) NOT NULL CHECK (ModLevel IN ('UG1', 'UG2', 'UG3', 'MSc')),
ModLeader INTEGER NOT NULL,
Foreign Key (ModLeader) REFERENCES Staff (StaffID));
CREATE TABLE Enrolment
(ModCode CHAR(4) NOT NULL,
StudID INTEGER NOT NULL,
StartDate DATE NOT NULL,
PRIMARY KEY (ModCode, StudID),
Foreign Key (StudID) REFERENCES Student (StudID),
Foreign Key (ModCode) REFERENCES Module (ModCode));
The answer is... there is no trouble with your query.
It works just fine.
Check here
INSERT INTO Student (StudID, StudFName, StudLName, DoB, Sex, Email) VALUES
(1, 'Jack', 'Black', TO_DATE('2015/01/01', 'yyyy/mm/dd'), 'M', 'jack#email.com');
INSERT INTO Student (StudID, StudFName, StudLName, DoB, Sex, Email) VALUES
(2, 'Andrew', 'Wiggin', TO_DATE('2015/01/01', 'yyyy/mm/dd'), 'M', 'andrew#email.com');
INSERT INTO Student (StudID, StudFName, StudLName, DoB, Sex, Email) VALUES
(3, 'Bob', 'Marley', TO_DATE('2015/01/01', 'yyyy/mm/dd'), 'M', 'bob#email.com');
INSERT INTO Staff (StaffID, Title, StaffFName, StaffLName, Email, Extension) VALUES
(1, 'Prof', 'Joe', 'Smith', 'stuff#emal.com', 0001);
INSERT INTO Module (ModCode, ModName, ModCredits, ModLevel, ModLeader) VALUES
(1, 'Java Fundamentals', 30, 'UG1', 1);
INSERT INTO Module (ModCode, ModName, ModCredits, ModLevel, ModLeader) VALUES
(2, 'C# Fundamentals', 15, 'UG2', 1);
INSERT INTO Enrolment (ModCode, StudID, StartDate) VALUES
(1, 1, TO_DATE('2015/01/01', 'yyyy/mm/dd'));
INSERT INTO Enrolment (ModCode, StudID, StartDate) VALUES
(1, 2, TO_DATE('2015/01/02', 'yyyy/mm/dd'));
INSERT INTO Enrolment (ModCode, StudID, StartDate) VALUES
(2, 3, TO_DATE('2015/01/03', 'yyyy/mm/dd'));
-------------------------------------------------------------
SELECT stu.StudFName, stu.StudLName, enrol.StartDate
From Student stu
INNER JOIN Enrolment enrol ON stu.StudID = enrol.StudID
INNER JOIN Module mod ON enrol.ModCode = mod.ModCode
WHERE mod.ModName = 'Java Fundamentals'
Result
STUDFNAME STUDLNAME STARTDATE
----------------------------------------
Jack Black January, 01 2015
Andrew Wiggin January, 02 2015