What is the wrong with this query? - mysql

I have 3 sql tables calls category, movies, category_movies. category and movies tables have many to many relationship. Thats why I use category_movies table. This is tables' structure...
Category : cat_id, cat_name,
movies : mov_id, mov_name,
category_movies : cat_id, mov_id
Now I have got 3 category IDs dynamically and now I want to select movies' names alone with category names which belongs to 3 category_id have already got.
This is the query that I tried so far..
SELECT c.cat_name AS cn, m.mov_name AS mn, m.mov_id
FROM category AS c
INNER JOIN category_movies AS cm ON cm.cat_id = c.cat_id
INNER JOIN movies AS m ON m.mov_id = cs.mov_id
WHERE c.cat_id IN (2, 5, 7)
GROUP BY c.cat_name, m.mov_name, m.mov_id
HAVING COUNT(*) >= 3
but this is now working.. can anybody tell me what is wrong with this query?

use IN clause on this
SELECT..
FROM..
WHERE cat_id IN (2, 5, 7)
and is the same with
SELECT..
FROM..
WHERE cat_id = 2 OR
cat_id = 5 OR
cat_id = 7
Please also take note that it is INNER JOIN not INNOR JOIN
but I guess, you want to perform RELATIONAL Division (you want to search for a movie that has all the category you want to find)
SELECT c.cat_name, m.mov_name, m.mov_id
FROM category AS c
INNER JOIN movies AS m ON m.cat_id = c.cat_id
INNER JOIN category_movies AS cm ON cm.mov_id = m.mov_id
WHERE cat_id IN (2, 5, 7)
GROUP BY c.cat_name, m.mov_name, m.mov_id
HAVING COUNT(*) >= 3
Relational Division

INNOR -> INNER
WHERE cat_id = 2 AND 5 AND 7
that hardly can be right it probably should be OR

1 code
SELECT Id, name, YEAR(BillingYar) AS Year
FROM Records
WHERE Year ≥ 2010
2 code
SELECT id, name
FROM students
WHERE grades = (SELECT MAX(grades)
FROM students
GROUP BY subject_id);
I can see only in first code wrong this symbol ( ≥ ), need to be >= . Something else?

Related

How to do multiple tasks in a single SQL query

I was given the database below:
movie(movie_id, movie_name, production_year, votes, ranking, rating)
movie_info(movie_id, movie_genre_id, note)
movie_genre(movie_genre_id, genre_name)
person(person_id, person_name, gender)
role(person_id, movie_id, role_name, role_type_id)
role_type(role_type_id, type_name)
I was asked to display the name of the top 7 directors with at least 3 movies in the list, the number of movies they are in and the average rating of their movies, sorted by the average rating. With the query below I managed to get the name of the directors, the number of movies they are in and the average rating, but I'm having issues limiting it to the top 7 and sorting them by the average rating. I tried using LIMIT and ORDER BY, but I'm getting syntax errors.
SELECT
person_name, COUNT(role.movie_id), AVG(rating)
FROM
movie
INNER JOIN
role
ON role.movie_id = movie.movie_id
INNER JOIN
person
ON role.person_id = person.person_id
INNER JOIN
role_type
ON role.role_type_id = role_type.role_type_id
WHERE
type_name = 'director'
GROUP BY
person_name
HAVING
COUNT(role.movie_id) > 2;
I can even order by the number of movies they did and limit it to the top 7, but for God I cannot order it by the AVG(rating)
person_name COUNT(role.movie_id) AVG(rating)
Hitchcock, Alfred 9 8.2888890372382
Kubrick, Stanley 8 8.2999999523163
Wilder, Billy 6 8.3000000317891
Spielberg, Steven 6 8.4000000953674
Scorsese, Martin 6 8.3166666030884
Nolan, Christopher 6 8.5333331425985
Tarantino, Quentin 6 8.3666666348775
In MySQL, Aliases defined in the Select clauses can be used in the Group By, Order By and Having clauses.
Use Order by .. DESC to sort the result-set in descending order and Limit 7 to get only 7 rows.
You should use proper Aliasing in multi table queries, to avoid ambiguous and unintended behavior.
You need to use Group By on person_id also, as there may be cases where director(s) have same name.
If you have duplicate entries in role table, you will have to use Count(Distinct ...) to avoid counting duplicate rows.
Try the following query:
SELECT
p.person_id,
p.person_name,
COUNT(r.movie_id) AS movies_count,
AVG(m.rating) AS average_rating
FROM
movie AS m
INNER JOIN
role AS r
ON r.movie_id = m.movie_id
INNER JOIN
person AS p
ON r.person_id = p.person_id
INNER JOIN
role_type AS rt
ON r.role_type_id = rt.role_type_id
WHERE
rt.type_name = 'director'
GROUP BY
p.person_id,
p.person_name
HAVING
movies_count > 2
ORDER BY
movies_count DESC,
average_rating DESC
LIMIT 7

MYSQL Order by sum of different table

