I'm using sqlplus (oracle). I trying to write a statement to remove all authors that have not yet published a book based on the bookauthor table.
Since I have joined to tables , I don't know how to delete authors that have not yet published a book. Also I'm not sure If I got subquery correctly in order to get an output of authors who have not published a book.
DELETE
FROM bookauthor, books
WHERE authorid =
(SELECT authorid, count(*) pubdate
FROM bookauthor
JOIN books USING (isbn)
GROUP BY authorid
HAVING count(*) < 1);
This is what I have so far.
I can't get it run correctly.
For table books -> isbn, title, pubdate, pubid, cost, retail, discount, category
for table bookauthor -> isbn, authorid
There are several flaws in your delete statement:
You want to delete authors that haven't published a book. That means you should be looking for authors that have no entry in the bookauthor table. But you don't even mention any author table and DELETE FROM bookauthor, books instead, which makes no sense.
You compare WHERE authorid = (SELECT authorid, count(*) FROM .... How can one ID possibly equal a pair of ID and count? It would have to be WHERE authorid = (SELECT authorid FROM ... instead.
In your subquery you are asking for HAVING count(*) < 1. But every author that is in the table occurs at least once of course. So this condition is never met. You are kind of asking: "Which of the authors in the bookauthor table is not in the bookauthor table?".
As mentioned, all this only makes sense with an author table:
trying to write a statement to remove all authors that ...
You are showing two tables. The book table where each book is identified by its ISBN. And the bookauthor table that links books to authors. This is called a bridge table (or junction table or association table or ... ‐ well there are many names for this). It establishes an m:n relation between author and book, so one author can have many books and one book can be written by more than one author. (If you wanted an 1:n relation instead, so that a book can only be written by one author, then the author ID would be an attribute in the book table.) So there must be an author table you haven't shown that the bookauthor table is referring to.
It should be something like:
delete from author where authorid not in (select authorid from bookauthor);
DELETE
FROM bookauthor
WHERE authorid =
(SELECT authorid FROM bookauthor WHERE isbn NOT IN (SELECT isbn FROM books))
Try this.
DELETE
FROM bookauthor
WHERE authorid =
(SELECT authorid FROM bookauthor a LEFT OUTER JOIN books b ON a.isbn = b.isbn WHERE b.isbn IS null)
Or this.
Related
I am asking myself how to best define a new database given two databases.
I have the following two databases
Author where I save information about authors i.e. Name, Birthyear, Country, Genre etc.
Book where I save information about the book i.e. AuthorName, ReleaseYear, Pages etc
How do I create a new database with the full information about all books and the author? I.e. a Book_Complete Database which includes Author.Name, ReleaseYear,Pages, Genre,ReleaseYear and Author.Birthyear, Author.Country?
Better to go for a single database and having 2 tables in it like
Author Table
AuthorId (PK)
Name
Birthyear
Country
Genre
Book Table
BookId (PK)
AuthorId (FK)
ReleaseYear
Pages
If you have two tables in a database you can combine them using JOIN. Here is SQLite tutorial on how to use JOIN.
https://www.sqlitetutorial.net/sqlite-join/
On the information you provided I assume you can you columns Name in table Author, and AuthorName in table Book. You can try something like this
SELECT
A.Name,
B.ReleaseYear,
B.Pages,
B.Genre,
B.ReleaseYear,
A.Birthyear,
A.Country
FROM
Author A
LEFT JOIN Book B
ON A.Name = B.AuthorName
Basically, I have these create these two tables on my app and want to store the combined version on a server. Or would you suggest another approach?
Yes we would. You should have one table per entity, i.e. one for the authors and one for the books. Thus you don't store data redundantly (e.g. the author's name or the book's title), which could otherwise lead to inconsistencies later. You can read up on database normalization here: https://en.wikipedia.org/wiki/Database_normalization or google it.
Now you must decide how to link the tables. One author can write multiple books. Can one book be written by multiple authors? Give both tables IDs you can work with (or find some natural unique key, like the ISBN for the book and maybe name + birth year for the author - the name only will probably not suffice and maybe it won't even when combined with the year).
If one book can only be written by one author, you have a 1:n relation (one book written by one author, one author writing multiple books).
author (author_id, name, birth_year, country, ...)
book (book_id, title, author_id, release_year, pages, ...)
If one book can have several authors, you have an m:n relation (one book written by multiple authors, one author writing multiple books).
author (author_id, name, birth_year, country, ...)
book (book_id, title, release_year, pages, ...)
book_author (book_id, author_id)
You can always join the tables, so as to get a combined result.
TL;DR problem
Entity A's have a many to many relationship with Entity B's. Given some Entity B's, how can I find all Entity A's that are related to those given Entity B's?
Actual Problem
I'm currently a bit stuck on a problem of SELECTing rows that are in a many to many relationship. The problem can be phrased like this:
Entity A: Book
Each book is stored in a table called Books that looks something like this:
DESCRIBE Books;
book_id | book_name | ... other metadata on books
-- book_id is a PRIMARY KEY
Entity B: Genres
A genre of some type, like Adventure or Romance, held in a table like this:
DESCRIBE Genres;
genre_id | genre_name
-- genre_id is a PRIMARY KEY
Relationship Holder: BookGenres
Each Entity A, Book, can be related to multiple Entity B, Genre. For example, Harry Potter can be related to the genre_names: 'Adventure' and 'Fantasy'. The relationships are stored here via. a (book_id, genre_id) tuple per row
DESCRIBE BookGenres;
book_id | genre_id
-- book_id REFERENCES Books(book_id)
-- genre_id REFERENCES Genres(genre_id)
-- (book_id, genre_id) is UNIQUE pairing
I want to be able to SELECT for books that have some desired genres. Let's say, I want to return all book_id where the book has the genres 'Adventure' and 'Fantasy'. The best I've been able to do is a self INNER JOIN and checking if the pairing ('Adventure', 'Fantasy') exists and returning that book_id, but this is terribly slow and if I'm searching for n genres relationships, I need n INNER JOINS! (unacceptable). My query looks something like this:
SELECT t1.book_id
FROM BookGenres as t1
INNER JOIN Genres as t2
ON t2.genre_id = t1.genre_id
INNER JOIN BookGenres as t3
ON t3.book_id = t1.book_id
INNER JOIN Genres as t4
ON t4.genre_id = t3.genre_id
WHERE t2.genre_name = 'Adventure' AND t4.genre_name = 'Fantasy'
To search for Books that have n specified relationships to desired Genres, I do n self INNER JOINS and check if such a pairing exists. This seems forbiddingly inefficient and I would like a bit of help on this query as I'm sure it is a common problem.
For starters, your relationship between Books and Genres is a Many to Many relationship, not a One to Many relationship.
As I understand your question, you want to return a list of all books that match all selected genres. Assuming you want additional information about the book, I have included the Books table
SELECT
Books.book_id
FROM
Books
WHERE
book_id IN (SELECT book_id
FROM BookGenres INNER JOIN Genres ON BookGenres.genre_id = Genres.genre_id
WHERE Genre.genre_name = 'Adventure') AND
book_id IN (SELECT book_id
FROM BookGenres INNER JOIN Genres ON BookGenres.genre_id = Genres.genre_id
WHERE Genre.genre_name = 'Fantasy')
I have two tables, lets say table books and table authors.
Table books has 4 fields, BookId, Title, Author, Publisher
Table authors has 5 field AuthorID, Title, Author, Publisher, Price
I want to update book to have the price field from authors. There is no one unique key so the criteria is if Title or Author or Publisher match then add that price to books. In my case authors has many duplicate values in Title, Author or Publisher so I get update errors because of duplicates. So basically how in oracle can I update books with that criteria and in case of duplicates just choose any record, it doesn't matter which and put it in there? Other languages have the top command that you can use to do such a thing but it looks like Oracle lack that.
I have tried various merge and update statements on my own with no luck. Something like:
UPDATE books n
set n.price = (
select t.price from authors t where
n.title= t.title or
n.author = t.author or
n.publisher = t.publisher)
But that statement isn't checking for duplicates and stopping them thus failing so I am missing that key.
The simple way is:
UPDATE books n
set n.price = (
select t.price from authors t where
( n.title= t.title or
n.author = t.author or
n.publisher = t.publisher )
and rownum = 1)
hello all im developing new project for publisher ...this project for develop system saved all books for that publisher ...............
we have 3 table
books
author
coauthor
problem case:
ieach book have 1 main author thats author could replay in alot of books and ieach book in some cases could have co-author this co author could be 1 or 2 or 3 or 12 note: this co author is already saved in author table
realtionship:
one to many between authors and books
many to many between coauthor and books and authors
table #1 authors table => table hold all authors
id - author_name
table #2 books table => table hold all books
id- title - author_id - publishing_year
table #3 co_authors table => hold all item which have alot of co author
item_id and authors_id
now how i can retrive all books for specific author if he is main author or co author
There're two ways you can go about this... One is to use a UNION, so something like:
SELECT id FROM books WHERE author_id = ?
UNION ALL
SELECT item_id FROM co_authors WHERE authors_id = ?
Another way you could solve this is to rework your database structure such that there is no author_id in the books table and instead you have a flag in co_authors called main_author or some such. Considering you may have books where it's unclear who the main author is, this may make more sense...
You can do something like this :
SELECT DISTINCT books.*, authors.*
FROM books
LEFT JOIN co_authors ON co_authors.item_id = books.id
INNER JOIN authors ON
authors.id = books.author_id OR
authors.id = co_authors.author_id
WHERE authors.id = ID
The where clause can also be written where authors.name = 'NAME' if you need to search by name and not id.
EDIT: added distinct to avoid multiple rows for the same book.
Ok guys, im having a real issue trying to understand the logic behind the aliasing in oracle. Here is the query:
select isbn,
b.fname,
b.lname
from bookauthor a,
author b,
(select authorid auth
from bookauthor
where isbn = (select max(isbn) maxisbn
from orderitems))
where b.authorid = auth
and isbn = maxisbn;
for some reason, the dbms isn't recognizing maxisbn as an alias, but if i get rid of everything regarding maxisbn, the query runs and recognizes the alias "auth" just fine. Why is it seeing one but not the other?
maxisbn isn't the name of any column exposed by your derived table's SELECT list.
In order for this syntax to work you would need to add it as a column as below.
select isbn,
b.fname,
b.lname
from bookauthor a,
author b,
(select authorid auth, isbn maxisbn
from bookauthor
where isbn = (select max(isbn) maxisbn
from orderitems))
where b.authorid = auth
and isbn = maxisbn;
NB: There is probably definitely a more efficient way of writing this query (you shouldn't need to access bookauthor twice) and I would always use explicit JOIN syntax. This is just to answer your specific question about why it doesn't work.
To take up Martin's question if this can be written more efficiently.
I think that the following will perform better and still return the same thing:
SELECT a.max_isbn,
b.fname,
b.lname
FROM (SELECT authorid as max_authorid,
isbn as max_isbn
FROM bookauthor
WHERE isbn = (SELECT max(isbn) FROM orderitems)) a
JOIN author b ON a.max_authorid = b.authorid AND a.max_isbn = b.isbn