Count(*) an attribute from subquery - mysql

Question:
How would you display one field from an outer query and another from an inner subquery?
My Problem:
I need to display the names of actors AND how many movies each one has made (even if they haven't been in any) without any left or right joins.
Star(starnumb, starname)
MovStar(starnumb, mvnumb)
I previously displayed the information using a join;
SELECT starname, COUNT(movstar.starnumb) AS numMovies
The issue I have is the information for the amount of movies a star has acted in are inside the Movstar relation and the star's name is inside the Star relation.
SELECT starname, COUNT(*) AS numMovies
FROM star s
Where starnumb NOT IN
(SELECT movstar.starnumb
FROM movstar)
OR starnumb IN
(SELECT movstar.starnumb
FROM movstar)
GROUP BY starname
ORDER BY numMovies DESC;
The code runs, but I can't get the right information to display inside the Count field;
SELECT starname, COUNT(*) AS numMovies

You can correlate a subquery e.g. by comparing one of its columns with one of the columns from the outer query. And count() will give 0 if no matching records was found.
SELECT s.starname,
(SELECT count(*)
FROM movstat ms
WHERE ms.starnumb = s.startnumb) nummovies
FROM star s;

Why you don't want to use join?
SELECT s.starname, count(*) AS numMovies FROM star s LEFT JOIN movstar m ON m.starnumb = s.starnumb GROUP BY startname ORDER BY numMovies DESC
should get you what you ask for if I understood it correctly.

Related

MYSQL GROUP BY and WHERE clause

I have this query that runs just fine:
SELECT offers.*, COALESCE(SUM(commission),0) AS revenue, COUNT(commission) AS leads
FROM offers
LEFT JOIN offers_revenue AS or ON or.offerid=offers.offerid
GROUP BY offers.offerid
This returns me all of the rows in the offers table with correct comission added up.
Now I need to add a where clause (lets say, to not SUM when a certain condition is met):
SELECT offers.*, COALESCE(SUM(commission),0) AS revenue, COUNT(commission) AS leads, reversed
FROM offers
LEFT JOIN offers_revenue AS or ON or.offerid=offers.offerid
WHERE reversed=0
GROUP BY offers.offerid, reversed
First I tried just adding the WHERE clause, but that returned me an empty set of results, after digging around I've learned that you need to include where parameters in your GROUP BY and include them in the SELECT... but still, no results.
What am I doing incorrectly here? On the first query, all the results on my test tables are set to have reversed=0, so I must be missing something here.
Presumably reversed is in the or table. You are turning the left outer join into an inner join by doing the comparison. The solution is to move the condition to the on clause:
SELECT o.*, COALESCE(SUM(ofr.commission),0) AS revenue, COUNT(ofr.commission) AS leads, reversed
FROM offers o LEFT JOIN
offers_revenue ofr
ON `ofr`.offerid = o.offerid and ofr.reversed = 0
GROUP BY o.offerid;
try this with IF statment:
SELECT offers.*, if(reversed=0 , 0 , SUM(commission)) ) AS revenue,
COUNT(commission) AS leads,
reversed
FROM offers
LEFT JOIN offers_revenue AS or ON or.offerid=offers.offerid
GROUP BY offers.offerid, reversed

SQL query is not retrieving all the fields

I have to tables in my database, the first one (participants) look just like that:
And I have another called votes in which I can vote for any participants.
So my problem is that I'm trying to get all the votes of each participant but when I execute my query it only retrieves four rows sorted by the COUNT of votes, And the other remaining are not appearing in my query:
SELECT COUNT(DISTINCT `votes`.`id`) AS count_id, participants.name
AS participant_name FROM `participants` LEFT OUTER JOIN `votes` ON
`votes`.`participant_id` = `participants`.`id` GROUP BY votes.participant_id ORDER BY
votes.participant_id DESC;
Retrieves:
I think the problem is that you're grouping by votes.participant_id, rather than participants.id, which limits you to participants with votes, the outer join notwithstanding. Check out http://sqlfiddle.com/#!2/c5d3d/5/0
As what i have understood from the query you gave you were selecting unique id's from the votes table and I assume that your column id is not an identity. but it would be better if that would be an identity? and if so, here is my answer.replace your select with these.
Select count (votes.participant.id) as count_id ,participants.name as participant_name
from participants join votes
on participants.id = vote.participant_id
group by participants.name
order by count_id
just let me know if it works
cheers

mysql left join not returning empty row

