SQLite3 INNER JOIN with 3 tables - sql

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

Related

Using inner join as ALIASES with multiple tables

I have these tables below:
create table student(
studentName varchar (40) not null,
studentRollNo varchar (30) primary key, -- also acts as username
studentPassword varchar(30) NOT NULL,
studentGender varchar(7) default NULL
);
create table supervisors(
supervisorID varchar(30) foreign key references Faculty(facultyID) unique,
sWorkLoad int default null,
CHECK (sWorkLoad<=6 and sWorkLoad>=0)
);
create table co_supervisors(
co_supervisorID varchar(30) foreign key references Faculty(facultyID) unique,
csWorkLoad int default null,
CHECK (csWorkLoad<=6 and csWorkLoad>=0)
);
create table studentGroup(
groupID int IDENTITY(1,1) primary key ,
Member1rollNo varchar(30) foreign key references student(studentRollNo) default NULL, -- member 1
Member2rollNo varchar(30) foreign key references student(studentRollNo) default NULL, -- member 2
Member3rollNo varchar(30) foreign key references student(studentRollNo) default NULL, -- member 3
supervID varchar(30) foreign key references supervisors(supervisorID),
co_supervID varchar(30) foreign key references co_supervisors(co_supervisorID) default NULL,
projectTitle varchar(100) not null,
projectDetails varchar (500) default NULL
);
create table FYP1(
groupID int foreign key references studentGroup(groupID),
);
I want to display student details who are registered in FYP1.
with their supervisors, co_supervisors,and project title.
But I I'm not able to do so,
What I have done so far is this.
select sg.Member1rollNo,S.studentName,Member2rollNo,S.studentName,sg.Member3rollNo,sg.supervID,sg.projectTitle
FROM student S
inner join studentGroup SG ON S.studentRollNo = SG.Member1rollNo
OR some random tries like this
-- Faculty.facultyName
SELECT FYP1.groupID, studentGroup.Member1rollNo,student.studentName as student1, studentGroup.Member2rollNo,student.studentName as student2,studentGroup.projectTitle
FROM FYP1 as FYP1_Students
INNER JOIN studentGroup ON (studentGroup.groupID = FYP1_Students.groupID)
INNER JOIN supervisors ON (studentGroup.supervID = supervisors.supervisorID)
INNER JOIN student ON (student1.studentRollNo = studentGroup.Member1rollNo)
INNER JOIN student ON (student.studentRollNo = studentGroup.Member2rollNo)
Output or first query is this (example):
'i19-0434' 'Sourav Malani' 'i19-0498' 'Sourav Malani' NULL 'urooj.ghani' 'Indoor Navigation'
'i19-0466' 'Aftab Ali' 'i19-0528' 'Aftab Ali' NULL 'urooj.ghani' 'AI based Physics exp.'
I want output to be like:
'i19-0434' 'Sourav Malani' 'i19-0498' 'Student2 Name' NULL 'urooj.ghani' 'Indoor Navigation'
'i19-0466' 'Aftab Ali' 'i19-0528' '<student2Name>' NULL 'urooj.ghani' 'AI based Physics exp.'
Sample Data
Thanks to #Hana, I solved the problem.
Here's the solution:
SELECT SG.groupID,
SG.Member1rollNo,S1.studentName as 'student1 Name',
SG.Member2rollNo, S2.studentName as 'student2 Name',
SG.Member3rollNo, S3.studentName as 'Studen3 Name',
SG.supervID, SN.facultyName as 'Supervisor Name',
SG.co_supervID, CSN.facultyName as 'Co_Supervisor',
SG.projectTitle as 'Project Title',
SG.projectDetails as 'Project Desc.'
FROM FYP1 FYP1
LEFT OUTER JOIN studentGroup SG ON FYP1.groupID = SG.groupID
LEFT OUTER JOIN supervisors SV ON SG.supervID = SV.supervisorID
LEFT OUTER JOIN Faculty SN ON SG.supervID= SN.facultyID
LEFT OUTER JOIN Faculty CSN ON SG.co_supervID= CSN.facultyID
LEFT OUTER JOIN student S1 ON SG.Member1rollNo = S1.studentRollNo
LEFT OUTER JOIN student S2 ON SG.Member2rollNo = S2.studentRollNo
LEFT OUTER JOIN student S3 ON SG.Member3rollNo = S3.studentRollNo
Is this what you are looking for?
SELECT SG.groupID, SV.supervisorID, CSV.co_supervisorID, S1.studentName, S2.studentName, S3.studentName
FROM FYP1 FYP1
INNER JOIN studentGroup SG ON FYP1.groupID = SG.groupID
INNER JOIN supervisors SV ON SG.supervID = SV.supervisorID
INNER JOIN co_supervisors CSV ON SG.co_supervID = CSV.co_supervisorID
INNER JOIN student S1 ON SG.Member1rollNo = S1.studentRollNo
INNER JOIN student S2 ON SG.Member1rollNo = S2.studentRollNo
INNER JOIN student S3 ON SG.Member1rollNo = S3.studentRollNo

Sum two SQLite columns, when they're subqueries