I have two tables:
cat_seriale - which represents the serial categories and provides ID's for each category like: 1, 2, 3, 4, 5.
seriale - which is actual tv serials, and each tv serial falls in one category.
I am trying to
SELECT * FROM cat_seriale WHERE `id`='1'
and additionally to all columns, display the sum of views column from all rows in seriale table.
If some one can help me out, that would be great.
Thanks in advance.
SCHEMA:
cat_seriale columns:
Primary Key - catid(int)
catname (varchar)
...
seriale columns:
Primary Key - id(int)
cat (int)
views(int)
I need to select cat_seriale where ID = 1, and select sum of views in seriale columns where cat is same with id from cat_seriale.
Like this:
select *, (select sum(views) from seriale S where S.cat=C.catid) as sum_views
from cat_seriale C
where id='1'
order by sum_views
Join the two tables.
SELECT c.*, SUM(s.views) AS views
FROM cat_seriale AS c
LEFT JOIN seriale AS s ON c.catid = s.cat
WHERE c.id = `1`
GROUP BY c.catid
+1 for #Mike answer, but this version has more performance:
SELECT c.*, SUM(s.views) as summary
FROM cat_seriale c
LEFT JOIN seriale s ON s.cat = c.catid
WHERE c.id = '1'
GROUP BY c.catid
ORDER BY summary

MYSQL Query search in relationship

For the sake of clarity and this question i will rename the tables so it is a bit clearer for everybody and explain what i want to achieve:
There is an input form with options that return categories ID's. If a 'Product' has 'Category', i want to return/find the 'Product' which lets say has multiple categories(or just 1) and all of its categories are inside the array that is passed from the form.
Products table
ID Title
1 Pizza
2 Ice Cream
Categories table
ID Title
1 Baked food
2 Hot food
ProductsCategories table
ID ProductId CategoryId
1 1 1
2 1 2
So if i pass [1,2] the query should return Product with id 1 since all ProductsCategories are inside the requested array, but if i pass only 1 or 2, the query should return no results.
Currently i have the following query which works, but for some reason if i create a second Product and create a ProductCategory that has a CategoryId same as the first product, the query returns nulll...
SELECT products.*
FROM products
JOIN products_categories
ON products_categories.product_id= products.id
WHERE products_categories.category_id IN (1, 2)
HAVING COUNT(*) = (select count(*) from products_categories pc
WHERE pc .product_id = products.id)
All help is deeply appretiated! Cheers!
In order to match all values in IN clause, you just need to know in addition the number of passed categories which you must use it in HAVING clause:
SELECT
p.*,
GROUP_CONCAT(c.title) AS categories
FROM
Products p
INNER JOIN ProductsCategories pc ON pc.productId = p.ID
INNER JOIN Categories c ON c.ID = pc.categoryId
WHERE
pc.categoryId IN (1,2)
GROUP BY
p.id
HAVING
COUNT(DISTINCT pc.categoryId) = 2 -- this is # of unique categories in IN clause
So in case IN (1,2) result is:
+----+-------+---------------------+
| id | title | categories |
+----+-------+---------------------+
| 1 | Pizza | Baked Food,Hot Food |
+----+-------+---------------------+
1 row in set
In case IN (1,3) result is Empty set (no results).
#mitkosoft, thanks for your answer, but sadly the query is not producing the needed results. If the product's categories are partially in the passed categories the product is still returned. Additionally i might not know how many parameters are sent by the form.
Luckily I managed to create the query that does the trick and works perfectly fine (at least so far)
SELECT products.*,
COUNT(*) as resultsCount,
(SELECT COUNT(*) FROM products_categories pc WHERE pc.product_id = products.id) as categoriesCount
FROM products
JOIN products_categories AS productsCategories
ON productsCategories.product_id= products.id
WHERE productsCategories.category_id IN (7, 15, 8, 1, 50)
GROUP BY products.id
HAVING resultsCount = categoriesCount
ORDER BY amount DESC #optional
That way the query is flexible and gives me exactly what I needed! - Only those products that have all their categories inside the search parameters(not partially).
Cheers! :)

select all books from one category except books which belong to other category