I'm trying to get the list of categories with number of child records present in there. If the categories doesn't have records it should return NULL or 0 but my query returning categories with child records looks like its skipping the one without child records. ... will really appreciate the help.
here's my code:
SELECT
t_gal.f_sub_category_id,
t_sub_cat.f_sub_cat_name,
t_gal.f_image_thumb, (
SELECT COUNT(*)
FROM t_gallery
WHERE f_sub_category_id = t_gal.f_sub_category_id)
AS f_image_total
FROM t_gallery t_gal
LEFT JOIN t_sub_category t_sub_cat ON t_sub_cat.r_id = t_gal.f_sub_category_id
GROUP BY t_sub_cat.r_id
ORDER BY t_gal.f_added_on DESC, t_gal.r_id DESC
Here's the two tables:
Problem appears to be your group by clause.
You are grouping by a field that is on the LEFT JOINed table, hence when it does the group by all the rows which do not have a matching row on that table would appear to be aggregated into a single row.
I think what you are trying to get is a list of gallery items, along with the category they are in (if found) and the count of other galleries in the same category. If so try the following (if not let me know!)
SELECT t_gal.f_sub_category_id, t_sub_cat.f_sub_cat_name, t_gal.f_image_thumb, Sub1.GalleryCount
FROM t_gallery t_gal
LEFT JOIN t_sub_category t_sub_cat
ON t_sub_cat.r_id = t_gal.f_sub_category_id
LEFT OUTER JOIN (SELECT f_sub_category_id, COUNT(*) AS GalleryCount FROM t_gallery GROUP BY f_sub_category_id) Sub1
ON Sub1.f_sub_category_id = t_gal.f_sub_category_id
ORDER BY t_gal.f_added_on DESC, t_gal.r_id DESC
It LOOKS like for every sub-category (of a previously selected category), you want to include ALL of that sub-category... And, of those sub-categories, you want a count of how many images for that category wheather or not there even IS an image in the gallery table.
What you may have been running into is the select statement for the FIELD used to count images... first, that could become a performance killer. Instead, you could just do a left-join directly to the gallery table and COUNT the distinct R_IDs from the gallery FOR the corresponding sub-category
SELECT
t_sub_cat.r_id,
t_sub_cat.f_sub_cat_name,
MIN( COALESCE( t_gal.f_image_thumb, '' )) as JustOneThumbImg,
COUNT( DISTINCT( t_gal.r_id )) SubCategoryImageCount
FROM
t_sub_category t_sub_cat
LEFT JOIN t_gallery t_gal
ON t_sub_cat.r_id = t_gal.f_sub_category_id
GROUP BY
t_sub_cat.r_id
ORDER BY
t_sub_cat.f_added_on DESC
Since you are not grabbing all gallery images (since some may not exist FOR a given sub-category), ordering by the t_gal.r_id doesn't make sense
Also, the reason I'm not pre-grabbing aggregates in a sub-query to join against... I don't want to get everything from every category / sub-category without knowing which sub-categories are associated with the category you actually want.
the problem with your query is that you are using t_gallery as your main table and not t_sub_category while using left join.
you could try this: sqlfiddle
select
t_gal.f_sub_category_id,
t_sub_cat.f_sub_cat_name,
(
SELECT COUNT(*)
FROM t_gallery
WHERE f_sub_category_id = t_gal.f_sub_category_id)
AS f_image_total
from t_sub_category as t_sub_cat
left join t_gallery t_gal on t_gal.f_sub_category_id = t_sub_cat.r_id
GROUP BY t_sub_cat.r_id
ORDER BY t_gal.r_id DESC;

The following SQL zoo query is apparently wrong

I have a problem with the following exercise query on this page http://sqlzoo.net/3.htm :
4d. List the 1978 films by order of cast list size.
I'm trying to do the query:
SELECT DISTINCT(m1.title), COUNT(c1.actorid)
FROM ((movie AS m1 JOIN casting AS c1 ON m1.id=c1.movieid) JOIN actor AS a1 ON a1.id=c1.actorid)
WHERE m1.yr=1978
GROUP BY m1.title
ORDER BY COUNT(c1.actorid) DESC
But it doesn't give the right answer, and I don't know why. Am I wrong?
This should do it:
select m.title, count(c.actorid)
from movie m
join casting c on c.movieid = m.id
where m.yr = 1978
group by m.title
order by 2 desc
As you don't need any information from the actors, you don't need to include that table in the join.
Btw: your usage of distinct shows two misunderstandings:
distinct is not a function. It always operates on all columns of the result
when you do a group by there is no need to also to a distinct (as the group by will already return only the distinct values of the grouped columns)

How can I make these two queries into one?

