How to select the MAX from the COUNT in SQL - mysql

That is a picture of my table.
I must select "Fastanumer" of all cars where "Tegund" is the most common value (which is Toyota in this example)
This is the code i tried
SELECT Fastanumer FROM `Bill`
WHERE Tegund =
(SELECT MAX(y.cnt) FROM (SELECT COUNT(Tegund) AS cnt FROM Bill ) AS y)
Which i had to work pretty hard to figure out only to end up beating myself in the head over the fact that MAX will only turn into a number. (And since Tegund isn't a list of numbers...)
Is this even possible? How can i do this?

I guess it should work this way:
SELECT Fastanumer
FROM `Bill`
WHERE Tegund = (
SELECT Tegund
FROM (
SELECT Tegund,COUNT(*) FROM Bill GROUP BY Tegund ORDER BY COUNT(*) DESC LIMIT 1
) t1
)
Or even like this:
SELECT Fastanumer
FROM `Bill`
WHERE Tegund = (
SELECT Tegund FROM Bill GROUP BY Tegund ORDER BY COUNT(*) DESC LIMIT 1
)

Here's my solution:
SELECT Bill.*
FROM Bill
WHERE Tegund IN (
SELECT Tegund
FROM Bill
GROUP BY Tegund
HAVING COUNT(*) = (
SELECT MAX(cnt) FROM (
SELECT COUNT(*) cnt
FROM Bill
GROUP BY Tegund
) s
)
)
A little more complicated than others, but if more than one Tegund shares the same number of rows, this query will show all Tegunds which are the most common.
Please see fiddle here or here.

What you want to do first is figure out which Tegund appears the most in your table. That is what the subquery is doing. Then you will select the Fastanumer which matches that Tegund.
SELECT DISTINCT Fastanumer
FROM 'BILL'
WHERE Tegund = (
SELECT TOPT 1 Tegund,
COUNT(*) as Count
FROM `BILL`
GROUP BY Tegund
ORDER BY Count DESC)

Depends on the DB (and associated SQL). Try
select fastanumber from bill
inner join
(select count(*) as cnt, tegund from Bill group by tegund) grpby
on bill.tegund = grpby.tegund
and grpby.cnt = (select max(cnt) from (select count(*) as cnt, tegund from Bill group by tegund))

Related

How to use a dynamic limit in sql query

I have a query SELECT * FROM grades WHERE userid = 4123;
I want to limit this query
I have a query SELECT * FROM grades WHERE userid = 4123 LIMIT(2);
This works great but if I want this limit to be dynamic from another query.
SELECT COUNT(id) FROM count_table WHERE course = 131;
doing this gives me a syntax error
SELECT * FROM grades WHERE userid = 4123 LIMIT (SELECT COUNT(id) FROM count_table WHERE course = 131);
if this is not possible at all, then is there an alternative way to achieve this?
please help.!
You can do it in MySQL 8.x using the ROW_NUMBER() function.
Assuming you order the rows by some column (I guessed the column ID... change it as needed), you can do:
select
g.*
from (
select
*,
row_number() over(order by id) as rn -- change ordering as needed
from grades
) g
join (
SELECT COUNT(id) as cnt FROM count_table WHERE course = 131
) c on g.rn <= c.cnt

Trying to figure out how to find the max count

Which team has the most number of members on their roster?
Okay so below is the code that I have input currently. It returns all the teams as well as how many people are on each team. I am not sure how to code it to only display the team with the most members as when I try to use a max function and a count function I get an error.
SELECT Team_Name, COUNT(Member.Student_ID_Num)
FROM Teams
JOIN Member ON Teams.Team_Number = Member.Team_Number
GROUP BY Team_Name
you can try below - using limit and order by desc
Select Team_Name, count(Member.Student_ID_Num) as cnt
from Teams join Member on Teams.Team_Number = Member.Team_Number
group by Team_Name
order by cnt desc
limit 1
If you are using MySQL 8+, then the ROW_NUMBER function comes in handy here:
SELECT Team_Name, cnt
FROM
(
SELECT t.Team_Name, COUNT(*) AS cnt,
ROW_NUMBER() OVER (ORDER BY COUNT(*) DESC) rn
FROM Teams t
INNER JOIN Member m
ON t.Team_Number = m.Team_Number
GROUP BY t.Team_Name
) t
WHERE rn = 1;
If you instead want all ties for the highest count, should two or more teams be tied, then replace ROW_NUMBER with RANK.
If you have to do this the old fashioned way, without LIMIT or ROW_NUMBER, then get ready for a really ugly query:
SELECT
t.Team_Name,
COUNT(*) AS cnt
FROM Teams t
INNER JOIN Member m
ON t.Team_Number = m.Team_Number
GROUP BY t.Team_Name
HAVING COUNT(*) = (SELECT MAX(cnt) FROM (SELECT COUNT(*) AS cnt
FROM Teams t
INNER JOIN Member m
ON t.Team_Number = m.Team_Number
GROUP BY t.Team_Name) t );
In order to get the team with the highest member count, we need no join (unless we also want to show the member count). One thing to keep in mind that there may be multiple teams sharing the same maximum member count.
The old fashioned way in standard SQL, before there was any limit clause (FETCH FIRST ROWS in standard SQL) was this:
Count members per team number.
Get the maximum count.
Get the team number(s) with this maximum count.
Get the team(s) for these team numbers.
The query:
select *
from teams
where team_number in
(
select team_number
from member
group by team_number
having count(*) =
(
select max(cnt) as max_cnt
from
(
select count(*) as cnt
from member
group by team_number
) counted
)
);
As of MySQL 8 we would rather use a wnindow function, however:
select *
from teams
where (team_number, 1) in
(
select team_number, rank() over (order by count(*) desc)
from member
group by team_number
);

MYSQL: group by and count issues

I've done research on this problem, but am having trouble finding a solution.
How can I get the output like this ?
You can join your original table to a subquery which tallies the students attending each school.
SELECT t1.student,
t2.count,
t1.school
FROM yourTable t1
INNER JOIN
(
SELECT school, COUNT(*) AS count
FROM yourTable
GROUP BY school
) t2
ON t1.school = t2.school
ORDER BY t2.count DESC,
t1.school
Note that your intended order was not clear from the question. You might have been looking for this ordering:
ORDER BY t1.school,
t1.count -- or t2.count DESC
If you really want every student appears in rows, you should do it like this:
select
yourtable.student, t.cnt as `count`, t.school
from (
select count(id) as cnt, school
from yourtable
group by school
) t
left join yourtable
on yourtable.school = t.school
order by t.school, yourtable.id
or if you just want all the student for every school, you can use group_concat
select
group_concat(student) as student,
count(id) as `count`,
school
from yourtable
group by school
the student will be separeted by , in one row for each school.

How to get a percentage of total when the query has a GROUP BY?

Say I have a non-normalized table with movie actor names and the movies they've been in. eg.
CREATE TABLE movies_actors (
movies_actors_id INT,
movie VARCHAR(255),
actor VARCHAR(255),
PRIMARY KEY (movies_actors_id)
);
I do a SELECT actor, COUNT(1) FROM movies_actors GROUP BY actor to find out how many movies the actor has been in. But I also want to find out what percentage of movies that actor has been in.
I guess I could do this:
SELECT
actor,
COUNT(1) AS total,
COUNT(1) / (SELECT COUNT(1) FROM movies_actors) * 100 AS avg
FROM movies_actors
GROUP BY actor;
But that just seems... idk... yucky.
Any ideas?
For large sets, a JOIN may perform better than the subquery.
SELECT ma.actor
, COUNT(1) AS total
, COUNT(1) / t.cnt * 100 AS `percentage`
FROM movies_actors ma
CROSS
JOIN (SELECT COUNT(1) AS cnt FROM movies_actors) t
GROUP
BY ma.actor
, t.cnt
For large sets, and when a large percentage of the rows are being returned, the JOIN operation can usually outperform a subquery. In your case, it's not a correlated subquery, so MySQL shouldn't have to execute that multiple times, so it may not make any difference.
Note to non-fans of COUNT(1)... we could replace any and all occurrences of COUNT(1) with COUNT(*) or IFNULL(SUM(1),0) to achieve equivalent result.
Do a Self cross join whenever you want to get manipulated data from same table.
SELECT
m.actor,
COUNT(m.actor) AS total,
(COUNT(m.actor) / t.total_movies) * 100 AS avg
FROM movies_actors m
cross (select count(*) as total_movies from movies_actors) t
GROUP BY m.actor;
Without using join and multiple query :-
select actor,counter, 100 * counter / #total as percentage
from(
select actor,
case when actor is null
then #total := count(*)
else count(*)
end as counter
from movies_actors
group by actor
with rollup
) mytable
I'm not sure if it's any "better", but you could do a SUM and do the math elsewhere:
SELECT actor,
COUNT(1) AS total,
SUM(oneMoviePercentPts) AS percentage
FROM movies_actors
CROSS JOIN
(
SELECT 100 / CAST(COUNT(1) AS DECIMAL(15,4)) AS oneMoviePercentPts
FROM movies_actors
) t
GROUP BY actor
I would hope the MySQL optimizer is smart enough to not execute your subquery more than once but the join syntax makes that explicit.
This works for me:
SELECT tmpTotal.yearmonth, tmpTotal.rec_count,
(tmpTotal.rec_count / #myCumul) * 100 AS myPercentage
FROM
(
SELECT tmpResult.*, #myCumul := #myCumul + tmpResult.rec_count AS myNewCumul
FROM
(
SELECT date_format(d.created_at, '%Y/%m') as yearmonth, count(*) rec_count
FROM cf4a_webapp.factTable d
join cf4a_webapp.dimTable c on (d.client_id = c.id)
WHERE c.id = 25
AND d.created_at >= '2019-01-01 00:00:01'
AND d.created_at < '2020-01-01 00:00:01'
GROUP BY yearmonth
) tmpResult
JOIN (SELECT #myCumul := 0) tmpCumul
) tmpTotal;

Summing union of counts in a correlated subquery

I have a member table that has a foreign key to various other tables. I am checking each of these tables to see if a member has one or more records in it and if they do I return a value, if not I return 0, this is all selected as a total. This is mostly working except in one place. I need to check two tables and if there is a record in either of them the query will return 5,0 otherwise. I am trying to use a SUM of counts with a UNION for this but I am not getting the results I expect, it seems like only the first record in each of the two tables is being selected and that is it.
I am using(after some help ) a series of correlated queries with COUNT() and IF() to get the total. Here is what part of the query looks like :
SELECT
member_id,
(SELECT IF(COUNT(member_id)>0,10,0) FROM tbl1 WHERE member_id = m.member_id)
+
(SELECT IF(SUM(tbl_count) > 0,5,0) FROM
(
SELECT member_id, COUNT(tbl2.id) as tbl_count
FROM tbl2
UNION ALL
SELECT member_id, COUNT(tbl3.id) as tbl_count
FROM tbl3
) sub WHERE sub.member_id = m.member_id
)
as total
FROM members m
The actual query joins another 10 or so tables, again the only part that is not working is the SUM of COUNT with the UNION. Could anyone suggest how I should do this? Any help would be very much appreciated. Thank you very much.
I think you are looking for this:
First try (FAIL)
SELECT
member_id,
(SELECT IF(COUNT(member_id)>0,10,0) FROM tbl1 WHERE member_id = m.member_id)
+
(SELECT IF(SUM(tbl_count) > 0,5,0) FROM
(
SELECT COUNT(*) as tbl_count
FROM tbl2
WHERE tbl2.member_id = m.member_id
UNION ALL
SELECT COUNT(*) as tbl_count
FROM tbl3
WHERE tbl3.member_id = m.member_id
) sub
)
as total
FROM members m
Second try:
SELECT
member_id,
(SELECT IF(COUNT(member_id)>0,10,0) FROM tbl1 WHERE member_id = m.member_id)
+
(SELECT IF(SUM(tbl_count) > 0,5,0) FROM
(
SELECT member_id, COUNT(*) as tbl_count
FROM tbl2
GROUP BY member_id
UNION ALL
SELECT member_id, COUNT(*) as tbl_count
FROM tbl3
GROUP BY member_id
) sub
WHERE sub.member_id = m.member_id
)
as total
FROM members m
If the query has 10 joins maybe you have to think about refactoring... :-)