SQL Query Using Data from 2 tables - sql

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

Related

Select information from 3 tables in 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 = ''

Joins using Sub Queries

I have two tables named "Book" and "Author." The attributes for the "Book" table are: PK- Book_Num, Book_Title, Book_Year, Book_Cost, Book_Subject. The attributes for the "Author" table are PK- Au_ID, Au_Fname, Au_Lname. These two tables have a M:N relationship with each other and the bridge table between them is named "Writes" and it has a composite primary key from the two tables made up of Book_Num and Au_ID. Here's my question: I want to write a query to display the Au_ID, Au_Fname, Au_Lname for all authors that have never written a book with the subject "Programming" and order the results by Au_Lname. How would I go about doing this with a sub-query?
Give this a shot:
SELECT A.Au_ID, A.Au_Fname, A.Au_Lname FROM Author A
JOIN Writes W ON A.Au_ID = W.Au_ID
JOIN Book B ON B.Book_Num = W.Book_Num
WHERE A.Au_ID NOT IN (
SELECT A.Au_ID FROM Author A
JOIN Writes W ON A.Au_ID = W.Au_ID
JOIN Book B ON B.Book_Num = W.Book_Num
WHERE B.Book_Subject = 'Programming'
)
ORDER BY A.Au_Lname ASC;
If you want better performance,you can use "NOT EXISTS" to get the data you want.
SELECT Au_ID, Au_Fname, Au_Lname FROM Author
WHERE NOT EXISTS
(
SELECT A.Au_ID FROM Author A
JOIN Writes W ON A.Au_ID = W.Au_ID
JOIN Book B ON B.Book_Num = W.Book_Num
WHERE B.Book_Subject = 'Programming'
AND Author.Au_ID = A.Au_ID
)
ORDER BY Au_Lname ASC

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

Postgres: Select where all rows with the same foreign key are null

I have two tables posts and authors. An author has many posts, so there's a foreign key posts.author_id. Post also has a column approved_at which is a datetime, and is NULL until the post is approved
So how can I select all authors who have no approved posts?
I can select all authors who have at least one approved post with something like this:
SELECT * FROM authors
WHERE id IN
(
SELECT a.id FROM authors a
JOIN posts p ON a.id = p.author_id
AND p.approved_at IS NOT NULL
)
But I can't figure out how to do the opposite: I want to select all authors where all of their associated posts have approved_at = NULL. How can I select this?
If you want to select authors who have either no posts at all or all posts are not approved (or, as you said - authors who have no approved posts), use not exists, for me it's most readable way:
select a.*
from authors as a
where
not exists
(
select *
from posts as p
where p.author_id = a.id and p.approved_at is not null
)
If postgres supports this syntax, try this approach
SELECT * FROM authors
WHERE id IN
(
SELECT a.id FROM authors a
JOIN posts p ON a.id = p.author_id
AND p.approved_at is NULL
except
SELECT a.id FROM authors a
JOIN posts p ON a.id = p.author_id
AND p.approved_at IS NOT NULL
)

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;