I have two tables, one for downloads and one for uploads. They are almost identical but with some other columns that differs them. I want to generate a list of stats for each date for each item in the table.
I use these two queries but have to merge the data in php after running them. I would like to instead run them in a single query, where it would return the columns from both queries in each row grouped by the date. Sometimes there isn't any download data, only upload data, and in all my previous tries it skipped the row if it couldn't find log data from both rows.
How do I merge these two queries into one, where it would display data even if it's just available in one of the tables?
SELECT DATE(upload_date_added) as upload_date, SUM(upload_size) as upload_traffic, SUM(upload_files) as upload_files
FROM packages_uploads
WHERE upload_date_added BETWEEN '2011-10-26' AND '2011-11-16'
GROUP BY upload_date
ORDER BY upload_date DESC
SELECT DATE(download_date_added) as download_date, SUM(download_size) as download_traffic, SUM(download_files) as download_files
FROM packages_downloads
WHERE download_date_added BETWEEN '2011-10-26' AND '2011-11-16'
GROUP BY download_date
ORDER BY download_date DESC
I want to get result rows like this:
date, upload_traffic, upload_files, download_traffic, download_files
All help appreciated!
Your two queries can be executed and then combined with the UNION cluase along with an extra field to identify Uploads and Downloads on separate lines:
SELECT
'Uploads' TransmissionType,
DATE(upload_date_added) as TransmissionDate,
SUM(upload_size) as TransmissionTraffic,
SUM(upload_files) as TransmittedFileCount
FROM
packages_uploads
WHERE upload_date_added BETWEEN '2011-10-26' AND '2011-11-16'
GROUP BY upload_date
ORDER BY upload_date DESC
UNION
SELECT
'Downloads',
DATE(download_date_added),
SUM(download_size),
SUM(download_files)
FROM packages_downloads
WHERE download_date_added BETWEEN '2011-10-26' AND '2011-11-16'
GROUP BY download_date
ORDER BY download_date DESC;
Give it a Try !!!
What you're asking can only work for rows that have the same add date for upload and download. In this case I think this SQL should work:
SELECT
DATE(u.upload_date_added) as date,
SUM(u.upload_size) as upload_traffic,
SUM(u.upload_files) as upload_files,
SUM(d.download_size) as download_traffic,
SUM(d.download_files) as download_files
FROM
packages_uploads u, packages_downloads d
WHERE u.upload_date_added = d.download_date_added
AND u.upload_date_added BETWEEN '2011-10-26' AND '2011-11-16'
GROUP BY date
ORDER BY date DESC
Without knowing the schema is hard to give the exact answer so please see the following as a concept not a direct answer.
You could try left join, im not sure if the table package exists but the following may be food for thought
SELECT
p.id,
up.date as upload_date
dwn.date as download_date
FROM
package p
LEFT JOIN package_uploads up ON
( up.package_id = p.id WHERE up.upload_date = 'etc' )
LEFT JOIN package_downloads dwn ON
( dwn.package_id = p.id WHERE up.upload_date = 'etc' )
The above will select all the packages and attempt to join and where the value does not join it will return null.
There is number of ways that you can do this. You can join using primary key and foreign key. In case if you do not have relationship between tables,
You can use,
LEFT JOIN / LEFT OUTER JOIN
Returns all records from the left table and the matched
records from the right table. The result is NULL from the
right side when there is no match.
RIGHT JOIN / RIGHT OUTER JOIN
Returns all records from the right table and the matched
records from the left table. The result is NULL from the left
side when there is no match.
FULL OUTER JOIN
Return all records when there is a match in either left or right table records.
UNION
Is used to combine the result-set of two or more SELECT statements.
Each SELECT statement within UNION must have the same number of,
columns The columns must also have similar data types The columns in,
each SELECT statement must also be in the same order.
INNER JOIN
Select records that have matching values in both tables. -this is good for your situation.
INTERSECT
Does not support MySQL.
NATURAL JOIN
All the column names should be matched.
Since you dont need to update these you can create a view from joining tables then you can use less query in your PHP. But views cannot update. And you did not mentioned about relationship between tables. Because of that I have to go with the UNION.
Like this,
CREATE VIEW checkStatus
AS
SELECT
DATE(upload_date_added) as upload_date,
SUM(upload_size) as upload_traffic,
SUM(upload_files) as upload_files
FROM packages_uploads
WHERE upload_date_added BETWEEN '2011-10-26' AND '2011-11-16'
GROUP BY upload_date
ORDER BY upload_date DESC
UNION
SELECT
DATE(download_date_added) as download_date,
SUM(download_size) as download_traffic,
SUM(download_files) as download_files
FROM packages_downloads
WHERE download_date_added BETWEEN '2011-10-26' AND '2011-11-16'
GROUP BY download_date
ORDER BY download_date DESC
Then anywhere you want to select you just need one line:
SELECT * FROM checkStatus
learn more.