To list column from table mentioned in sub query (MySQL) - mysql

Consider the three tables - actors, roles and movies
mysql> DESCRIBE actors;
+------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | 0 | |
| first_name | varchar(100) | YES | MUL | NULL | |
| last_name | varchar(100) | YES | MUL | NULL | |
| gender | char(1) | YES | | NULL | |
+------------+--------------+------+-----+---------+-------+
4 rows in set (0.17 sec)
mysql> DESCRIBE roles;
+----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| actor_id | int(11) | NO | PRI | NULL | |
| movie_id | int(11) | NO | PRI | NULL | |
| role | varchar(100) | NO | PRI | NULL | |
+----------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql> DESCRIBE movies;
+-----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | 0 | |
| name | varchar(100) | YES | MUL | NULL | |
| year | int(11) | YES | | NULL | |
| rankscore | float | YES | | NULL | |
+-----------+--------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
The following query list the first_name and last_name of all actors acted in movie 'Schindler's List':
mysql> SELECT first_name, last_name FROM actors WHERE id IN
-> (SELECT actor_id FROM roles WHERE movie_id IN
-> (SELECT id FROM movies WHERE name='Schindler\'s List')
-> ) ORDER BY first_name;
Suppose if I want to list the role played by the actors along with their first and last names, what will the best query to fetch the desired result set or output? It may be noted that the role is a column in roles table, which is in the Sub Query.

SELECT DISTINCT a.first_name, a.last_name, r.role
FROM actors a, roles r, movies m
WHERE a.id = r.actor_id and r.movie_id = m.id and m.name='Schindler\'s List'
ORDER BY first_name;
or you can use by joins;
SELECT DISTINCT a.first_name, a.last_name, r.role
FROM roles r
INNER JOIN actors a ON a.id = r.actor_id
INNER JOIN movies m ON r.movie_id = m.id
WHERE m.name='Schindler\'s List'
ORDER BY first_name;

Related

What is the average year_max - year_min in these sql tables?

I have 3 tables: actors, movies and cast:
mysql> desc actors;
+-----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+-------+
| id | int | NO | PRI | 0 | |
| full_name | varchar(200) | YES | | NULL | |
| gender | varchar(1) | YES | | NULL | |
+-----------+--------------+------+-----+---------+-------+
mysql> desc movies;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int | NO | PRI | 0 | |
| title | varchar(100) | YES | | NULL | |
| year | int | YES | | NULL | |
| genre | varchar(100) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
and
mysql> desc cast;
+----------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+------+------+-----+---------+-------+
| actor_id | int | YES | MUL | NULL | |
| movie_id | int | YES | MUL | NULL | |
| salary | int | YES | | NULL | |
+----------+------+------+-----+---------+-------+
The connection between tables is: cast.movie_id = movies.id and actors.id = cast.actor_id
The question: what is the average career longevity(years between the first film and the last film) of
actors who were at least in five films during their career?
I have tried to list actors ordered by the number of films, they took part in:
mysql> select full_name, count(title) as movie_title from cast, actors, movies
-> where cast.movie_id = movies.id and actors.id = cast.actor_id
-> group by full_name
-> order by movie_title
-> desc limit 2;
+--------------------------+-------------+
| full_name | movie_title |
+--------------------------+-------------+
| Kevin Bacon | 9 |
| Bill Paxton | 3 |
...
If what I've done is correct (not sure), we have only one such actor, so the question will be how to find this span
Will be very grateful for any advice!
How about:
SELECT AVG(YearsActive) TotalAverage
FROM (
-- by actor
SELECT a.id AS ActorId,
-- GROUP_CONCAT(a.full_name) AS ActorName,
(MAX(m.year) - MIN(m.year)) AS YearsActive
FROM actors a
INNER JOIN cast c ON a.id = c.actor_id
INNER JOIN movies m ON c.movie_id = m.id
GROUP BY a.id
HAVING COUNT(0) >= 5
) B
;

MySQL 5.7: Order by left-joined one-to-many tables

