Joining three tables. Two related, and one unrelated to the other two - sql

I want to Create a view called ShowAllBooksBorrowed that shows the information (BookName, ISBN, BookCategoryName, BookAuthor, BorrowedDate, ReturnDate, ActualReturnDate) of all the books that have been borrowed from the library but not returned.
I am having trouble figuring out how to relate the BorrowerInfo table to the BookInfo and BookCategory table using the information from the Books table. I understand how it relates but I am not sure how to carry this out. I think I may need to use Union or CrossJoin?
here is my database:

You could create a view like as shown below:
create view show_all_books_borrowed as
select
k.bookname,
b.isbn,
c.bookcategoryname,
k.bookauthor,
w.borrowdate,
w.returndate,
w.actualreturndate
from books b
join borrowerinfo w on w.bookid = b.bookid
join bookinfo k on k.isbn = b.isbn
join bookcategory c on k.bookcategoryid = c.bookcategoryid
where w.actualreturndate is null

Related

How to replace the column value with value from other connected table

The code below is my query code of postgresql schema views.
Please assuming this a library table, which is a book list and you have some defined tags can apply on the book itself, and every book will be devided into one category.
CREATE VIEW tagging_books AS
SELECT tags."TagName", books."BookISBN", books."BookName", books."BookCategoryID"
FROM library
INNER JOIN tags on library."TagName_id" = tags."id"
INNER JOIN books on library."BookISBN_id" = books."id"
ORDER BY tags."id"
The schema views inside db will looks like this:
/tags.TagName /books.BookISBN /books.BookName /books.BookCategoryID
Python ISBN 957-208-570-0 Learn Python 1
And the BookCategoryID from table "books" is actually a foreign key of table "category", the table looks like this:
/category
BookCategoryID CategoryName
1 Toolbook
I wonder that, is there anyway to replace the books."BookCategoryID" field to category."CategoryName" by query code? Like the example below.
/tags.TagName /books.BookISBN /books.BookName /category.CategoryName
Python ISBN 957-208-570-0 Learn Python Toolbook
Since they are connected with each other, I think they can definitely being replaced, but I don't know how to do... Thank you.
To include category.name, simply join with table category on the foreign-key constraint like:
select category.name, books.*
from books
join category on books.BookCategoryID = category.BookCategoryID
You can add it to your view creation as well:
CREATE VIEW tagging_books AS
SELECT tags.TagName, books.BookISBN, books.BookName, category.name as "CategoryName"
FROM library
JOIN tags on library.TagName_id = tags.id
JOIN books on library.BookISBN_id = books.id
JOIN category on books.BookCategoryID = category.BookCategoryID
ORDER BY tags.id

How can I take a joined table and use it to reference another table?

I've just started learning SQL and need help with an assignment question. I am asked to look through a dataset about Kickstarter campaigns. I'm asked to find the top 3 categories by amount of backers.
Here is the ER diagram:
ER diagram
In the 'Campaign' Table, there's the 'backers' column, but the 'Category' Table is only related with the Campaign through the 'Sub-Category' Table.
So far, I have been able to Join sub_category.category_id with the sub-category.category_name, but i'm not sure how to take this new Table and join it with Campaign
SELECT C.name AS category_name, SC.category_id, SC.id AS SC_id
FROM Category AS C
JOIN sub_category AS SC ON C.id = SC.category_id
Screenshot
I am hoping to have a table where there is a column for 'Category Name' and 'Backers' and then simply sort it by the number of backers
How should I go about this? Am I on the right track?
SELECT C.name AS category_name, CA.backers
FROM campaign AS CA
JOIN sub_category AS SC
ON CA.sub_category_id =SC.Id
JOIN Category AS C
ON C.id = SC.category_id
order by CA.backers
You can have multiple joins all together in one query.
Secondly there is a connection between Campaign and Sub_Category table which will help to join these two tables.
Later we can then join Category table as these two table has a connection between them based on Category_Id which is a foreign key in sub category table.
At last you can just order by based on Backers.
Let me know if you have any issue or doubt in comments.
And just to take Magnus's answer and rewrite visually, you can better see the hierarchy of the query. See how it closely resembles that of your table relationships
SELECT
C.name category_name,
CA.backers
FROM
campaign CA
JOIN sub_category SC
ON CA.sub_category_id = SC.Id
JOIN Category C
ON SC.category_id = C.id
order by
CA.backers
Notice the indentation to the table its ID is based upon from that prior to it. This way you know which column FROM connecting TO. I have found that if you list the tables in the FROM clause first to show all the HOW tables are related and ON what foreign : primary key relationships, that is the hardest part. Then its just pulling the columns you want after that.

