SELECT COUNT() INSIDE A SELECT MAX() SQL - mysql

I've got this table called player_mast in a db (data are just an example), and I want to find the club which supplied the most number of players to the 2016 EURO cup.
player_id
country_id
jersey_no
player_name
posi_to_play
dt_of_bir
age
playing_club
1231
1231
10
Hazard
striker
2/3/1991
33
Chelsea
Why this query doesn't work? It seems right to me:
SELECT playing_club, MAX(NumberOfPlayerForTeam)
FROM (
SELECT playing_club, COUNT(player_id) AS NumberOfPlayerForTeam
FROM player_mast
GROUP BY(playing_club))
GROUP BY(playing_club);

Try this
SELECT playing_club, NumberOfPlayerForTeam<br>
FROM (<br>
SELECT playing_club, COUNT(player_id) AS NumberOfPlayerForTeam<br>
FROM player_mast<br>
GROUP BY(playing_club))<br>
ORDER BY NumberOfPlayerForTeam DESC LIMIT 1;

If you want the playing clubs that have the most rows in your table, you can use rank():
SELECT pm.*
FROM (SELECT playing_club, COUNT(*) AS NumberOfPlayerForTeam,
RANK() OVER (ORDER BY COUNT(*) DESC) as seqnum
FROM player_mast
GROUP BY playing_club
) pm
WHERE seqnum = 1;
Note:
COUNT(<column name>) counts the number of non-NULL values in the column. There is no need to do this additional check; COUNT(*) does what you want.
Parentheses are not needed around the GROUP BY keys.

Related

Trying to utilize a window function instead of this script

I'm trying to improve my query for this topic at hand. I'm trying to find the top 5 and bottom 5 growth rates per state from 2020 to 2021 in my org. The table has the columns as specified: orderid, orderdate, totaldue, state, etc. (these are probably the most important columns). This is the query I created so far, while it works I think it would be more efficient if I was able to implement a window function instead.
SELECT state, SUM(TotalDue) as sum
into #temp2020
from table
where OrderDate like "2020%"
group by StateProvince
order by sum desc;
SELECT state, SUM(TotalDue) as sum
into #temp2021
from table
where OrderDate like "2021%"
group by StateProvince
order by sum desc;
--top 5 growth rates--
select #temp2020.state, ((#temp2021.sum-#temp2020.sum)/#temp2020.sum) as 'growthrate'
from #temp2020
join #temp2021 on #temp2021.state = #temp2020.state
order by growthrate desc limit 5
--bottom 5 growth rates--
select #temp2020.state, ((#temp2021.sum-#temp2020.sum)/#temp2020.sum) as 'growthrate'
from #temp2020
join #temp2021 on #temp2021.state = #temp2020.state
order by growthrate asc limit 5
drop table if exists #temp2020
drop table if exists #temp2021
You could use DENSE_RANK here:
WITH cte AS (
SELECT state, SUM(TotalDue) AS sum,
DENSE_RANK() OVER (ORDER BY SUM(TotalDue)) rnk_asc,
DENSE_RANK() OVER (ORDER BY SUM(TotalDue) DESC) rnk_desc
FROM yourTable
WHERE YEAR(OrderDate) IN (2020, 2021)
GROUP BY state
)
SELECT state, sum
FROM cte
WHERE rnk_asc <= 5 OR rnk_desc <= 5
ORDER BY state, sum;

How to sort teams by summarized score in SQL? (two columns sorting with SUM())

