Select information from 3 tables in SQL - sql

I have three tables in a SQLite database: book, author and loaned_books. They look like this
book: _id | author_id | title | subject
author: _id | first_name | last_name
loaned_books: _id | book_id | loan_date | due_date
The author_id is a foreign key for the author table, and the book_id is a foreign key for the book table.
I am trying to create a query that extracts all the books (with their associated author) which are not loaned. So far, I have this query:
SELECT book.title, book.subject, author.first_name, author.last_name
FROM book, author
INNER JOIN loaned_books ON book._id != loaned_books.book_id AND book.author_id = author._id
This one does the job with the exception that all the records returned are duplicated. I have tried using DISTINCT on the column names, but the result is wrong as well.
What would be a query that returns all the books (with their associated author) that are not loaned?

The way you join book and author:
FROM book, author
is wrong because it returns the cartesian product of the 2 tables.
You need a LEFT JOIN to loaned_books and return the non matching rows (meaning the books that don't exists in loaned_books)
SELECT b.title, b.subject, a.first_name, a.last_name
FROM book AS b
INNER JOIN author AS a ON b.author_id = a._id
LEFT JOIN loaned_books AS l ON b._id = l.book_id
WHERE l._id IS NULL

Could you please try executing this:
SELECT distinct book.title, book.subject, author.first_name, author.last_name
FROM book inner join author on book.id = author._id left outer join loaned_books ON book._id = loaned_books.book_id where loaned_books.book_id is null or length(loan_date) = 0 or loan_date = ''

Related

update SQL WHERE BOOKNO = BOOK number in temp table

I have a table Books which has its bookauthorID in another table that is Author
BOOK
ID BOOK NAME AUTHORID
0 A NULL
1 B NULL
2 C NULL
AUTHOR
BOOKID AUTHORID
0 123
1 1234
2 12345
Now I have to fill up AuthorID column in Book table from Author table where BOOK.ID = AUTHOR.BOOKID as the BOOK.AUTHORID column was added later in the table
So far
I have this
WITH ALLBOOKSANDAUTHORIDS AS
(
SELECT * FROM BOOK INNER JOIN AUTHOR on BOOK.ID = AUTHOR.BOOKID
)
I now have a table telling each book and its author ID
but how can I update the BOOK.AUTHORID with correct values, getting values from Author table and putting them in book ?
It is like a for loop where go to each row in Book table and check which ID matches in the Author table, then get the AUTHORID and update it in book table.
Please tell how to write the SQL ?
Thanks
Aiden
You can do this with an update/join:
update b
set b.authorid = a.authorid
from book b join
author a
on b.id = a.bookid
where b.authorid is null;
Simply join those table and do update.
update book b join author a on (a.bookid=b.id)
set b.AUTHORID=a.AUTHORID
UPDATE BOOK
SET AUTHORID = AUTHOR.AUTHORID
FROM BOOK INNER JOIN AUTHOR ON BOOK.ID = AUTHOR.BOOKID
First of all ID can not be Zero, And ans to your question is may be simaple Update statement with join
Update B
SET B.AUTHORID=A.AUTHORID
FROM Book B
INNER JOIN AUTHOR A ON A.BOOKID = B.ID
We can also do this I think
Update b
Set b.AUTHORID = ( Select top 1 a.AUTHORID From AUTHOR a
where b.ID = a.BOOKID)

SELECTing specific information with SQL

I created a database from the following flow-chart:
Populated according to this:
There is a book called 'The Lost Tribe'.
There is a library branch called 'Sharpstown' and one called 'Central'.
There are at least 20 books in the BOOK table.
There are at least 10 authors in the BOOK_AUTHORS table.
Each library branch has at least 10 book titles, and at least two copies of each of those titles.
There are at least 8 borrowers in the BORROWER table, and at least 2 of those borrowers have more than 5 books loaned to them.
There are at least 4 branches in the LIBRARY_BRANCH table.
There are at least 50 loans in the BOOK_LOANS table.
There must be at least one book written by 'Stephen King'
I am trying to find how many copies of the book titled The Lost Tribe are owned by the library branch whose name
is "Sharpstown". Now I know that by finding out what the BranchId of Sharpstown is I could just run the following query:
SELECT No_Of_Copies FROM BOOK_COPIES WHERE BookId = 1 and BranchId = 1
But is there a way to search by using the actual name "Sharpstown"?
Thank you for your help, I am quite new to SQL SERVER and don't know how specific one user can get with queries.
For library branch, you could use IN
SELECT No_Of_Copies FROM BOOK_COPIES
WHERE BookId = 1
AND BranchId IN (SELECT BranchId
FROM library_branch
WHERE BranchName = 'Sharpstown');
Sure it's possible.
It will look something like this if you wanna use correlated subquery:
SELECT No_Of_Copies FROM BOOK_COPIES
WHERE BranchId IN (
SELECT BranchId FROM LIBRARY_BRANCH WHERE BranchName = "Sharpstown")
AND BookId IN (
SELECT BookId FROM BOOK WHERE Title = "The Lost Tribe" )
Or you could use joins as #Sachin suggested in another answer.
You have to use Join for that requirement. You have to join BOOK_COPIES with LIBRARY_BRANCH and BOOK table, then you can find by BranchName
SELECT No_Of_Copies
FROM BOOK_COPIES inner join LIBRARY_BRANCH
on BOOK_COPIES .BranchId = LIBRARY_BRANCH.BranchId
inner join BOOK
on BOOK_COPIES.BookId = BOOK.BookId
WHERE BOOK.Title = "The Lost Tribe" and LIBRARY_BRANCH.BranchName = "Sharpstown"
try this.
SELECT No_Of_Copies FROM BOOK_COPIES
WHERE BranchId in
(
select BranchId from library_branch
where branchname like '%Sharpstown%'
)
and BookId in
(
select BookId
from book where title like
'%The Lost Tribe%'
)
SELECT No_Of_Copies FROM BOOK_COPIES
LEFT JOIN LIBRARY_BRANCH on BOOK_COPIES.BranchId=LIBRARY_BRANCH.BranchId
WHERE BookId = 1 and BranchName = 'Sharpstown'
SELECT No_Of_Copies
FROM BOOK_COPIES
WHERE BookId=(SELECT BookId FROM BOOK WHERE Title="The Lost Tribe")
AND branchid=(SELECT BranchId FROM LIBRARY_BRANCH WHERE BranchName="Sharpstown")
Use Title="The Lost Tribe" if you are looking for exact match and it will faster then using Title LIKE "%The Lost Tribe%"
In case you want to get the book id dynamically as well, you can use inner join.
SELECT BC.NOOFCOPIES FROM
BOOK_COPIES BC INNER JOIN BOOK B ON B.BOOKID = BC.BOOKID
INNER JOIN BRANCH BR ON BC.BRANCHID = BR.BRANCHID
WHERE BR.BRANCHNAME = 'SHARPSTOWN';

Join 3 tables with different FKs

I'm trying to join 3 tables together in a SELECT query with some WHERE clauses.
Table 1 is linked to Table 2, and Table 2 is linked to Table 3.
The tables are as follows:
Author
PK: Author_ID
FK: Location_ID
Author_First_Name
Location
PK: Location_ID
City
Articles
PK: Article_ID
FK: Author_ID
Article_Name
So far I've put together this Query, but am having trouble determining how to to Join the second Foreign Key 'Location_ID'
SELECT
Articles.Article_Name
FROM
Articles
INNER JOIN Author
ON Articles.Author_ID
INNER JOIN Location
ON
WHERE Author.Author_First_Name='Sam'
AND Location.City<>'Detroit'
The proper syntax is something like this:
SELECT a.Article_Name
FROM Articles a INNER JOIN
Author au
ON a.Author_ID = au.Author_ID INNER JOIN
Location l
ON l.Location_ID = au.Location_Id
WHERE au.First_Name = 'Sam' AND l.City <> 'Detroit';
Note the use of table aliases make the query easier to write and to read. Also, you need conditions connecting the two tables for the ON clauses.
You forgot to compare table fields
SELECT * FROM articles ar
LEFT JOIN author a ON ar.author_id = a.author_id
LEFT JOIN location l ON a.location_id = l.location_id
WHERE a.author_first_name = 'Sam' AND l.city <> 'Detroit'

How do i select datas from two different tables when count() = 2 with join?

I have a db with 3 tables, as following
CREATE TABLE Person
(id_pers number (3),
name varchar(20) NOT NULL,
phone number (15),
PRIMARY KEY(id_pers)
);
CREATE table Book(
id_book number(3),
title varchar(30),
about varchar (200),
nr_of_books number (3),
type varchar (11),
PRIMARY KEY(id_book)
);
CREATE table Author(
id_book number(3),
id_aut number(3),
FOREIGN KEY (id_book) REFERENCES Book(id_book),
FOREIGN KEY (id_aut) REFERENCES Person(id_pers)
);
I want to display the title of the book that has exactly 2 authors and the name of the authors which wrote the book. Example "Book1 - Author1, Author2"
All i managed to do is to take the book id and the number of authors but i want them more precisely.
The code that I wrote is this:
SELECT au.id_book, count(au.id_aut)
FROM author au join book bk ON au.id_book = bk.id_book
JOIN person p ON p.id_pers = au.id_aut
GROUP BY au.id_book
HAVING COUNT(au.id_aut) = 2;
everything I thought about had as result either "no group by expression" either some error because of the syntax.
Should I make a nested query? if so, what should i type in "where" to be equal to this?
I'm so confused. Any help would be appreciated.
This will include your title in the result, and it won't give errors about missing group by. I am not sure this is all you want, though...
SELECT au.id_book, bk.title, count(au.id_aut)
FROM author au
JOIN book bk
ON au.id_book = bk.id_book
JOIN person p
ON p.id_pers = au.id_aut
GROUP BY au.id_book, bk.title
HAVING COUNT(au.id_aut) = 2;
In order to include the authors names, I resorted to something a bit more elaborate:
DECLARE #result varchar(500)
DECLARE #numAut int
SET #result = ''
SET #numAut = 2
SELECT #result = #result + [Name] + ', '
FROM person WHERE id_pers in
(SELECT id_aut FROM author WHERE id_book in
( SELECT id_book FROM author
GROUP BY id_book HAVING COUNT(*) = #numAut)
);
SELECT bk.title, #result
FROM author au JOIN book bk ON au.id_book = bk.id_book
GROUP BY au.id_book, bk.title
HAVING COUNT(*) = #numAut;
First, we enumerate the names of the authors that appear in the "books with N authors"-list. This result Is then included in th (now a bit simpler) actual query, where I basically only select the titles of the books in that same list.
This works, but i am wondering if there is not a more elegant way...
SELECT au.id_book, count(au.id_aut)as count
FROM author au join book bk ON au.id_book = bk.id_book
JOIN person p ON p.id_pers = au.id_aut
GROUP BY au.id_book
HAVING (count=2)
Given your data structure, I don't think the joins are necessary.
Although your query looks fine, the following simpler version may also work:
SELECT au.id_book, count(au.id_aut)
FROM author au
GROUP BY au.id_book
HAVING COUNT(au.id_aut) = 2;
In order to display the book title and the authors you're going to need a GROUP_CONCAT:
SELECT au.id_book, bk.title, count(au.id_aut), GROUP_CONCAT(p.name) authors
FROM author au
JOIN book bk ON au.id_book = bk.id_book
JOIN person p ON p.id_pers = au.id_aut
GROUP BY au.id_book, bk.title
HAVING COUNT(au.id_aut) = 2

SQL Query Using Data from 2 tables

I have 2 tables: authors and books.
in authors i have attributes authorID, authorName, and authorDOB.
authorID is the primary key in this table.
in the books table i have attributes bookISBN, authorID, etc.
with bookISBN as the primary and authorID as the foreign key
i am trying to perform a query where given an author name, perform a
count of all the books by that author.
here is what i got:
SET #ID =
AuthorID
FROM authors
WHERE ('Mark Twain' = AuthorName);
SELECT COUNT(*)
FROM books
WHERE (AuthorID = ID);
Any help would be greatly appreciated
Try:
SELECT a.authorId, a.authorName, count(*)
FROM authors a
INNER JOIN books b ON b.AuthorID=a.AuthorID
WHERE ('Mark Twain' = a.AuthorName)
GROUP BY a.authorId, a.authorName
i am trying to perform a query where given an author name, perform a count of all the books by that author.
Try
select count(1)
from books b
inner join authors a on a.AuthorID=b.AuthorID
where a.AuthorName='Mark Twain'
You can use a function as well if you think you'd be doing the search more frequently. Just an idea.
go
create function totalbooksbyauthor (#authorname varchar(20) ) returns table
as return
select a.authorid, a.authorname, COUNT(b.bookname) bookcount
from authors a
inner join books b
on a.authorID = b.authorID
where a.authorname = #authorname
group by a.authorid, a.authorname
go
select * from totalbooksbyauthor ('Mark Twain')