SQL How to select rows based on values from multiple rows - sql

Hi I ran into a problem regarding the following tables
CREATE TABLE BOOKS (
Title varchar(255),
Year INT,
Type ENUM("Horror", "Fantasy"),
Pages INT,
PRIMARY KEY (Title, Year)
);
CREATE TABLE AUTHORS(
Title varchar(255),
Year INT,
PlaceOfBirth varchar(255),
AuthorName varchar(255),
PRIMARY KEY (Title, Year, PlaceOfBirth ),
FOREIGN KEY (Title, Year) REFERENCES BOOKS(Title, Year)
);
Now i want to query all Authors who only have horror books with 40 pages and more.
SELECT a.AuthorName, b.Pages FROM AUTHORS a INNER JOIN BOOKS b ON a.Title=b.Title AND a.Year=b.Year
WHERE b.Type="Horror" AND b.Pages > 40
The problem is now I get those authors which have written horror books with more than 40 pages but they could also have horror books with less than 40 pages. I Want those Authors which only wrote horror books that are 40 pages or longer.

If you want the name of authors that have written at least one horror book and whose all such books have more than 40 pages, you can use group by and having:
select a.authorname
from authors a
inner join books b on a.title = b.title and a.year = b.year
where b.type = 'Horror'
group by a.authorname
having min(b.pages) > 40

Related

Printing authors in descending order per sold copies per year

I have two tables
create table AUTHORS
(
id integer primary key,
name varchar(30)
)
create table BOOKS
(
id integer primary key,
name varchar(30),
year integer,
sold_copies integer,
author_id integer references AUTHORS (id)
)
How would I create a table with authors in descending order per sold copies of books per year in pgAdmin4 (PostgreSQL) ?
im a beginner and I am not sure how to go about this
I don't see why you would need to create a new table. A simple SELECT will do (maybe stored inside a view)
select a.id, a.name, b.year, sum(b.sold_copies) as total_copies
from author a
join books b on b.author_id = a.id
group by a.id, a.name, b.year
order by sum(b.sold_copies) desc;

Select Titles of All Books Without any Rating

create table books
(
id int,
title varchar(250),
year int,
author varchar(250)
);
create table reviewers
(
id int,
name varchar(250)
);
create table ratings
(
reviewer_id int,
book_id int,
rating int,
rating_date date
);
Select titles of all books without any rating
Now so far I have this
SELECT *
FROM Books
INNER JOIN Book.ID ON Reviewer.ID
WHERE Reviews.review = 'NULL'
In your case the Ratings table serves as a table connecting ´Books´ and ´Reviewers´.
So to check if there are no ratings you can simply:
SELECT b.*
FROM books b
WHERE NOT EXISTS (SELECT book_id FROM ratings r WHERE r.book_id = b.id)
Meaning that this is showing all the books that do not have any rating.
PS: You don't need INNER JOINs, since you don't need any information from the rating and reviewers table (since there is none).
The way your question is phrased, think "not exists": You want books where a review does not exist:
SELECT b.*
FROM Books b
WHERE NOT EXISTS (SELECT 1 FROM Ratings r WHERE r.BookId = b.id);

Listing columns from multiple tables in sql

I've got a database which is formed like this:
BOOKTYPES ( book_type_id (PK), book_type )
CATEGORIES ( category_id (PK), category )
PUBLISHERS ( publisher_id (PK), publisher, speciality, country )
BOOKS ( book_id (PK), title, publisher_id (FK), published_year,
purchase_price, category_id (FK),purchase_date, pages,
book_type_id(FK) )
AUTHORS ( author_id (PK), first_name, last_name, pseudonym )
AUTHORSHIP ( author_id (PK), book_id (PK) )
Now, what I need help with is listing category and the number of books that contain that category. This means that I need to retrieve the category from CATEGORIES, and category_id from books. The problem I'm facing with this is that category_id already exists inside categories, and that isn't the one that I want to retrieve.
I'd really appreciate some help with this since it's been picking my brain for quite the while now.
listing category and the number of books that contain that category
That looks like a simple aggregate query on books:
SELECT category_id, COUNT(*) count_of_books FROM books GROUP BY category_id
If you want the category name as well, you can JOIN on categories. You do disambiguate the column names by prefixing them with the table they belong to (or the table alias):
SELECT c.category, COUNT(*)
FROM books b
INNER JOIN categories c ON c.category_id = b.category_id
GROUP BY c.category_id, c.category
To filter on a given count of categories, you can use a HAVING clause:
SELECT c.category, COUNT(*)
FROM books b
INNER JOIN categories c ON c.category_id = b.category_id
GROUP BY c.category_id, c.category
HAVING COUNT(*) > 5

How to write this select statement that counts if profit is < 55% of the cost of the item?