Playerbase have 3 columns: PlrName, TeamTag, Score
I need to sort players grouping them by TeamTag. And put teams with best summarized score above.
So want to figure out what query will help make this:
PlrName|TeamTag|Score PlrName|TeamTag|Score
-------------------------------------------------------
Player1|TeamThr|0 Player6|TeamThr|9 \
Player2|TeamTwo|2 Player1|TeamThr|0 > 9
Player3|TeamOne|4 Player4|TeamThr|0 /
Player4|TeamThr|0 Player5|TeamOne|4 \
Player5|TeamOne|4 became-> Player3|TeamOne|4 > 8
Player6|TeamThr|9 Player8|TeamOne|0 /
Player7|TeamTwo|2 Player2|TeamTwo|2 \
Player8|TeamOne|0 Player7|TeamTwo|2 > 6
Player9|TeamTwo|2 Player9|TeamTwo|2 /
added:
With this query i can get an array(?) of TeamTag's ordered by team score:
SELECT TeamTag FROM Playerbase GROUP BY team ORDER BY SUM(Score) DESC
..can I sort then PlayerBase using this "array"? Prefably within one query :)
Also i need to get full lines (using *), not only three fields.
If your dbms doesn't support window functions (any MySQL version below 8.0):
SELECT PlrName, TeamTag, Score FROM table a
LEFT JOIN
(SELECT PlrName, TeamTag, Score ,SUM(score) ts FROM table GROUP BY TeamTag) b
ON a.TeamTag=b.TeamTag
ORDER BY b.ts DESC, a.TeamTag, score DESC;
Try this
; with cte as (
select TeamTag, sum(Score) as Sum
from tablename)
select t.PlrName, t.teamtag, t.Score from tablename as t inner join cte as c
on t.teamtag=c.teamtag order by c.sum desc, t.score desc
Assuming your dbms supports window functions
select PlrName, TeamTag, Score
from (
select PlrName, TeamTag, Score, sum(Score) over (partition by TeamTag) ms
from tablename ) t
order by ms desc, TeamTag, Score desc
EDIT changed max() to sum() as OP refined the problem explanation.
I made it like this, but feel little uncomfortable about sql :D
SELECT * FROM `Playerbase` as T1
JOIN
(SELECT TeamTag, SUM(Score) AS Sum FROM `Playerbase` GROUP BY TeamTag ORDER BY Sum DESC) AS T2
ON T2.TeamTag = T1.TeamTag
Didn't make what i was trying to, but anyway thanks for answers. They helped me to understand a bit more :D

How to sum when they have same color with sql?

I have this table
i want to ignore productNo and sum all product count accordingly.
select sum(count), max(productNo)
from Table
where date between 117 and 118
group by product
this one gives wrong result...
I want to have sum of counts for each Product-ProductNo combination
try like below
select product,productno,sum(count) as result
from table_name
where productno='X1'
group by product,productno
seems you need the firts rows order by result
select product,productno,sum(count) as result
from table
group by product,productno
order by result
limit 1
Since you haven't tagged any DBMS so, i would use row_number():
select t.*
from (select product, productno, sum(count) as cnt,
row_number() over (partition by product order by sum(count) desc) as seq
from table t
group by product, productno
) t
where seq = 1;
You can also use LIMIT clause (but not for each product) :
select product, productno, sum(count) as cnt
from table t
group by product, productno
order by cnt desc
limit 1;
Some other DBMS requires TOP clause instead of LIMIT clause so, you can change accordingly but the idea would be same.
select sum(count), max(productNo)
from Table
where date between 117 and 118
group by product, productNo
with this it works :)

Select sum of top three scores for each user

I am having trouble writing a query for the following problem. I have tried some existing queries but cannot get the results I need.
I have a results table like this:
userid score timestamp
1 50 5000
1 100 5000
1 400 5000
1 500 5000
2 100 5000
3 1000 4000
The expected output of the query is like this:
userid score
3 1000
1 1000
2 100
I want to select a top list where I have n best scores summed for each user and if there is a draw the user with the lowest timestamp is highest. I really tried to look at all old posts but could not find one that helped me.
Here is what I have tried:
SELECT sum(score) FROM (
SELECT score
FROM results
WHERE userid=1 ORDER BY score DESC LIMIT 3
) as subquery
This gives me the results for one user, but I would like to have one query that fetches all in order.
This is a pretty typical greatest-n-per-group problem. When I see those, I usually use a correlated subquery like this:
SELECT *
FROM myTable m
WHERE(
SELECT COUNT(*)
FROM myTable mT
WHERE mT.userId = m.userId AND mT.score >= m.score) <= 3;
This is not the whole solution, as it only gives you the top three scores for each user in its own row. To get the total, you can use SUM() wrapped around that subquery like this:
SELECT userId, SUM(score) AS totalScore
FROM(
SELECT userId, score
FROM myTable m
WHERE(
SELECT COUNT(*)
FROM myTable mT
WHERE mT.userId = m.userId AND mT.score >= m.score) <= 3) tmp
GROUP BY userId;
Here is an SQL Fiddle example.
EDIT
Regarding the ordering (which I forgot the first time through), you can just order by totalScore in descending order, and then by MIN(timestamp) in ascending order so that users with the lowest timestamp appears first in the list. Here is the updated query:
SELECT userId, SUM(score) AS totalScore
FROM(
SELECT userId, score, timeCol
FROM myTable m
WHERE(
SELECT COUNT(*)
FROM myTable mT
WHERE mT.userId = m.userId AND mT.score >= m.score) <= 3) tmp
GROUP BY userId
ORDER BY totalScore DESC, MIN(timeCol) ASC;
and here is an updated Fiddle link.
EDIT 2
As JPW pointed out in the comments, this query will not work if the user has the same score for multiple questions. To settle this, you can add an additional condition inside the subquery to order the users three rows by timestamp as well, like this:
SELECT userId, SUM(score) AS totalScore
FROM(
SELECT userId, score, timeCol
FROM myTable m
WHERE(
SELECT COUNT(*)
FROM myTable mT
WHERE mT.userId = m.userId AND mT.score >= m.score
AND mT.timeCol <= m.timeCol) <= 3) tmp
GROUP BY userId
ORDER BY totalScore DESC, MIN(timeCol) ASC;
I am still working on a solution to find out how to handle the scenario where the userid, score, and timestamp are all the same. In that case, you will have to find another tiebreaker. Perhaps you have a primary key column, and you can choose to take a higher/lower primary key?
Query for selecting top three scores from table.
SELECT score FROM result
GROUP BY id
ORDER BY score DESC
LIMIT 3;
Can you please try this?
SELECT score FROM result GROUP BY id ORDER BY score DESC, timestamp ASC LIMIT 3;
if 2 users have same score then it will set order depends on time.
You can use a subquery
SELECT r.userid,
( SELECT sum(r2.score)
FROM results r2
WHERE r2.userid = r.userid
ORDER BY score DESC
LIMIT 3
) as sub
FROM result r
GROUP BY r.userid
ORDER BY sub desc
You should do it like this
SELECT SUM(score) as total, min(timestamp) as first, userid FROM scores
GROUP BY userid
ORDER BY total DESC, first ASC
This is way more efficient than sub queries. If you want to extract more fields than userid, then you need to add them to the group by.
This will of cause not limit the number of scores pr user, which indeed seems to require a subquery to solve.

