MySQL showing duplicates in a column - mysql

Hi I'm trying to write a query to get information about the author, title, category and medium.
However as the items can be in many mediums and categories, I'm getting the results appearing duplicated in the columns. How can I get the results so I don't see medium as book,book,book and category as Horror,Fantasy,Fiction. I'm assuming I will need some sort of subquery - if so how would I do it?
SELECT book.bookid, book.author, book.title, group_concat(category.categorydesc), group_concat(medium.mediumdesc)
FROM book
Inner JOIN bookscategories ON book.bookid = bookscategories.bookid
Inner JOIN category ON bookscategories.categoryid = category.categoryid
Inner JOIN booksmediums ON book.bookid = booksmediums.bookid
Inner JOIN medium ON booksmediums.mediumid = medium.mediumid
GROUP BY book.bookid
Thanks
Tom

So as stated in comments, solution is to add the DISTINCT keyword in the GROUP_CONCAT() instructions like that:
... book.title, group_concat(DISTINCT category.categorydesc), group_concat(DISTINCT medium.mediumdesc) ...

Related

MYSQL: Select Query with multiple values from one column

i am currently working with a MYSQL-Database whichhas three tables:
Books, Keywords and KeywordAssignment.
The tables Books and Keywords are in a many to many relationship therefore the table KeywordAssignment.
Now to my question: I want to search for a book with multiple (max: up to ten) keywords.
I've already tried a self join:
SELECT BookID
FROM Keywords K1 INNER JOIN
Keywords K2
ON K1.KeywordAssignmentID=K2.KeywordAssignmentID INNER JOIN
KeywordAssignment
ON KeywordAssignment.KeywordAssignmentID=K1.KeywordAssignmentID INNER JOIN
Books
ON KeywordAssignment.BookID=Books.BookID
WHERE K1.Keyword='Magic' AND K2.Keyword='Fantasy'
The problem is it only works if the given Keyword are in the right order. If they aren't there are more than one.
I appreciate your help thank you very much!
You need to GROUP BY BookID and a HAVING clause with the condition that both keywords are linked to that BookID:
SELECT b.BookID, b.Title
FROM Books b
INNER JOIN KeywordAssignment ka ON ka.BookID = b.BookID
INNER JOIN Keyword k ON k.KeywordID = ka.KeywordID
WHERE k.Keyword IN ('Magic', 'Fantasy')
GROUP BY b.BookID, b.Title
HAVING COUNT(DISTINCT k.Keyword) = 2
This code will return books that are linked to both 'Magic' and 'Fantasy'.
If you want either of the 2 keywords then remove the HAVING clause.
If I understand your question correctly, you want to query for books that have multiple key words. The key word there is have. I don't have MYSQL but the query should look something like this:
SELECT B.BookID, COUNT(*) as NumberOfKeywords FROM Books B
INNER JOIN KeywordAssignment KA
ON B.BookID = KA.BookID
INNER JOIN Keywords K
ON KA.KeywordID = K.KeywordID
GROUP BY B.BookID
HAVING NumberOfKeywords > 0 AND NumberOfKeywords <= 10
What we are doing is grouping by each book and then selecting the ones that have more than 0 keywords and less than 10.

How to limit values when using distinct