Database
mysql> DESCRIBE filtercategories;
+----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(16) | NO | | NULL | |
| position | tinyint(4) | NO | | NULL | |
+----------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
mysql> DESCRIBE tags;
+---------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| slug | varchar(64) | NO | UNI | NULL | |
| name | varchar(128) | NO | | NULL | |
| color | varchar(7) | NO | | NULL | |
| visible | tinyint(1) | NO | | 0 | |
+---------+--------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
mysql> DESCRIBE filtercategories_tags;
+-------------------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| filtercategory_id | int(11) | NO | MUL | NULL | |
| tag_id | int(11) | NO | MUL | NULL | |
| position | tinyint(4) | NO | | NULL | |
+-------------------+------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
Goal
To return a LIST of filtercategories ordered by position, the left-joined tags should be ordered by position as well.
So far trying smth like:
SELECT
fc.*,
GROUP_CONCAT(t.name) AS tagNames
FROM filtercategories fc
LEFT JOIN (filtercategories_tags fc_t, tags t)
ON (
fc_t.filtercategory_id = fc.id AND
t.id = fc_t.tag_id
)
GROUP BY fc.id
ORDER BY fc.position
Problem is that MySQL would not allow to use ORDER BY fc_t.position:
ER_WRONG_FIELD_WITH_GROUP: Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 'foo_db.fc_t.position' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
the left-joined tags should be ordered by position as well.
Then you should use an ORDER BY clause within GROUP_CONCAT():
SELECT
fc.*,
GROUP_CONCAT(t.name ORDER BY fc_t.position) AS tagNames
FROM filtercategories fc
LEFT JOIN filtercategories_tags fc_t ON fc_t.filtercategory_id = fc.id
LEFT JOIN tags t ON t.id = fc_t.tag_id
GROUP BY fc.id
ORDER BY fc.position
I also fixed your JOIN syntax. Please don't mix explicit JOINs with comma joins in one query. This is hard to understand and debug.

How to paramaterize a JOIN?

Given the following tables
mysql> describe customers;
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| customer_id | int(11) | NO | PRI | NULL | auto_increment |
| login | varchar(16) | NO | | NULL | |
| password | varchar(40) | NO | | NULL | |
| name | varchar(32) | NO | UNI | NULL | |
| address | varchar(64) | NO | | NULL | |
| contact | varchar(32) | NO | | NULL | |
+-------------+-------------+------+-----+---------+----------------+
6 rows in set (0.02 sec)
mysql> describe orders;
+-----------------+-------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+-------------+------+-----+-------------------+----------------+
| customer_id | int(11) | NO | MUL | NULL | |
| order_id | int(11) | NO | PRI | NULL | auto_increment |
| order_timeStamp | timestamp | NO | | CURRENT_TIMESTAMP | |
| item | varchar(16) | NO | | NULL | |
| price | double | NO | | NULL | |
+-----------------+-------------+------+-----+-------------------+----------------+
5 rows in set (0.04 sec)
I want to get all rows of orders which match a parameterized query (my code will pass in customer_id), plus the customer name from the customers table.
How do I do that?
JOIN the two tables, and put the condition in the WHERE clause at the end of the query:
SELECT
o.order_id,
o.order_timestamp,
o.item,
o.price,
c.name,
c.address,
c.contact
FROM Orders AS o
INNER JOIN Customers AS c ON o.customer_id = c.customer_id
WHERE o.customer_id = ?
select orders.*, customers.name
from orders, customers
where orders.customer_id=customers.customer_id
and customers.customer_id='MY_ID';

MySql query error, can anyone equivalent query of this?

