How to construct a SQL query involving max values? - sql

I have the following psql tables with the following columns:
Library:
library_id
Shelf:
shelf_id
library_id (Library foreign key)
forbidden = (boolean)
Author
author_id
shelf_id (Shelf foreign key)
number_pages_witten
Book
book_id
author_id (Author foreign key)
book_name
I need a query that retrieves the following back:
For library_id=5, get the list of book names from authors who have written the most pages per shelf, for all shelves that have "forbidden" = False
I have the following so far:
SELECT name FROM Book AS b
INNER JOIN Author AS a
ON b.author_id = a.author_id
...
...
WHERE library_id=5
My sql syntax is very weak. I'm having trouble getting the author with the most number of pages on the shelf back and plug it into rest of the query. Thank you.

The requirement to get "authors who have written the most pages per shelf, for all shelves that have "forbidden" = False" is a classic usecase for the rank() window function. From there on, you just need an inner queries:
SELECT name
FROM book b
WHERE b.author_id IN (SELECT author_id
FROM (SELECT a.author_id,
RANK() OVER
(PARTITION BY a.shelf_id
ORDER BY number_pages_written DESC) rk
FROM author a
JOIN shelf s ON a.shelf_id = a.shelf_id
WHERE library_id = 5)
WHERE rk = 1)

This query simultaneously retrieve list of most pages book per author and per shelf,
At first, It's prepared a list of Author Id, Shelf Id and Number Pages Written by a self-join that has the same Author Id and Shelf Id but their Number Pages Written are different,
Then, Group by Author Id and Shelf Id
I hope it can be helpful for your question and all relate issues
select author_id1, shelf_id1, max(num_pages1)
(
select
Author1.author_id author_id1, Author1.shelf_id shelf_id1, Author1.number_pages_witten num_pages1,
Author2.author_id author_id2, Author2.shelf_id shelf_id2, Author2.number_pages_witten num_pages2
from Author Author1 left join Author Author2
on Author1.author_id = Author2.author_id and Author1.shelf_id = Author2.shelf_id
and Author1.number_pages_witten != Author2.number_pages_witten
)ds
group by author_id1, shelf_id1

Related

Query in a way to show books that belong to different authors

select subject, authors, authorID
from library with (nolock)
inner join authors with (nolock) bookid = bookauthorID
where subject = 'Russian History'
So I want to write a query that will show that all the authors that have written books on Russian History, and I want to show column categoryID as "multiple" if there are more than 2 different authors that written on the subject, and vice versa as "single".
Example:
CategoryID Author
2009940 Steve Cohen
From the above ID, it would return as single, since there's only one distinctive author on this ID.
Would be the best to achieve this using count(min)?
You don't provide a desired output nor do I believe you have shared the appropriate objects for your tables/columns but you can alter this for your needs.
You just need to reference a COUNT(DISTINCT columnName) to see if its greater than 1 or not.
select
subject
, CASE WHEN COUNT(DISTINCT authors) = 1 THEN 'single'
WHEN COUNT(DISTINCT authors) > 1 THEN 'multiple'
END AS Authors
from library
inner join authors bookid = bookauthorID
where subject = 'Russian History'
GROUP BY subject

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

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

SQL Query needed to get information from TWO separate tables

I am trying to create a query that will list all books by the same author. Most of the list has only one book by one author, but I want the author that has multiple books listed in db to display those book for that author.
I have two tables:
Book - AuthorID, BkTitle, etc
Author - AuthorID, AuthFName, AuthLName
I want the result to be sorted by AuthLName and the report to consist of any books in db that have same authorid.
Example result wanted:
AUTHORID BKTITLE AUTHFNAME AUTHLNAME
--------- ----------------- ------------ -----------
504 KNIGHT FREEDOM Chris Feehan
504 KNIGHT SHOWDOWN Chris Feehan
Currently, I have the following code:
select AUTHORID, BKTITLE
from BOOK
where AUTHORID in
(select AUTHORID from
(select AUTHORID,
count(*) as BOOK_COUNT
from BOOK
group by AUTHORid
order by AUTHORid )
where BOOK_COUNT >= 2);
which gives:
AUTHORID BKTITLE
---------- --------------------
504 KNIGHT FREEDOM
504 KNIGHT SHOWDOWN
I need to find a way to get the information from the Author Table and add it in this.
This should do:
SELECT b.AUTHORID, b.BKTITLE, a.AUTHFNAME, a.AUTHLNAME
FROM BOOK b
INNER JOIN AUTHOR a
ON b.AUTHORID = a.AUTHORID
AND b.AUTHORID IN
(
SELECT AUTHORID
FROM BOOK
GROUP BY AUTHORID
HAVING COUNT(AUTHORID) > 1
)
ORDER BY a.AUTHLNAME, a.AUTHFNAME
How about this - updated to use a CTE (Common Table Expression) first to figure out which authors have more than one book in the database table BOOK, and then listing only those authors and their books:
;WITH AuthorsWithMoreThanOneBook AS
(
SELECT AUTHORID, BOOK_COUNT = COUNT(*)
FROM BOOK
GROUP BY AUTHORID
HAVING BOOK_COUNT > 1)
)
SELECT
b.AUTHORID, b.BKTITLE, a.AuthFName, a.AuthLName
FROM
BOOK b
INNER JOIN
AUTHOR a ON b.AuthorID = a.AuthorID
INNER JOIN
AuthorsWithMoreThanOneBook A2 ON a.AuthorID = A2.AuthorID
ORDER BY
a.AuthLName, a.AuthFName
Update: OK, you're using Oracle .... not sure (haven't used it in ages) - but can't you just extend your original query something like this:
select bk.AUTHORID, bk.BKTITLE, a.AUTHORFNAME, a.AUTHORLNAME
from BOOK AS bk
INNER JOIN AUTHOR AS a ON a.AUTHORID = bk.AUTHORID
where bk.AUTHORID in
(select AUTHORID from
(select AUTHORID,
count(*) as BOOK_COUNT
from BOOK
group by AUTHORid
order by AUTHORid )
where BOOK_COUNT >= 2);
Not sure if/how Oracle supports those table aliases (BOOK AS bk) - but I'm pretty sure it does support it some way or another....
You can do this with only one access to each table:
SELECT * FROM
(
SELECT AuthorID, BkTitle, AuthFName, AuthLName
,COUNT(*) OVER (PARTITION BY AuthorID)
AS c
FROM BOOK
JOIN AUTHOR USING (AuthorID)
)
WHERE c > 1;

In a Many to Many relationship, how can records collectively owned be selected

I'm sure I'm missing the correct terminology here, but for this example many-to-many relationship:
A user has many books. A book is owned by many users.
What's the best way to see all books owned by both of two users?
Right now I'm just using this:
SELECT * FROM books
WHERE book_id IN
(SELECT book_id FROM user_has_book WHERE user_id = 'joe' AND book_id IN
(SELECT book_id FROM user_has_book WHERE user_id = 'frank'))
I know that can't be the best way to do this - right? I'm using MySQL
SELECT b.*
FROM books b
INNER JOIN
(SELECT book_id, COUNT(*) as cnt
FROM user_has_book
WHERE user_id IN ('Frank', 'Joe')
GROUP BY book_id
HAVING cnt=2)x ON (x.book_id = b.book_id)