Updating fields with indirectly related data - sql

I have four tables:
student table with id_student, firstname and lastname fields
rent table with id_student and id_book
book table with id_book, book_name, author_name
booking table with id_book, current_student
The rent table only has IDs and links between student and book tables.
How can I update the booking.current_student field with a concatenation of firstname and lastname fields from student table (like 'john doe' ) - for each id_book in booking table, update booking.curent_student from student.firstname and student.lastname.
Since the booking table has no id_student column, how can I update booking.current_student from the student table?

You need a correlated update, which uses a subquery to get the new value to use in the set clause for each row; and that subquery needs to join the rent and student tables:
update booking b
set current_student = (
select s.firstname || ' ' || s.lastname
from rent r
join student s on s.id_student = r.id_student
where r.id_book = b.id_book
);
The 'correlation' part is that the subquery filters on r.id_book = b.id_book, so it correlates with the outer booking (b) table which is being updated.
If there are any rows in booking which don't have a matching rent row then they will be set to null. And if you have multiple booking rows for the same book ID then they will all be updated to the same student name; and if you have multiple rent rows for the same book ID it will error as the subquery will return multiple rows.
It's generally not a good idea to duplicate data like this. It would require less maintenance if you used a view instead:
create view booking (id_book, current_name) as
select r.id_book, s.firstname || ' ' || s.lastname
from rent r
join student s on s.id_student = r.id_student;
Then as rows are added to or removed from the rent table, or if a student changes their name, the view will automatically reflect the changes without you having to do anything.

Related

Condition for finding rows with same value in one colum and null in another column

I have a table with columns student ID, subject, Enrolled. I have a row for each subject against a student. I am inserting this data to a temp table for reporting. I have another column named reporting in this temp table. I need to update reporting false when enrolled is null for all the rows imported for a student.
Here is the approach:
Select from all students
Left outer join to student-course (outer join is important here)
Group by student ID, and get min course ID
Use rows with null course ID to decide what temp rows to update
In SQL this query would look like this:
SELECT StudentId, MIN(CourseId)
FROM Student s
LEFT OUTER JOIN StudentCourse sc
ON s.StudentId=sc.StudentId
GROUP BY s.StudentId
HAVING MIN(CourseId) IS NULL

Selecting students who have not made any payment in a given period (term)

I have two tables: students and payments.
students has the columns:
first_name
last_name
student_id
class_name
payments table has the columns:
full_name
student_id
term
session
amount_paid
class_fee
The details of every student is in the students table, but only those who have made either full or part payment enters the payments table. I have written a query to select those who have paid.
The question now is how to write a query that will select those in a particular class that have made no payment at all in a given period (term).
You are probably using a JOIN to select those who have paid. That will work because there are matching rows in both tables. To find those who have not paid, you can use a LEFT JOIN. It will give you NULL if rows do not match.
SELECT students.*
FROM students
LEFT JOIN payments ON students.student_id = payments.student_id
AND term = 'whatever'
WHERE amount_paid IS NULL
(Note: the term = 'whatever' needs to be in the ON clause, not the WHERE)
You can also do this using a subquery and the NOT EXISTS clause. NOT EXISTS will return true if the subquery returns zero rows.
SELECT *
FROM students
WHERE NOT EXISTS(
SELECT amount_paid
FROM payments
WHERE students.student_id = payments.student_id
AND term = 'whatever'
)

Selecting columns from different tables

I need to display two columns from my attendance table (MEMBER_ID & MEETING_ID) and one column from my meeting table and finally two columns from my member table which displays the names that match with MEETING_ID.
The attendance table has a composite key (MEMBER_ID*, MEETING_ID*)
The member table's primary key is MEMBER_ID
Meeting table's primary key is MEETING_ID
My attempt is not working, can someone please help?
SELECT MEMBER_ID, MEETING_ID, MEETING_NAME MEMBER_FIRSTNAME, MEMBER_LASTNAME
FROM ATTENDANCE, MEMBER, MEETING
WHERE MEETING.MEMBER_ID = MEETING.MEMBER_ID;
End result needs to be:
MEMBER_ID MEETING_ID MEETING_NAME FIRSTNAME LASTNAME
0001 MEET0004 SPORTS DAY JOHN SMITH
May be you need this.
SELECT A.MEMBER_ID, A.MEETING_ID, M2.MEETING_NAME, M1.MEMBER_FIRSTNAME, M1.MEMBER_LASTNAME
FROM ATTENDANCE A, MEMBER M1, MEETING M2
WHERE M1.MEMBER_ID = A.MEMBER_ID
AND A.MEETING_ID = M2.MEETING_ID;
SELECT
a.MEMBER_ID
,a.MEETING_ID
,mt.MEETING_NAME
,mb.MEMBER_FIRSTNAME
,mb.MEMBER_LASTNAME
FROM
ATTENDANCE a
INNER JOIN MEMBER mb
ON a.MEMBER_ID = mb.MEMBER_ID
INNER JOIN MEETING mt
ON a.MEETING_ID = mt.MEETING_ID
;
Use Explicit Join Syntax and then setup your relationships using the ON conditions and the keys between the tables. Note I also used table aliases to shorten typying.

JOIN Two tables one of which has where clause

I want to join two tables where Person table fields(having Street S1) will be merged into Student table, but adding new field (STUDENT/NONSTUDENT).
Student table has 1milyon rows, Result person table has max 100 rows.
What is the best sql for performance to merge them all?
student table (name, age)
A-12
B-23
C-24
person table (name, street, live)
A-S1-L
B-S2-NL
D-S1-L
At the end I want such result
A-12-Student
D-NULL-NOTSTUDENT
This should work:
select p.name,
s.age,
case when s.name is null then 'NotStudent'
else 'Student' end as IsStudent
from person p
left join student s on p.name = s.name
where p.Street = 's1'

How to retrieve records having many to many relationship bet two tables?

I have two tables:
1) employee with columns: e_id, e_name, address;
2) project with columns: p_id, p_name, start_Date, End_Date.
There is a many-to-many relationship between these two tables.
How can I store this relationship and how can I query for retrieving "Employee details and project details on which he is working"?
You need a cross reference table inbetween:
EmployeeProjectXref: e_id, p_id
The combination of e_id and p_id can be the primary key for this Xref table.
Then, if #e_id is a variable holding the selected Employee ID:
SELECT E.e_name, P.p_name
FROM EmployeeProjectXref EPX
JOIN Employee E ON E.e_id = EPX.e_id
JOIN Project P ON P.p_id = EPX.p_id
WHERE EPX.e_id = #e_id
ORDER BY P.Name
For more details, add them to the SELECT list. E.g.: SELECT E.e_name, E.address, P.p_name, P.start_date, P.end_date, etc. Here the E is an alias for the Employee table, and P is an alias for the Project table. This query will return one row for each entry in the EmployeeProjectXref table (provided that it references real entries in the Employee and Project tables.) If there is one employee and three projects, you'll get three rows.