I tried this
select posts.id, posts.title
from posts
inner join (
select post_id,max(created)
from comments
group by post_id
order by max(created) DESC ) as foo
on posts.id=foo.post_id
order by foo.max(created) DESC;
Error
ERROR 1630 (42000): FUNCTION foo.max does not exist.
Check the 'Function Name Parsing and Resolution' section in the Reference Manual
Tables
mysql> describe comments;
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| post_id | int(11) | NO | MUL | NULL | |
| name | varchar(255) | NO | | NULL | |
| email | varchar(255) | NO | | NULL | |
| body | varchar(500) | NO | | NULL | |
| mark | tinyint(4) | NO | | 1 | |
| created | datetime | YES | | NULL | |
| modified | datetime | YES | | NULL | |
+----------+--------------+------+-----+---------+----------------+
8 rows in set (0.00 sec)
mysql> describe posts;
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | NO | | NULL | |
| title | varchar(255) | NO | | NULL | |
| body | text | YES | | NULL | |
| category_id | int(11) | NO | | NULL | |
| tags | varchar(50) | NO | | NULL | |
| mark | tinyint(4) | NO | | 1 | |
| created | datetime | YES | | NULL | |
| modified | datetime | YES | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
9 rows in set (0.00 sec)
I need to get the posts with latest comments.
You have using the wrong reference here :-
foo.max(created)
It should be :-
max(foo.created)
The error message is already reveal where is the problem,
you should always debug on the error message when you encounter an error
But you did not return a column created for alias foo, so :-
select posts.id, posts.title
from posts
inner join
(
select post_id,max(created) AS created
from comments
group by post_id
) as foo
on posts.id=foo.post_id
order by created DESC; <-- you don't need max
select posts.id, posts.title
from posts
inner join (
select post_id, max(created) as most_recent
from comments
group by post_id) as foo
on posts.id=foo.post_id
order by most_recent DESC;
The problem is that max(created) in the subquery should have a name. An you do not need to sort in a subquery.
There is no foo.max function.
Did you mean:
SELECT posts.id,
posts.title
FROM posts
INNER JOIN (SELECT post_id,
created
FROM comments
GROUP BY post_id
ORDER BY Max(created) DESC) AS foo
ON posts.id = foo.post_id
ORDER BY Max(foo.created) DESC;

Query randomly returning all items or just some items

