MySQL's count(*) doesn't work properly - mysql

I want to count all rows from the game_votes where g_id is equal to 14, it is working almost good, but if there aren't any records with g_id = 14 it does still show 1 in the cnt field.
Here is my query:
SELECT
SUM(vote) as vote,
COUNT(*) as cnt
FROM (`games`)
LEFT JOIN `game_votes`
ON
`game_votes`.`g_id` = `games`.`id`
WHERE `games`.`id` = '14'
Whats wrong? Am I missing something?

You're getting a count of 1 because COUNT(*) essentially counts the number of rows in your result set. Since you're selecting a row out of your games table with an id of 14 and left joining that to the game_votes table, you're going to always have 1 or more rows as long as there exists a game with an id of 14 regardless of whether or not it contains any corresponding votes in your game_votes table. Instead of COUNT(*), try COUNT(game_votes.g_id). If there are no votes, the g_id field will contain a null value, and COUNT() will not include a null value in its calculation.

Check the result of
SELECT *
FROM (`games`)
LEFT JOIN `game_votes`
ON
`game_votes`.`g_id` = `games`.`id`
WHERE `games`.`id` = '14'
and you will see that your using LEFT JOIN (instead of JOIN) is the cause.

SELECT SUM(vote) as vote, COUNT(*) as cnt from games,game_votes where game_votes.g_id=games.id and games.id=14;
This should work

The MySQL SUM function requires a GROUP BY ... see http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html

Related

SQL INNER JOIN and AVG() returning wrong data

I am trying to select all rows from a table containing data about a video and then afterwards i am joining all of their ratings as an AVG() from another table.
The thing is there is only 1 row for each video but many ratings for each video, so i have to get all the ratings and find the average for each video.
I have this piece of SQL
SELECT t1.video_id,
t1.video_title,
t1.video_url,
t1.video_views,
AVG(t2.videos_rating_rating) AS rating
FROM videos_approved t1
INNER JOIN videos_rating t2
ON t1.video_id = t2.videos_rating_video_fk
WHERE 1
ORDER BY video_id
DESC LIMIT 12
The SQL returns a result but it only returns 1 row with a wrong Average value?
Can someone explain to me why this is going on and what i could do instead?
You need to use GROUP BY here. In your current query you are taking an average over the entire table.
SELECT
t1.video_id,
t1.video_title,
t1.video_url,
t1.video_views,
AVG(t2.videos_rating_rating) AS rating
FROM videos_approved t1
INNER JOIN videos_rating t2
ON t1.video_id = t2.videos_rating_video_fk
GROUP BY
t1.video_id
ORDER BY
t1.video_id DESC
LIMIT 12
Note that my answer assumes that video_id is the primary key of the videos_approved table, in which case we may select any column from that table even when grouping by the video_id. If not, then strictly speaking we would have to do another join.
Try replacing INNER JOIN with LEFT JOIN.
See more details in this answer and on this page (search for AVG + GROUP BY + JOINS)

Fetch rows with MAX DATE and GROUP BY

I have a table name payment_schedule with following contents
I want to fetch records with MAX(due_date) GROUPED BY loan_application_id
With reference to records in above image, i expect the result to be following
I tried using following SQL query
SELECT
id,
MAX(due_date) as due_date,
loan_application_id
FROM
payment_schedule
GROUP BY
loan_application_id
Which returns me the following result.
As you see it does not return the corresponding id for a given due date.
Additionally, I have another column called payment_type_id and I need to exclude rows when payment_type_id has value of 3.
I tried several solution available here, nothing seems to work, how to go about it?
Thanks.
This is called Group-wise Maximum and tagged here as greatest-n-per-group. The most traditional approach is to find the value you want and do a join to get the corresponding row per group like this:
SELECT
ps.id,
ps.due_date,
ps.loan_application_id
FROM
(
SELECT
MAX(due_date) as due_date,
loan_application_id
FROM payment_schedule
WHERE payment_type_id != '3'
GROUP BY loan_application_id
) ps2
LEFT JOIN payment_schedule ps USING (loan_application_id)
WHERE ps.due_date = ps2.due_date
AND ps.payment_type_id != '3'
GROUP BY ps.loan_application_id
It's also worth mentioning that this query will run a bazillion times faster if you have an index on your loan_application_id and due_date columns.
Best discussion I've seen here on SO is this: Select first row in each GROUP BY group?
Also addressed in the official docs here: http://dev.mysql.com/doc/refman/5.7/en/example-maximum-column-group-row.html
If due date per loan_application_id is distinct, you can remove the keyword distinct below:
select distinct a.*
from payment_schedule a, (
select loan_application_id, max(due_date) max_date
from payment_schedule
where payment_type_id <> 3
group by 1
) as b
where a.loan_application_id = b.loan_application_id
and a.due_date = b.max_date
In most databases, this is easiest using window functions. In MySQL, you can use a join and group by:
select ps.*
from payment_schedule ps join
(select load_application_id, max(due_date) as maxdd
from payment_schedule
group by load_application_id
) l
on ps.load_application_id = l.load_application_id and ps.due_date = l.maxdd;

MySQL join on max value