Finding entities (in a many to many relationship) that are related to other entities

TL;DR problem
Entity A's have a many to many relationship with Entity B's. Given some Entity B's, how can I find all Entity A's that are related to those given Entity B's?
Actual Problem
I'm currently a bit stuck on a problem of SELECTing rows that are in a many to many relationship. The problem can be phrased like this:
Entity A: Book
Each book is stored in a table called Books that looks something like this:
DESCRIBE Books;
book_id | book_name | ... other metadata on books
-- book_id is a PRIMARY KEY
Entity B: Genres
A genre of some type, like Adventure or Romance, held in a table like this:
DESCRIBE Genres;
genre_id | genre_name
-- genre_id is a PRIMARY KEY
Relationship Holder: BookGenres
Each Entity A, Book, can be related to multiple Entity B, Genre. For example, Harry Potter can be related to the genre_names: 'Adventure' and 'Fantasy'. The relationships are stored here via. a (book_id, genre_id) tuple per row
DESCRIBE BookGenres;
book_id | genre_id
-- book_id REFERENCES Books(book_id)
-- genre_id REFERENCES Genres(genre_id)
-- (book_id, genre_id) is UNIQUE pairing
I want to be able to SELECT for books that have some desired genres. Let's say, I want to return all book_id where the book has the genres 'Adventure' and 'Fantasy'. The best I've been able to do is a self INNER JOIN and checking if the pairing ('Adventure', 'Fantasy') exists and returning that book_id, but this is terribly slow and if I'm searching for n genres relationships, I need n INNER JOINS! (unacceptable). My query looks something like this:
SELECT t1.book_id
FROM BookGenres as t1
INNER JOIN Genres as t2
ON t2.genre_id = t1.genre_id
INNER JOIN BookGenres as t3
ON t3.book_id = t1.book_id
INNER JOIN Genres as t4
ON t4.genre_id = t3.genre_id
WHERE t2.genre_name = 'Adventure' AND t4.genre_name = 'Fantasy'
To search for Books that have n specified relationships to desired Genres, I do n self INNER JOINS and check if such a pairing exists. This seems forbiddingly inefficient and I would like a bit of help on this query as I'm sure it is a common problem.
For starters, your relationship between Books and Genres is a Many to Many relationship, not a One to Many relationship.
As I understand your question, you want to return a list of all books that match all selected genres. Assuming you want additional information about the book, I have included the Books table
SELECT
Books.book_id
FROM
Books
WHERE
book_id IN (SELECT book_id
FROM BookGenres INNER JOIN Genres ON BookGenres.genre_id = Genres.genre_id
WHERE Genre.genre_name = 'Adventure') AND
book_id IN (SELECT book_id
FROM BookGenres INNER JOIN Genres ON BookGenres.genre_id = Genres.genre_id
WHERE Genre.genre_name = 'Fantasy')

need help with mysql for book system - problem with where clause

