I have 3 table obl_books, obl_authors and the link table books_authors.
The question is:
Write a query to select only those books whose all authors belong to Indian Nationality.
And the query I wrote for this is
SELECT obl_books.*, books_authors.author_id
FROM books_authors,obl_authors,obl_books
WHERE books_authors.author_id = obl_authors.author_id
AND books_authors.book_id=obl_books.book_id
GROUP BY books_authors.book_id
HAVING books_authors.author_id IN (SELECT obl_authors.author_id FROM obl_authors WHERE nationality='Indian')
Nationality is the column of obl_authors table and a book can have many authors.
So if book_id (2) has author_id (1), author_id (2) where author_id (1) and (2) are Indians then it should return that and if even one of the author is not Indian it should not.
But my query is returning even that book_id.
I even changed my having clause using ALL keyword in place of IN but it does not return any row.
Try:
SELECT obl_books.*, GROUP_CONCAT(books_authors.author_id)
FROM books_authors
JOIN obl_authors ON books_authors.author_id = obl_authors.author_id
JOIN obl_books ON books_authors.book_id=obl_books.book_id
GROUP BY books_authors.book_id
HAVING MIN(obl_authors.nationality)='Indian' AND
MAX(obl_authors.nationality)='Indian'
As I understand your problem, this is what you want; it just counts whether the number of indian authors is the same as the number of total authors per book, and show the ones where they're equal.
SELECT b.*, GROUP_CONCAT(a.author_id) authors
FROM obl_books b
JOIN books_authors ba ON b.book_id=ba.book_id
LEFT JOIN obl_authors a ON ba.author_id=a.author_id AND a.nationality = 'Indian'
GROUP BY b.book_id
HAVING COUNT(a.author_id)=COUNT(ba.author_id)
An SQLfiddle to test with.
Note that the GROUP BY on book_id only is a MySQL'ism, you'd normally need to group by all selected fields in obl_books.
Try this one query:
SELECT obl_books.*, books_authors.author_id
FROM books_authors,obl_authors,obl_books
WHERE books_authors.author_id = obl_authors.author_id
AND books_authors.book_id=obl_books.book_id and obl_authors.nationality='Indian'
GROUP BY books_authors.book_id
HAVING count(books_authors.book_id) = (SELECT count(*) FROM books_authors group by books_authors.author_id)
Try this
select * from obl_books where id in (select book_id from books_authors where author_id in (select id from obl_authors where nationality='Indian'))
I think, we can do this.. in reverse way also.. First get all the author id,who is not Indian and then except those author select all the remaining author's book (Indian Author's book).
SELECT obl_books.*, books_authors.author_id
FROM books_authors,obl_authors,obl_books
WHERE books_authors.author_id = obl_authors.author_id
AND books_authors.book_id=obl_books.book_id AND books_authors.author_id NOT IN (SELECT obl_authors.author_id FROM obl_authors WHERE nationality<>'Indian')
Related
I have Books table
BookID BookName
1 BookA
2 BookB
3 BookC
Member table
MemberID MemberName
1 MemberA
2 MemberB
Borrow Table
MemberID BookID
1 1
1 2
2 1
2 2
I want to find out five popular book by Memeber A
I tried the following query
SELECT TOP (5) Book.BookTitle, COUNT(*) AS Count, Member_1.MemberName
FROM Book INNER JOIN
Borrow ON Book.BookID = Borrow.BookID INNER JOIN
Member ON Borrow.MemberID = Member.MemberID INNER JOIN
Member AS Member_1 ON Borrow.MemberID = Member_1.MemberID
where Member.MemberName='A'
GROUP BY Book.BookTitle, Member_1.MemberName
ORDER BY Count DESC
But this is not giving me the actual result.
Any suggestion would be appreciated.
I think you have too many joins:
SELECT TOP (5) b.BookTitle, COUNT(*) AS Count, m.MemberName
FROM Book b INNER JOIN
Borrow bo
ON bo.BookID = b.BookID INNER JOIN
Member m
ON bo.MemberID = m.MemberID
WHERE m.MemberName = 'A'
GROUP BY b.BookTitle, m.MemberName
ORDER BY Count DESC;
Note: This syntax is usually associated with SQL Server and does not work in MySQL. In MySQL, you would use LIMIT 5 rather then SELECT TOP (5).
I'm trying to find the output of all books that have more than one genre using a group by statement and subquery. However, it keeps returning Subquery returns more than 1 row. This is what I have so far:
SELECT title
FROM book
WHERE 1 < (SELECT COUNT(genre) FROM genres GROUP BY book_id);
Here's an example:
SELECT b.title
FROM ( SELECT g.book_id
FROM genres g
GROUP
BY g.book_id
HAVING COUNT(1) > 1
) m
JOIN book b
ON b.id = m.book_id
The inline view m is meant to return us values of book_id that appear more than one time in the genres table. Depending on uniqueness constraints, we might want to count distinct values of genre
HAVING COUNT(DISTINCT g.genre) > 1
if we want to find books with exactly three related genre:
HAVING COUNT(DISTINCT g.genre) = 3
Once we have a list of book_id values, we can join to the book table. (The query assumes that book_id in genres is a foreign key reference to the id column in book table.)
You seem to what a correlated subquery:
SELECT b.title
FROM book b
WHERE 1 < (SELECT COUNT(*) FROM genres g WHERE g.book_id = b.book_id);
SELECT distinct a.title
FROM book a, (select bookid,count(distinct genre)genres from genres group by bookid)b
WHERE a.book_id=b.bookid and b.genres>1
hope it helps!
I'm not sure how to do the following query. I have 3 tables:
song (song_id, title, is_draft)
author (author_id, name)
song_author (song_id, author_id, display_order)
There are songs, and a song can have multiple authors and an author can write multiple songs
I want to output the authors of a specific song with the total numbers of songs that each author wrote.
So, if i pick song_id: 598, i want to have a result set like this
author_id name total songs he wrote
------------------------------------------------
234 Michael Lord 58
589 Lama Turc 12
NOTE: The total number of songs each author wrote must exclude songs were song.is_draft equals 1 and order the result set by song_author.displayorder
From my research, i think i have to do 2 queries (sub queries) but that's as far as i got...
Thanks
SELECT author.author_id, author.name, count(song.song_id)
FROM song, author, song_author,
WHERE song.song_id = $id
AND song.song_id = song_author.song_id
AND song_author.author_id = author.author_id
AND song_author.display_order != 1
GROUP BY song_author.author_id, author.name
ORDER BY author.author_id asc;
try this..
select b.author_Id, b.name, COUNT(a.Song_Id) as 'total'
FROm song_author as a
INNER JOIN author as b
ON a.author_id = b.author_id
where a.song_id IN (select s.song_id
From songs as s
Where s.Song_Id = 598
AnD s.is_draft = 1)
GROUP bY b.author_Id, b.name
New to SQL too, but off the top of my head maybe this? This doesn't explicitly spell out joins, but I've found it works for my purposes. Maybe someone can let me know if this is bad practice?
Select author.author_id
, author.name
, count(author.author_id)
from song, author, song_author
where song.song_id = song_author.song_id
and author.author_id = song_author.author_id
group by author.authorid, author.name
order by author.author_id asc;
I am having the following two table.
1.Movie Detail (Movie-ID,Movie_Name,Rating,Votes,Year)
2.Movie Genre (Movie-ID,Genre)
I am using the following query to perform join and get the movie with highest rating in each
genre.
select Movie_Name,
max(Rating) as Rating,
Genre from movie_test
inner join movie_genre
where movie_test.Movie_ID = movie_genre.Movie_ID
group by Genre
In the output Rating and Genre are correct but the Movie_Name is incorrect.
can anyone suggest what changes I should make to get the correct movie name along with rating and genre.
SELECT g.*, d.*
FROM MovieGenre g
INNER JOIN MovieDetail d
ON g.MovieID = d.MovieID
INNER JOIN
(
SELECT a.Genre, MAX(b.Rating) maxRating
FROM MovieGenre a
INNER JOIN MovieDetail b
ON a.MovieID = b.MovieID
GROUP BY a.Genre
) sub ON g.Genre = sub.Genre AND
d.rating = sub.maxRating
There is something wrong with your schema design. If a Movie can have many Genre as well as Genre can be contain on many Movie, it should be a three table design.
MovieDetails Table
MovieID (PK)
MovieName
MovieRating
Genre Table
GenreID (PK)
GenreName
Movie_Genre Table
MovieID (FK) -- compound primary key with GenreID
GenreID (FK)
This is a common MySQL problem - specifying non-aggregate/non-aggregated-by columns in an aggregate query. Other flavours of SQL do not let you do this and will warn you.
When you do a query like yours, you are selecting non-aggregate columns in an aggregated group. Since many rows share the same genre, when you select Movie_Name it picks one row at random from each group and displays that one, because there is no general algorithm to guess the row you want and return the values of that.
You might ask 'why does it pick randomly? It could pick the one that max(Rating) belongs to?' but what about other aggregate columns, like avg(Rating)? What row does it pick there? What if two rows have the same max, anyway? Therefore it cannot have an algorithm to pick a row.
To solve a problem like this, you have to restructure your query, something like:
select Movie_Name,
Rating,
Genre from movie_test mt
inner join movie_genre
where movie_test.Movie_ID = movie_genre.Movie_ID
and Rating = (select max(Rating) from movie_test mt2 where mt.Genre = mt2.Genre
group by Genre
limit 1
This will select the row with the rating being the same as the maximum rating for that genre, using a subquery.
Query:
SELECT t.Movie_Name,
t.Rating,
g.Genre
FROM movie_test t
INNER JOIN movie_genre g ON t.Movie_ID = g.Movie_ID
WHERE t.Movie_ID = (SELECT t1.Movie_ID
FROM movie_test t1
INNER JOIN movie_genre g1 ON t1.Movie_ID = g1.Movie_ID
WHERE g1.Genre = g.Genre
ORDER BY t1.Rating DESC
LIMIT 1)
I have 3 tables for storing information about books:
books
-----
id
title
authors
-------
id
name
books_to_authors
----------------
book_id
author_id
When a book's information is displayed, I then want to be able to select any other books by the same authors.
I have the current book id available from the first query, but I can't figure out where to start to achieve what I need as there can be multiple authors. Obviously with just one of them it would be simple, so I'm really struggling with this. Any help would be much appreciated!
I think this aught to do it. Just replace the ? with the book ID they are currently viewing and this will give you all the books by the same author.
SELECT b.*
FROM books b
INNER JOIN books_to_authors b2a ON b2a.book_id = b.id
WHERE b2a.author_id IN (
SELECT author_id FROM books_to_authors WHERE book_id = ?
)
If you want to exclude the book they are currently viewing, you can change the query like this:
SELECT b.*
FROM books b
INNER JOIN books_to_authors b2a ON b2a.book_id = b.id
WHERE b2a.author_id IN (
SELECT author_id FROM books_to_authors WHERE book_id = ?
)
AND b.id <> ?
$book_id = (your code for retrieving book_id);
$db_query = "SELECT b.*
FROM books b
INNER JOIN books_to_authors bta ON bta.book_id = b.id
WHERE bta.author_id IN (
SELECT author_id FROM books_to_authors WHERE book_id = ".$book_id."
)";
I presumed that you are using php. If I'm wrong, just use SQL query string, and ignore the rest...
You're looking for the query below. I see some solutions with subqueries and I'd highly recommend not using subqueries. They are slower than running 2 queries:
Having the book id you do SELECT author_id FROM books_to_authors WHERE book_id = '{$book_id}'
Get the author id and then run this:
SELECT books.id, books.title, authors.name FROM books RIGHT JOIN books_to_authors ON books_to_authors.book_id = books.id) RIGHT JOIN authors ON (authors.id = books_to_authors.author_id) WHERE authors.id = '{$author_id}'