Most Common Value SubQuery MySql

Is there any other way to write this query ?
I tried doing it in a subquery but it doesn't work because of the multiple columns. It seems like this query only works by itself. Please correct me
Records
PK recordId
dateViewed
CarViewed
I tried this
SELECT R.`dateViewed` FROM Records ,(
SELECT R.CarViewed, COUNT(R.CarViewed) as cnt FROM Records R
GROUP BY R.CarViewed
ORDER BY cnt DESC
LIMIT 1 ) AS favouriteCarOfTheDay
GROUP BY R.`dateViewed
Then I tried this
SELECT R.`dateViewed` ,COUNT(R.CarViewed) as cnt FROM Records ,
(
SELECT R.CarViewed FROM Records R
GROUP BY R.CarViewed
ORDER BY cnt DESC
LIMIT 1 ) AS favouriteCarOfTheDay
GROUP BY R.`dateViewed
Along many other queries I tried, I have no idea how to get it working.
In a nutshell for a specific date, I would like to get the most common cars that were viewed.
Like :
dateViewed favouriteCarOfTheDay
2012-09-22 | Nissan
2012-09-23 | BMW
try this
SELECT R.`dateViewed` ,COUNT(R.CarViewed) as cnt ,R.CarViewed FROM Records R
GROUP BY R.`dateViewed
ORDER BY COUNT(R.CarViewed) DESC
I think the following should work (disclaimer, not all my own work, adapted from an answer at another question)
SELECT DISTINCT
R.dateViewed,
R.CarViewed
FROM Records R
WHERE
R.dateViewed =
(SELECT R2.dateViewed FROM
(
SELECT R1.dateViewed, COUNT(*) AS numViewed
FROM Records R1
WHERE R1.CarViewed = R.CarViewed
GROUP BY R1.dateViewed
ORDER BY R1.numViewed DESC
) AS R2
LIMIT 1
)
ORDER BY r.dateViewed
Such things are really awful to do in MySQL so it might actually by slower than two correlated subquery but at least it returns both the car and it's viewcount:
SELECT counts.`dateViewed`,counts.`CarViewed` as favourite_car, counts.cnt
FROM
(SELECT R.`dateViewed` ,R.`CarViewed`, COUNT(*) as cnt
FROM Records
GROUP BY R.`dateViewed` ,R.`CarViewed`
) as counts JOIN
(SELECT R.`dateViewed`, MAX(cnt) as cnt
FROM
(SELECT R.`dateViewed` ,R.`CarViewed`, COUNT(*) as cnt
FROM Records
GROUP BY R.`dateViewed` ,R.`CarViewed`
) as q
GROUP BY R.`dateViewed`) as maxes
ON counts.cnt=maxes.cnt