PHP
SELECT DISTINCT bk.title AS Title, bk.year AS Year, aut.authorname AS Author, cat.category AS Category
FROM book bk
JOIN book_category bk_cat
ON bk_cat.book_id = bk.bookid
JOIN categories cat
ON cat.id = bk_cat.category_id
JOIN books_authors bk_aut
ON bk_aut.book_id = bk.bookid
JOIN authors aut
ON aut.id = bk_aut.author_id
ORDER BY bk.title ASC
My data base is echoing out the following data you can see that it prints the book out more than once if it has more than one category. from my php code can anyone tell me how i can make it distinct from the category column. Thanks.
The easiest way to achieve different data only in the columns you want is using GROUP BY clause. By default, it'll group the rows, depending on the value of the column, showing only distinct values so, if you want to group and show only different titles and categories, you should write your query as:
SELECT bk.title AS Title, bk.year AS Year, aut.authorname AS Author, cat.category AS Category
FROM book bk
JOIN book_category bk_cat
ON bk_cat.book_id = bk.bookid
JOIN categories cat
ON cat.id = bk_cat.category_id
JOIN books_authors bk_aut
ON bk_aut.book_id = bk.bookid
JOIN authors aut
ON aut.id = bk_aut.author_id
GROUP BY bk.title, cat.category
ORDER BY bk.title ASC
As you may see, no DISTINCT is used, but you'll get all books with distincts title and categories. The more fields you added into the GROUP BY clause, the more distinct data you'd get.
Same way, if you only wanted list books by title, you should only leave bk.title in the GROUP BY clause
DISTINCT works on the entire row, not a single column. The only way to ensure not repeating rows is to exclude category column from the select.
If your objective is to list all categories, you will have to either look up categories as you're looping over the query result set during output (not very efficient though) OR process your result set in the code before you output it by collapsing repeating rows and merging/concatenating category values into a string.
You could try some fancy SQL with subqueries to convert categories into a single delimited string but that will sure make your code hard to read and query hard to debug.
SELECT DISTINCT bk.title AS Title, bk.year AS Year, aut.autName AS Author, cat.category AS Category
FROM book bk
JOIN book_category bk_cat
ON bk_cat.book_id = bk.bookid
JOIN categories cat
ON cat.id = bk_cat.category_id
JOIN (SELECT GROUP_CONCAT(aut.authorname) as autName FROM authors JOIN books_authors ON books_authors.author_id=authors.author_id WHERE books_authors.book_id=bk.bookid) as aut
ORDER BY bk.title ASC
I think you might want to look into subquery-ing with the group_concat() so please give this a try:
group_concat() will merge the results of the sub-query and provide you with one string of authors separated by a comma-space like this author1, author2, author3
SELECT
DISTINCT bk.title AS Title,
bk.year AS 'Year',
(
SELECT
group_concat(aut.authorname, ', ')
FROM
authors aut
LEFT OUTER JOIN
books_authors bk_aut
ON
aut.id=bk_aut.author_id
WHERE
bk_aut.book_id = bk.book_id
) AS Author
FROM
book bk
ORDER BY
bk.title ASC

MySQL: how to get result from 2 tables without repeating results?

I've got 3 tables: book, publisher, book_category
For a particular book category (fantasy) I have to display list of publisher names supplying that genre.
publisher_name and category_name are linked through book table, so my query is:
SELECT publisher.publisher_name
FROM publisher, book, book_category
WHERE publisher.publisher_id = book.publisher_id
AND book.category_id = book_category.category_id
AND category_name = 'fantasy';
But the result I'm getting is repeating the name of publisher if there's more than one fantasy book supplied by that publisher.
Let's say I've got The Hobbit and The Lord of the Rings,both are fantasy and are supplied by the same PublisherA.
In that case the result of my query is:
PublisherA
PublisherA
Is it possible to get that result just once? Even if there's much more than 2 fantasy books
published by the same publisher?
Just use distinct if you only need publisher_name
SELECT distinct publisher.publisher_name
by the way, try to use JOIN syntax... to join tables
SELECT distinct p.publisher_name
FROM publisher p
join book b on b.publisher_id = p.publisher_id
join book_Category bc on bc.category_id = b.category_id
where bc.category_name = 'fantasy'
Use DISTINCT
SELECT DISTINCT publisher.publisher_name
FROM publisher, book, book_category
WHERE publisher.publisher_id = book.publisher_id
AND book.category_id = book_category.category_id
AND category_name = 'fantasy';
Try adding this to the end of the query: GROUP BY publisher.publisher_name
Everyone is mentioning DISTINCT, which is correct (better than GROUP BY in MySQL, because of the way the optimizer is set up), but I figured I would also add a modification for performance enhancements.
Currently you have implicit cross joins to get to the other tables, and making these explicit INNER JOINs will increase efficiency because of the order of filtering. Example:
SELECT DISTINCT Publisher.publisher_name
FROM publisher Publisher
INNER JOIN book Book ON Publisher.publisher_id = Book.publisher_id
INNER JOIN book_category Book_Category ON Book.category_id = Book_Category.category_id
WHERE Book_Category.category_name = 'fantasy';
In the original query, you bring in the complete record set of all three tables (publisher, book, book_category), and then from that set you join on the respective keys, and then return the result set. In this new query, your join to Book_Category happens based only upon the record set returned from the join between Publisher and Book. If there is filtering that happens based on this join, you will see a performance increase.
You also have the added benefit of being ANSI-compliant, as well as explicit coding to improve ease of maintenance.