From joining the tables below on the entry.id, I want to extract the rows from the food_brands table which have the highest type_id - so I should be getting the top 3 rows below, with type_id 11940
food_brands
id brand type_id
15375 cesar 11940
15374 brunos 11940
15373 butchers 11940
15372 bakers 11939
15371 asda 11939
15370 aldi 11939
types
id type quantity food_id
11940 comm 53453 10497
11939 comm 999 10496
foods
id frequency entry_id
10497 twice 12230
10496 twice 12230
10495 once 12230
entries
id number
12230 26
My attempt at the query isn't filtering out the lower type.id records - so from the table records below in food_brands, i'm getting those with type_id 11940 and 11939. Grateful for any help fix this!
SELECT fb.*
FROM food_brands fb
INNER JOIN types t ON fb.type_id = t.id
INNER JOIN
(
SELECT MAX(id) AS MaxID
FROM types
GROUP BY id
) t2 ON t.food_id = t2.food_id AND t.id = t2.MaxID
INNER JOIN foods f ON t.food_id = f.id
INNER JOIN entries e ON f.entry_id = e.id
WHERE entries.id = 12230
A simple subquery should do it just fine;
SELECT * FROM food_brands WHERE type_id=
(SELECT MAX(t.id) tid FROM types t
JOIN foods f ON f.id=t.food_id AND f.entry_id=12230)
An SQLfiddle to test with.
If you just want to return the rows from food_brands with the max type id, you should be able to use:
SELECT fb.*
FROM food_brands fb
INNER JOIN
(
select max(id) id
from types
) t
on fb.type_id = t.id
See SQL Fiddle with Demo
I don't know why you are doing all these inner joins after the one on the t2 subquery, since you are only retrieving the columns of fb, but I suppose that you are not showing the whole query, and you just want to get that one fixed.
The issue is actually in the subquery t2: there, for some untold reason, you choose to do a GROUP BY id which changes the MAX function semantic to generate a maximum value per id, and since you are asking the maximum on that very column, MAX and GROUP BY cancel out each other. Just removing the GROUP BY clause fixes the query.
If for some untold reason you cannot remove that clause, perhaps replacing MAX(id) by id and adding ORDER BY id DESC LIMIT 1 would do.
Also, your subquery should probably select also food_id since it is used in the subsequent INNER JOIN clause.

Subquery returns more than 1 row

im geting this error when trying to do 2 counts inside of my query
first ill show you the query:
$sql = mysql_query("select c.id, c.number, d.name,
(select count(*) from `parts` where `id_container`=c.id group by `id_car`) as packcount,
(select count(*) from `parts` where `id_container`=c.id) as partcount
from `containers` as c
left join `destinations` as d on (d.id = c.id_destination)
order by c.number asc") or die(mysql_error());
now the parts table has 2 fields that i need to use in the count:
id_car
id_container
id_car = the ID of the car the part is for
id_container = the ID of the container the part is in
for packcount all i want is a count of the total cars per container
for partcount all i want it a count of the total parts per container
It's because of GROUP BY You're using
Try something like
(select count(distinct id_car) from `parts` where `id_container`=c.id)
in You're subquery (can't check right now)
EDIT
PFY - I think UNIQUE is for indexes
Your grouping in your first sub-query is causing multiple rows to be returned, you will probably need to run separate queries to get the results you are looking for.
This subquery may return more than one row.
(select count(*) from `parts` where `id_container`=c.id group by `id_car`) as packcount, ...
so, i'd suggest to try something of the following:
(select count(DISTINCT `id_car`) from `parts` where `id_container`=c.id) as packcount, ...
see: COUNT(DISTINCT) on dev.mysql.com
and: QA on stackoverflow

Query returns one row with complete sum instead of per-row sum

I have 9 items in a problem_categories tables that have category_id = 1
When I do this query:
select problems.problem_id , problem_title , sum( vote ) as totalVotes
from problems
left join problem_votes on problems.problem_id = problem_votes.problem_id
left join problem_categories on problems.problem_id = problem_categories.problem_id
where problem_categories.category_id = 1;
I get 1 row with a complete sum of all the votes for the 9 items. But what I was really looking for was the 9 rows with a vote sum for each. Any idea what is wrong with my query just by looking at it?
My tables are
problem - lists problem information
problem_votes - has a record per vote for each problem
problem_categories - table keeping a problem_id and a category_id so that a problem can be in a certain category
Thanks,
Alex
You need to tell MySQL what you're grouping by. Right now it thinks you want EVERYTHING grouped into one row. If you want it to by grouped by problem_title, then add in this line after your WHERE:
GROUP BY problem_title
This will cause you to get a different row for each unique problem_title, and the sum will only count records matching that title.
Edit:
So the whole query will look something like this:
select problems.problem_id , problem_title , sum( vote ) as totalVotes
from problems
left join problem_votes on problems.problem_id = problem_votes.problem_id
left join problem_categories on problems.problem_id = problem_categories.problem_id
where problem_categories.category_id = 1
group by problem_title;
Just an FYI, most versions of SQL do not accept group by statements that do not include all non-aggregate columns. So if you're ever working with some other SQL software, you'll likely need to include problems.problem_id and problem_title.
For more on this issue, see this thread: Do all columns in a SELECT list have to appear in a GROUP BY clause