Select Titles of All Books Without any Rating - sql

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

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;

SQL How to select rows based on values from multiple rows

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

Sql query to find select customer that bought in the specific company address

Here is my table
CREATE TABLE Customer
(
ID CHAR(50),
Customer_FName CHAR(50),
Customer_Lname CHAR(50)
);
CREATE TABLE Buying
(
Customer_ID CHAR(50),
Product_ID CHAR(50),
Order_Time CHAR(50)
);
CREATE TABLE Product
(
ID CHAR(50),
Name CHAR(50),
Address CHAR(50)
);
I am trying to find all customers who bought a product with their company's address in 'Burwood' and list the customer's ID, names, product ID, product name and product address
Select
Buying.Customer_ID, Buying.Product_ID, Product.ID,
Product.Name, Customer.ID,
Customer.Customer_FName, Customer.Customer_Lname
from
((Buying
inner join
Product on Buying.Product_ID = Product.ID)
inner join
Customer on Buying.Customer_ID = Customer.ID)
where
Product.Address like '%Burwood%';
I want to combine three table but It shows 'no rows selected'.
I also give a sample data table
Any reason why you have chosen CHAR as the datatype for all columns of all tables? For CHAR based columns, DBs tend to pad the values up to the column width defined. That said, it is not why you are not getting result. You may want to check if during insert you are adding any extra space or non-printable characters in IDs resulting into failed inner joins.
I suggest change the fields to VARCHAR instead, validate your inserts and then query just as I demonstrated below. You will start getting result, as I am..
CREATE TABLE Customer (
ID varchar(50),
Customer_FName varchar(50),
Customer_Lname varchar(50)
);
CREATE TABLE Buying (
Customer_ID varchar(50),
Product_ID varchar(50),
Order_Time varchar(50)
);
CREATE TABLE Product (
ID varchar(50),
Name varchar(50),
Address varchar(50)
);
insert into customer values('10001', 'John', 'Smith');
insert into Buying values('10001', '772', '2016/09/01');
insert into Product values('772', 'Telephone', '22 Ave, Burwood');
select b.product_id, p.name, b.customer_id, c.customer_fname, c.customer_lname
from buying b
join product p on b.product_id = p.id
join customer c on b.customer_id = c.id
where lower(p.address) like '%burwood%'
Please try this, it works for me:
Select B.Customer_ID, B.Product_ID, P.ID, P.Name, C.ID, C.Customer_FName, C.Customer_Lname
from Buying B
INNER JOIN Product P ON B.Product_ID = P.ID
INNER JOIN Customer C ON B.Customer_ID = C.ID
WHERE P.Address LIKE '%Burwood%'
Try this:
SELECT C.*,B.*, P.*
FROM Customer C,Buying B, Product P
WHERE B.Product_ID=P.ID
AND B.Customer_ID=C.ID
AND P.Address LIKE '%Burwood%';

Create tables with Many-to-One relation in Postgresql

I am a newbie with Postgresql and database . I have the following table Shop
Create table Shop(
id integer ,
Name varchar(50),
Adress varchar(50) )
And I have a second table Product
Create table Product(
id integer ,
Name varchar(50),
Price float)
How to create a relation One-To-One between Product and Shop ?
Use a separate table, called a junction table or join table (and unfortunately has many other names)
CREATE TABLE Products_in_shop (
shop_id INTEGER,
product_id INTEGER
)
You can then JOIN them for specific queries, e.g. the products a specific shop carries:
SELECT p.Name
FROM Shop AS s
JOIN Products_in_shop AS pis ON pis.shop_id = s.id
JOIN Product AS p ON pis.product_id = p.id
WHERE s.Name = 'MyShop'

Most efficient SQL for this example

Table A: Person: id, name
Table B: Toys: id, person_id, toy_name
I have a search screen that includes a dropdown of fixed toy names.
A search is found if a subset of the total set of toys for a person is matched.
Example, a person name=bob has toys: doll, car, house, hat
A search is done for person name=bob and toys=doll, hat.
I want to return bob and ALL of his toys, not just what toys were searched for(doll, hat).
Bob is found because a subset of his toys are a match.
I don't know what the most efficient/least db calls way to accomplish this.
I can do a search for bob and get all of his toys, then parse through the result set to see if the searched for toys find a match, but that seems wrong, that the db call could return rows for which no match is found (and that seems wrong?).
okay,
select
p.id,
p.name,
t.id as toyid,
t.toy_name
from
person p
join
toys t
on p.id = t.person_id
where
p.id in (
select person_id from toys where toy_name = 'doll'
intersect
select person_id from toys where toy_name = 'hat');
Fiddle Here
If you normalise your schema a little further,
create table Person
(
Id int,
Name varchar(100)
);
create table Toy
(
Id int,
Name varchar(100)
);
create table PersonToy
(
Id int,
PersonId int,
ToyId int
);
It should make the complexity of the problem clearer. It will also save some space. A statement of the form,
select
p.Name PersonName,
t.Name ToyName
from
Person p
join
PersonToy pt
on pt.PersonId = p.Id
join
Toy t
on t.Id = pt.ToyId
where
p.Id in
(
select PersonId from PersonToy where ToyId = 1
intersect
select PersonId from PersonToy where ToyId = 4
);
will work efficiently.
Updated Fiddle
Here's one way to do it using a subquery and checking for the existence of Hat and Doll in the HAVING clause:
select p.id, p.name,
t.id as toyid, t.name as toyname
from person p
inner join toys t on p.id = t.person_id
inner join (
select person_id
from toys
group by person_id
having sum(name = 'hat') > 0 and
sum(name = 'doll') > 0
) t2 on p.id = t2.person_id
SQL Fiddle Demo