SQL Multiple Joins multiple where

I have three tables is question. categories, vocabulary & tex. I am trying to figure out how to have multiple joins in my query, i thought you can just add as many joins as you wanted, as long as you reference them properly.
So, the following two work perfectly on there own:
1.
SELECT
categories.ID AS ID,
categories.ParentID AS ID,
vocabulary.value AS Name
FROM categories
INNER JOIN vocabulary
ON categories.sid=vocabulary.sid
WHERE vocabulary.langid=1
2.
SELECT
categories.ID AS ID,
categories.ParentID AS ID,
tex.value AS Description
FROM categories
INNER JOIN tex
ON categories.tid=tex.tid
WHERE tex.langid=1
However, if i try to combine them as follows, it does not work.
categories.ID AS ID,
categories.ParentID AS ID,
vocabulary.value AS Name
tex.value AS Description
FROM categories
INNER JOIN tex
ON categories.tid=tex.tid
WHERE tex.langid=1
INNER JOIN vocabulary
ON categories.sid=vocabulary.sid
WHERE vocabulary.langid=1
Any ideas?
Thanks in advance
John
In MySQL, when you have columns with the same name, one of them will only be shown. You need to identify them uniquely by supplying ALIAS. And you can either put the condition on the ON clause or WHERE clause which could yield the same result since it uses INNER JOIN.
SELECT categories.ID AS CategoryID,
categories.ParentID AS CategoryParentID,
vocabulary.value AS Name
tex.value AS Description
FROM categories
INNER JOIN tex
ON categories.tid = tex.tid
INNER JOIN vocabulary
ON categories.sid = vocabulary.sid
WHERE vocabulary.langid = 1 AND
tex.langid = 1

Subquery to show all other categories one to many relationships

I am trying to create a query where I can view all the books that are in both category 1 and 2 (e.g. horror and fiction) but also show the categories that the book also belongs to. How do I go about this? I can only assume that I'm going to need a recursive subquery, however this could be inefficient.
SELECT book.bookid,
book.author,
book.title,
Group_concat(DISTINCT category.categorydesc)
FROM book,
bookscategories,
category
WHERE book.bookid = bookscategories.bookid
AND bookscategories.categoryid = category.categoryid
AND category.categoryid = 1
AND category.categoryid = 2
GROUP BY book.bookid;
select b.bookid, b.author, b.title, group_concat(distinct c.categorydesc)
from book as b
inner join bookcategories as bc on b.bookid = bc.bookid
inner join categories as c on bc.categoryid = c.categoryid
where b.bookid in (select bc1.bookid
from bookcategories as bc1
inner join bookcategories as bc2 on bc1.bookid = bc2.bookid
where bc1.categoryid = 1 and bc2.categoryid = 2)
group by b.bookid;
I am not sure about the performance of this query because it uses the bookcategories table 3 times.
Selecting b.author and b.title is not technically correct, but should work in this case because b.bookid is probably unique. Otherwise it is not possible to select something that is neither part of the group by clause nor used in an aggregate function.
I believe that the code that you posted will always return an empty result set because you are restricting category.categoryid to be both 1 and 2 at the same time.