I have 3 tables: books, book_categories, categories.
book_categories table "joins" books and categories. It contains columns: id,book_id,category_id.
So one Book may belong to many categories and one Categorie may have many books.
I need query which retrieves all books from given_category except books which belongs to given_set_of_categories. So for example I want all books from category A but only if they don't belong also to category B or C. I need also sort (order) the result by Book.inserted column.
I know how to get all books from given_category with 2 joins but can't figure out how to exclude some books from other categories in result. I cant filter books in PHP because I am paginating the search result.
where
category_id = <given category>
and books.book_id not in
(
select book_id from book_categories
where category_id in (<given set of cat>)
)
order by books.inserted
So, if you mean it is in one category but not in any other:
AND EXISTS(SELECT * FROM books b JOIN book_categories bc ON b.id = bc.book_id JOIN categories c ON bc.category_id = c.id AND c.id = 'A')
AND NOT EXISTS(SELECT * FROM books b JOIN book_categories bc ON b.id = bc.book_id JOIN categories c ON bc.category_id = c.id AND c.id != 'A')
I think that this can be achieved through counting provided that book_categories entries are unique, thus the combination book_id & category_id are not repeating. Instead of trying directly to exclude records, we select from the combined set of categories [,] and then we'll count book_id entries that belong to the :
COUNT(IF(category_id = <given_category>, 1, NULL)) as cnt_exists
and after ensuring that it contains the required category, we count the total to see if it belongs to any other category as well:
COUNT(*) AS cnt_total
SELECT * FROM books b JOIN (
SELECT book_id,
COUNT(IF(category_id = <given_category>, 1, NULL)) as cnt_exists,
COUNT(*) AS cnt_total FROM book_categories WHERE
category_id IN(<given_category>, <given_set_of_categories>)
) bc ON b.id = bc.book_id AND
cnt_exists = 1 AND cnt_total = 1 ORDER BY b.inserted

mySQL SELECT FROM table WHERE ... AND ... AND ... AND

I have a table "articles" with columns and data:
article_id title body
1 This is the title This is the body text
2 Another title Another body text
Another table "category" with columns and data:
category_id category
1 localnews
2 visible
3 first10
And a table "categories" with columns and data:
categories_id article_id category_id
1 1 1
2 1 2
3 1 3
4 2 1
5 2 3
I want to SELECT the row(s) WHERE categories.category_id = 1 AND =2 AND =3
I'm using:
SELECT articles.article_id, articles.title, articles.body,
categories.article_id, categories.category_id
FROM articles, categories
WHERE articles.article_id = categories.article_id
AND categories.article_id = 1
AND categories.article_id = 2
AND categories.article_id = 3
but it doesn't work. Obviously mySQL needs another syntax.
Can someone help?
Thanks
SELECT
Articles.article_id,
COUNT( Categories.article_id ) AS total
FROM CategoryArticles
LEFT JOIN Articles USING (article_id)
WHERE
CategoryArticles.category_id IN (1,2,3)
GROUP BY CategoryArticles.article_id
HAVING total = 3
I used a bit different names for table because in your example the distinction between category and categories is hard to notice.
An column of a row cannot be 1, 2 or 3 at the same time, which is what AND stipulates. Use OR in your WHERE condition. Better yet - for readability - you can use IN:
SELECT ...
WHERE `categories`.`article_id` IN(1,2,3)
In addition to the commonly used IN() and using a HAVING count, I would be interested in the performance difference by doing a multiple-join as follows...
SELECT STRAIGHT_JOIN
articles.article_id,
articles.title,
articles.body
FROM
categories c1
JOIN articles
on c1.article_id = articles.article_id
JOIN categories c2
on c1.article_id = c2.article_id
AND c2.category_id = 2
JOIN categories c3
on c1.article_id = c3.article_id
AND c3.category_id = 3
WHERE
c1.Category_ID = 1
Yes, this may look obscure, but lets think about it... by doing a join FIRST on the categories table where ONE of your specific categories -- THIS FIRST FROM instance of categories should be representative of whichever category would have the smallest granularity. Ex: Your categories of Local News, Visible and First 10. Local news would probably have the most entries, while Visible and First 10 would have even less... of those, which would have even the smallest number of records. Use THIS category as the where clause.
So, say you have 100,000 articles, and 90,000 are in local news, 45,000 in Visible, and 12,000 in First 10. By starting your query on only those in the 12,000, you are eliminating most of the data.
By then joining to the articles table, and categories AGAIN as alias C2 and C3 respectively based on the other conditions, if found, done, if not, its excluded.
Again, I'm wondering the performance impact. I would also have a compound index on the categories table on both (article_id, category_id)
The value cannot be all three values simultaneously, so you'd better use an IN clause in your WHERE to define which you want to return. Give you've already got a join condition there, you'd want to move that to an ON clause instead as well; ie:
SELECT articles.article_id, articles.title, articles.body, categories.article_id, categories.category_id
FROM articles
INNER JOIN categories ON articles.article_id = categories.article_id
WHERE categories.article_id IN ( 1, 2, 3 )
Of course, you can go to the next step and do:
SELECT articles.article_id, articles.title, articles.body, category.category
FROM articles
INNER JOIN categories ON articles.article_id = categories.article_id
INNER JOIN category ON categories.category_id = category.category_id
WHERE categories.article_id IN ( 1, 2, 3 )
If instead you wanted to show only articles that appear in all three categories, then you could take an approach like:
SELECT articles.article_id, articles.title, articles.body
FROM articles
INNER JOIN categories AS c1
ON articles.article_id = c1.article_id
AND c1.category_id = 1
INNER JOIN categories AS c2
ON articles.article_id = c2.article_id
AND c2.category_id = 2
INNER JOIN categories AS c3
ON articles.article_id = c3.article_id
AND c3.category_id = 3