I have 4 tables:
mysql> describe solution_sections;
+---------------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+---------------+------+-----+---------+----------------+
| solution_section_id | int(10) | NO | PRI | NULL | auto_increment |
| display_order | int(10) | NO | | NULL | |
| section_name | varchar(1000) | YES | | NULL | |
+---------------------+---------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
mysql> describe suggested_solution_comments;
+-----------------------+----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+----------------+------+-----+---------+----------------+
| comment_id | int(10) | NO | PRI | NULL | auto_increment |
| problem_id | int(10) | NO | | NULL | |
| suggested_solution_id | int(10) | NO | | NULL | |
| commenter_id | int(10) | NO | | NULL | |
| comment | varchar(10000) | YES | | NULL | |
| solution_part | int(3) | NO | | NULL | |
| date | date | NO | | NULL | |
+-----------------------+----------------+------+-----+---------+----------------+
mysql> describe users;
+--------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+---------------+------+-----+---------+----------------+
| user_id | int(10) | NO | PRI | NULL | auto_increment |
| first_name | varchar(100) | NO | | NULL | |
| last_name | varchar(100) | NO | | NULL | |
| email | varchar(150) | NO | | NULL | |
| user_pass | varchar(40) | NO | | NULL | |
| zip | varchar(100) | NO | | NULL | |
| country | varchar(100) | NO | | NULL | |
| city | varchar(100) | NO | | NULL | |
| state | varchar(100) | NO | | NULL | |
| lat | float(9,6) | YES | | NULL | |
| lng | float(9,6) | YES | | NULL | |
| agreed_terms | tinyint(1) | YES | | NULL | |
| join_date | date | NO | | NULL | |
| last_login | date | NO | | NULL | |
| bio_blurb | varchar(5000) | YES | | NULL | |
+--------------+---------------+------+-----+---------+----------------+
15 rows in set (0.03 sec)
mysql> describe member_photo;
+-------------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+---------------+------+-----+---------+----------------+
| photo_id | int(10) | NO | PRI | NULL | auto_increment |
| member_id | int(10) | NO | | NULL | |
| photo_description | varchar(3000) | YES | | NULL | |
| photo_path | varchar(1000) | NO | | NULL | |
| small_thumb | varchar(1000) | YES | | NULL | |
| mid_thumb | varchar(1000) | YES | | NULL | |
| is_main_photo | tinyint(1) | YES | | NULL | |
+-------------------+---------------+------+-----+---------+----------------+
And I have a query like this:
select comment_id,
commenter_id,
section_name,
comment,
solution_part,
display_order,
solution_section_id,
suggested_solution_id,
DAYOFMONTH(date),
DAYNAME(date),
YEAR(date),
MONTH(date),
first_name,
last_name,
email,
small_thumb,
mid_thumb
from solution_sections
left join suggested_solution_comments on
solution_sections.solution_section_id = suggested_solution_comments.solution_part
left join users on
suggested_solution_comments.commenter_id = users.user_id
left join member_photo on
suggested_solution_comments.commenter_id = member_photo.member_id
where suggested_solution_id = 61 OR
suggested_solution_id IS NULL
order by solution_section_id,
comment_id,
section_name,
comment,
solution_part,
display_order;
What its supposed to do is get each section_name from the solution_sections table, and then find the comments (and data about who commented). Sometimes there are no comments, but it should still return at least the row with section_name and all other things being null.
But for some reason it does not. And the weirdest part is that if I give it a different suggested_solution_id to match, it will return all of the rows of solution_sections.
Any ideas why such a thing might happen? Thank you!!
And I just realized one thing - if another comment has been made for any problem_id, this query won't return the row with that section.
You need a left outer join to view all records from your parent table when child records are not guaranteed to exits. I'd also avoid adding a where clause when using outer joins.. I think its more readable to keep your join in a subselect, and filter the results.. Try something like this:
select * from
(
select sc.comment_id,
sc.commenter_id,
ss.section_name,
sc.comment,
sc.solution_part,
ss.display_order,
ss.solution_section_id,
sc.suggested_solution_id,
DAYOFMONTH(sc.date),
DAYNAME(sc.date),
YEAR(sc.date),
MONTH(sc.date),
u.first_name,
u.last_name,
u.email,
mp.small_thumb,
mp.mid_thumb
from solution_sections ss
left outer join suggested_solution_comments sc on ss.solution_section_id = sc.solution_part
left outer join users u on sc.commenter_id = u.user_id
left outer join member_photo mp on sc.commenter_id = mp.member_id) a
where a.suggested_solution_id = 61 OR
a.suggested_solution_id IS NULL
order by a.solution_section_id,
a.comment_id,
a.section_name,
a.comment,
a.solution_part,
a.display_order;
EDIT:
select sc.comment_id,
sc.commenter_id,
ss.section_name,
sc.comment,
sc.solution_part,
ss.display_order,
ss.solution_section_id,
sc.suggested_solution_id,
DAYOFMONTH(sc.date),
DAYNAME(sc.date),
YEAR(sc.date),
MONTH(sc.date),
u.first_name,
u.last_name,
u.email,
mp.small_thumb,
mp.mid_thumb
from solution_sections ss
left outer join suggested_solution_comments sc on ss.solution_section_id = sc.solution_part
AND sc.suggested_solution_id = 61
left outer join users u on sc.commenter_id = u.user_id
left outer join member_photo mp on sc.commenter_id = mp.member_id
order by solution_section_id,
comment_id,
section_name,
comment,
solution_part,
display_order;
If you want to show solution_sections even if all the rest doesn't exist, you can use "left outer join":
select comment_id,commenter_id, section_name, comment, solution_part,
display_order, solution_section_id, suggested_solution_id,
DAYOFMONTH(date), DAYNAME(date), YEAR(date), MONTH(date),
first_name, last_name, email, small_thumb,mid_thumb
from solution_sections
left outer join suggested_solution_comments on solution_sections.solution_section_id = suggested_solution_comments.solution_part
and suggested_solution_id = 61
left outer join users on suggested_solution_comments.commenter_id = users.user_id
left outer join member_photo on suggested_solution_comments.commenter_id = member_photo.member_id
where solution_section_id = ????
order by solution_section_id, comment_id, section_name, comment, solution_part,display_order;
ps. try to use aliases for tables it's more readable :-)