hello all im developing new project for publisher ...this project for develop system saved all books for that publisher ...............
we have 3 table
books
author
coauthor
problem case:
ieach book have 1 main author thats author could replay in alot of books and ieach book in some cases could have co-author this co author could be 1 or 2 or 3 or 12 note: this co author is already saved in author table
realtionship:
one to many between authors and books
many to many between coauthor and books and authors
table #1 authors table => table hold all authors
id - author_name
table #2 books table => table hold all books
id- title - author_id - publishing_year
table #3 co_authors table => hold all item which have alot of co author
item_id and authors_id
now how i can retrive all books for specific author if he is main author or co author
There're two ways you can go about this... One is to use a UNION, so something like:
SELECT id FROM books WHERE author_id = ?
UNION ALL
SELECT item_id FROM co_authors WHERE authors_id = ?
Another way you could solve this is to rework your database structure such that there is no author_id in the books table and instead you have a flag in co_authors called main_author or some such. Considering you may have books where it's unclear who the main author is, this may make more sense...
You can do something like this :
SELECT DISTINCT books.*, authors.*
FROM books
LEFT JOIN co_authors ON co_authors.item_id = books.id
INNER JOIN authors ON
authors.id = books.author_id OR
authors.id = co_authors.author_id
WHERE authors.id = ID
The where clause can also be written where authors.name = 'NAME' if you need to search by name and not id.
EDIT: added distinct to avoid multiple rows for the same book.

Subquery returns more than one row SQL

I have executed a code
SELECT CASE b.ON_LOAN
when 'Y' then
'In Lib'
when 'N' then
(SELECT c.duedate from book_copy a, book b, loan c
where b.isbn = 123456
and a.isbn = b.isbn
and a.book_no = c.book_no)
END AS Availability, a.isbn, a.class_number
FROM book_copy b, book a
where a.isbn = b.isbn and a.isbn = 123456
it returns an error saying subquery returns more than one row . I am trying to get the availability for a book. A book can have more than one copy, that is identified by its book_no. If a copy is available it should retrun just 'In lib' otherwise, the duedate from loan table. E.g if a book has three copies, 2 out and 1 in lib, i want my query to show all three copies. I think i am missing an outer join. Could you please clarify.
My tables that i use for this are
book_copy: book_no, isbn, on_loan
loan: student_id, book_no, duedate,datereturned,loan_id
fk: book_no with book_no in book_copy
book: isbn (pk), title, class
thanks,
rk
The problem is in:
(SELECT c.duedate from book_copy a, book b, loan c where b.isbn = 123456 and a.isbn = b.isbn and a.book_no = c.book_no)
You actually only want the loan table, but use MAX to make sure it only returns one row.
(SELECT MAX(c.duedate) from loan c where a.book_no = c.book_no)
So... you can hook into the tables in the outer query - no need to use a and b again.
Rob
I would first get rid of those implied joins. Then I would use a derived table instead of a correlated subquery (Never use a correlated subquery they are performance dogs!)
SELECT
CASE b.ON_LOAN
WHEN 'Y' THEN 'In Lib'
WHEN 'N' THEN c.duedate END
AS Availability,
a1.isbn,
a.class_number
FROM book_copy b
JOIN book A1
ON a1.isbn = b.isbn
JOIN (SELECT MIN(c.duedate), c.isbn FROM loan c
join book a
on a.a.isbn = c.isbn
WHERE a.isbn = 123456 AND datereturned is null
GROUP BY c.isbn
) c
ON a1.isbn = c.isbn
WHERE a.isbn = 123456
Originally, I used max because you have given us no indciator of how to chosse which of the records in the loan table to pick when you only want one. However, I suspect there is a better way (or at least I hope your design has a better way) to find the book that is out. Maybe you have a field that indicates the book has been returned or maybe you want the date of the first book that is available to be returned not the latest date to be returned. Don't use max without thinking about how to get just one record. Otherwise you may be writing a query that works but it is incorrect in its results. Based on your comment below I have revised the query.
The key to understanding this is that the derived table should bring back the record that has not yet been returned but which should be available soonest (ie it has the earliest due date). If my query doesn't do that, then you will need to experiement until you find one that does. The final where clause may or may not be necessary, you should check that as well. It depends on whether the book numbers are unique or if they are repeated for differnt books.