I'm a new student to database and I've come across a question in my book that I'm having a hard time solving. Pretending I'm the DBA of this bookstore...
I need to determine which books are generating less than 55% profit and how many copies of the books have been sold. Here is what I have tried doing:
SELECT title, COUNT(*)
FROM books
WHERE (retail-cost) >= .55 * cost group by title;
But when I run that, I just get this:
DATABASE IMPLEMENTATION 1
PAINLESS CHILD-REARING 1
HOW TO GET FASTER PIZZA 1
SHORTEST POEMS 1
BIG BEAR AND LITTLE DOVE 1
BODYBUILD IN 10 MINUTES A DAY 1
HOLY GRAIL OF ORACLE 1
HOW TO MANAGE THE MANAGER 1
COOKING WITH MUSHROOMS 1
BUILDING A CAR WITH TOOTHPICKS 1
Clearly, it's not right. How do I do this?
Here is my table structure:
CREATE TABLE Books
(ISBN VARCHAR2(10),
Title VARCHAR2(30),
PubDate DATE,
PubID NUMBER (2),
Cost NUMBER (5,2),
Retail NUMBER (5,2),
Discount NUMBER (4,2),
Category VARCHAR2(12),
CONSTRAINT books_isbn_pk PRIMARY KEY(isbn),
CONSTRAINT books_pubid_fk FOREIGN KEY (pubid)
REFERENCES publisher (pubid));
CREATE TABLE ORDERITEMS
( Order# NUMBER(4),
Item# NUMBER(2),
ISBN VARCHAR2(10),
Quantity NUMBER(3) NOT NULL,
PaidEach NUMBER(5,2) NOT NULL,
CONSTRAINT orderitems_pk PRIMARY KEY (order#, item#),
CONSTRAINT orderitems_order#_fk FOREIGN KEY (order#)
REFERENCES orders (order#) ,
CONSTRAINT orderitems_isbn_fk FOREIGN KEY (isbn)
REFERENCES books (isbn) ,
CONSTRAINT oderitems_quantity_ck CHECK (quantity > 0) );
You need to make a join to see how many of your books has been sold
SELECT b.ISBN, b.Title, COUNT(ISBN)
FROM books AS b
INNER JOIN ORDERITEMS AS oi ON oi.ISBN = b.ISBN
WHERE Retail >= .55 * Cost
GROUP BY b.ISBN, b.Title;
in your posted request ... count(*)... group by title returns the number of rows for each title in the table Books, that' s why you always obtain 1.
What you want is to sum the quantity in orderItems, and get the title with isbn matching value in table books. I would do something like this :
select Books.title, sum(ORDERITEMS.Quantity) as numberOfSales from ORDERITEMS
left join Books
on ORDERITEMS.isbn = Books.isbn and Books.cost <= (retail-cost/.55)
group by title
Try out this statement:
SELECT Title, COUNT(*)
FROM books
WHERE (retail-cost) >= (0.55 * (retail-cost))
group by Title;
SELECT ISBN,TITLE,SUM(QUANTITY)
FROM BOOKS JOIN ORDERITEMS USING(ISBN)
WHERE (RETAIL-COST)/COST<.55
GROUP BY ISBN, TITLE

How can we retrieve same data in one table?

I need one very expert help, I can't seem to find the answer to this, the problem is, find the titles and ISBNs of books that have the same title and publishers as at least 2 other books.
Order it by title.
So basically, everything is coming from the book table.
CREATE TABLE BOOK
(
ISBN VARCHAR2(20),
Title VARCHAR2(250) NOT NULL,
YearPublished NUMBER(4) NOT NULL,
PublisherName VARCHAR2(40) NOT NULL,
CONSTRAINT pk_isbnP PRIMARY KEY(ISBN)
);
Here is my rough draft:
select _____
from book b2
where ______ (select____ from book b2
where _____ = ______ and ______ =______)
Step 1: Find combinations of title and publisher that have at least 2 books:
SELECT title, PublisherName
FROM BOOK
GROUP BY title, PublisherName
HAVING COUNT(*) > 1
Step 2: find all other books that have this title and publisher:
SELECT *
FROM Books b1
WHERE EXISTS(
SELECT title, PublisherName
FROM BOOK b2
WHERE b1.title = b2.title AND b1.PublisherName = b2.PublisherName
GROUP BY title, PublisherName
HAVING COUNT(*) > 1
)
This ought to do it:
select isbn, title
from books
where (title,publishername) in(select title,publishername
from books
group by title,publishername
having count(*) >=3)
order by title;
select b1.title, b1.isbn
from book b1
inner join
(select title, publishername
from book
group by title, publishername having count(*) > 2) b2
on b1.title = b2.title and b1.publishername = b2.publishername
order by b1.title
The inner query fetches the titles/publishers of books where there are three or more duplicates. The outer query uses those results to get the associated ISBNs.
You can use group by statement here.
SELECT title
,isbn
FROM BOOKS
group by title, isbn
having COUNT(1) >= 2 order by title;