I have a table of receipts. Each one is associated with a service, and each person is obligated to pay equally for it, except when they are assigned an extra fee that can be activated/deactivaded (0/1). So I used a subquery to get the extra amount they have to pay only if that fee is active; the table 'fees' contains the user_id, the service_id, the extra amount and the active flag. And then, I should get the total per person, adding the extra fee (if any) to the subtotal (receipt total amount minus any active extra fee, and then divided by the number of persons who are obligated to contribute).
SELECT
P.nombre AS person,
S.nombre AS service,
(
SELECT TOTAL(C.value)
FROM fees C
WHERE C.user_id = P.id AND C.service_id = O.service_id AND C.active = 0
) AS fee,
IFNULL(NULL, 23333) AS subtotal,
(fee + subtotal) as total
FROM receipts R
LEFT JOIN obligations O ON O.service_id = R.service_id
LEFT JOIN persons P ON O.user_id = P.id
LEFT JOIN services S ON O.service_id = S.id
WHERE R.id = 3 AND O.active = 0;
Note: 23333 (the subtotal) will be replaced with a '?' and then I'll pass as argument to execute the query with Golang that result that I've already got from another function
Problem occurs at this line
(fee + subtotal) as total
Output: no such column: fee
If I run the query without that line, it will actually return a table with the active extra fees and subtotal, but I'm stuck when trying to create a final column to add those two values.
Thanks!
Edit
Following Stefan's advice, here are the statements I used to create the tables:
CREATE TABLE IF NOT EXISTS persons (id INTEGER PRIMARY KEY, name TEXT NOT NULL, active INTEGER DEFAULT 0); CREATE UNIQUE INDEX per_nom_uindex on persons (name)
CREATE TABLE IF NOT EXISTS services (id INTEGER PRIMARY KEY, name TEXT NOT NULL, active INTEGER DEFAULT 0); CREATE UNIQUE INDEX ser_nom_uindex on services (name)
CREATE TABLE IF NOT EXISTS receipts (id INTEGER PRIMARY KEY, y INTEGER NOT NULL, m INTEGER NOT NULL, service_id INTEGER NOT NULL, amount INTEGER NOT NULL, FOREIGN KEY (service_id) REFERENCES services (id))
CREATE TABLE IF NOT EXISTS fees (id INTEGER PRIMARY KEY, person_id INTEGER NOT NULL, service_id INTEGER NOT NULL, amount INTEGER NOT NULL, active INTEGER DEFAULT 0, FOREIGN KEY(person_id) REFERENCES persons(id), FOREIGN KEY(service_id) REFERENCES services(id))
CREATE TABLE IF NOT EXISTS obligations (id INTEGER PRIMARY KEY, person_id INTEGER NOT NULL, service_id INTEGER NOT NULL, active INTEGER DEFAULT 0, FOREIGN KEY(person_id) REFERENCES persons(id), FOREIGN KEY(service_id) REFERENCES services(id))
Consider moving the subquery from SELECT to JOIN clause (often called derived table) and adjust it with GROUP BY aggregation on user_id and service_id. Doing so, this allows you to reference the column as needed and even avoid rowwise aggregation (unless the SQLite engine runs it as a single aggregation under the hood).
SELECT
P.nombre AS person,
S.nombre AS service,
C.fee, -- REFERENCE SUBQUERY COLUMN
IFNULL(?, 23333) AS subtotal,
C.fee + IFNULL(?, 23333) as total -- REPEAT NEEDED EXPRESSION
FROM receipts R
LEFT JOIN obligations O
ON O.service_id = R.service_id
LEFT JOIN persons P
ON O.user_id = P.id
AND O.active = 0 -- MOVED FROM WHERE CLAUSE
LEFT JOIN services S
ON O.service_id = S.id
LEFT JOIN (
SELECT user_id,
service_id,
TOTAL(value) AS fee
FROM fees
WHERE active = 0
GROUP BY user_id,
service_id
) C ON C.user_id = P.id
AND C.service_id = O.service_id
WHERE R.id = 3

SQLite: Get Output From Two Tables Using Common Reference ID

I am new in SQLite and i have been working on an issue for quite a long time.
Lets say we have 2 database table say tbl_expense and tbl_category. Please find below the following table structure.
tbl_category
CREATE TABLE IF NOT EXISTS tbl_category(
category_id INTEGER PRIMARY KEY AUTOINCREMENT,
category_name VARCHAR(20) DEFAULT NULL,
category_desc VARCHAR(500) DEFAULT NULL,
category_icon VARCHAR(100) DEFAULT NULL,
category_created timestamp default CURRENT_TIMESTAMP
)
tbl_expense
CREATE TABLE IF NOT EXISTS tbl_expense(
expense_id INTEGER PRIMARY KEY AUTOINCREMENT,
expense_name VARCHAR(20) DEFAULT NULL,
expense_desc VARCHAR(500) DEFAULT NULL,
expense_type VARCHAR(20) DEFAULT NULL,
expense_amt DECIMAL(6.3) DEFAULT NULL,
expense_date TIMESTAMP DEFAULT NULL,
expense_category INTEGER DEFAULT NULL,
expense_created_date timestamp DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (expense_category) REFERENCES tbl_category(category_id)
ON DELETE SET NULL
)
Assume we have data in the tables like this below.
Expected Output:
Assure we have category_id and expense_category as common fields. How can i create an SQL Query where i can list all categories and sum of their expense amount as follows.
Please help me on this issue.
You need an INNER join of the tables and aggregation:
SELECT c.category_name Category,
SUM(e.expense_amt) Amount
FROM tbl_category c INNER JOIN tbl_expense e
ON e.expense_category = c.category_id
GROUP BY c.category_id;
If you want all categories from the table tbl_category, even those that are not present in tbl_expense, use a LEFT join and TOTAL() aggregate function:
SELECT c.category_name Category,
TOTAL(e.expense_amt) Amount
FROM tbl_category c LEFT JOIN tbl_expense e
ON e.expense_category = c.category_id
GROUP BY c.category_id;

Joins on multiple tables in Postgresql

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.

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