Select Most Frequent from Multiple Columns - mysql

I've got a table like;
ID | Winner | Loser | WinningCaster | LosingCaster
0 | Player A | Player B | Warcaster A | Warcaster B
1 | Player A | Player B | Warcaster C | Warcaster A
2 | Player C | Player D | Warcaster A | Warcaster B
etc..
With various values for Player, and Warcaster.
WinningCaster / LosingCaster is a finite namelist, and I want to make a query that will find me which name occurs the most often, across both columns, both with and without a particular player entry.
IE Player A should return WarcasterA with 2, and an overall Query should return WarcasterA with 3.
So far I've only been able to get the most frequent from either column, not from both, with the following;
SELECT
ID, Winner, Loser, CasterWinner, Count(CasterWinner) AS Occ
FROM
`Games`
GROUP BY
CasterWinner
ORDER BY
Occ DESC
LIMIT 1

Use union all:
select caster, count(*)
from ((select casterwinner as caster from games
) union all
(select casterloser from games
)
) c
group by caster
order by count(*) desc
limit 1;

Related

How to get ratio between the count of two columns grouped together in mysql (leaderboard kill/death ratio)

I've got a leaderboard in a pvp shooter game where I want to display the top 20 players ordered by their kill / death ratio (total kills divided by their total deaths)
I have a kills table that tracks kills and looks something like:
| killer_id | killed_id | date |
| patrick | jim | 2021-03-01 |
| greyson | jim | 2021-03-02|
| jim | patrick | 2021-03-03|
I can get the total kills by doing something like:
SELECT COUNT(*) as total_kills
FROM kills
GROUP BY killer_id
ORDER BY total_kills DESC
LIMIT 20
And I can get the total deaths by doing something like:
SELECT COUNT(*) as total_deaths
FROM kills
GROUP BY killed_id
ORDER BY total_deaths DESC
LIMIT 20
However, I can't seem to group the query together so that I'm returning a list of the best ratios. It would look like:
| player_id | kill_death_ratio (total kills / total deaths) |
| patrick | 2.1 |
| jim | 1.0 |
| greyson | .9 |
Is this even possible in a single query?
Use this query:
SELECT killer_id player_id FROM kills UNION SELECT killed_id FROM kills
to get all the players in the table.
Then join it with LEFT joins to your queries:
SELECT p.player_id,
COALESCE(t1.total_kills, 0) / t2.total_deaths kill_death_ratio
FROM (SELECT killer_id player_id FROM kills UNION SELECT killed_id FROM kills) p
LEFT JOIN (
SELECT killer_id, COUNT(*) total_kills
FROM kills
GROUP BY killer_id
) t1 ON t1.killer_id = p.player_id LEFT JOIN (
SELECT killed_id, COUNT(*) total_deaths
FROM kills
GROUP BY killed_id
) t2 ON t2.killed_id = p.player_id
Or, without your queries:
SELECT player_id, SUM(killer) / SUM(killed) kill_death_ratio
FROM (
SELECT killer_id player_id, 1 killer, 0 killed
FROM kills
UNION ALL
SELECT killed_id, 0, 1
FROM kills
) t
GROUP BY player_id
See the demo.
Results (for your sample data):
player_id
kill_death_ratio
jim
0.5
patrick
1.0
greyson
null
Notice that you will get null for players that were never killed.

Select ID having maximum count of another ID

I have a database of baseball plays with a PlayerID and a TypeID (the kind of play: double, strike out, etc). The data looks something like this:
+----------+--------+
| playerid | typeid |
+----------+--------+
| 2 | 4 |
| 2 | 4 |
| 2 | 7 |
| 3 | 7 |
| 3 | 7 |
| 3 | 7 |
| 3 | 26 |
| 3 | 7 |
I'm trying to find which players had the most of each kind of play. E.g. Jim (PlayerID 3) had the most strike outs (TypeID 7) and Bob (PlayerID 2) had the most home runs (TypeID 4) which should result in the following table:
+----------+--------+----------------+
| playerid | typeid | max(playcount) |
+----------+--------+----------------+
| 2 | 4 | 12 |
| 3 | 7 | 9 |
| 3 | 26 | 1 |
My best attempt so far is to run:
SELECT playerid,typeid,MAX(playcount) FROM
(
SELECT playerid,typeid,COUNT(*) playcount FROM plays GROUP BY playerid,typeid
) AS t GROUP BY typeid;
Which returns the proper maximums of each type, but the associated PlayerIDs are all wrong and I can't figure out why. I'm sure I'm missing something simple (or making this overly complicated) but can't figure it out. Any ideas?
In MySQL this group=wise maximum it is sadly not a simply as you want it to be.
Here's a way to do it using a method similar to what is suggested in ROW_NUMBER() in MySQL
SELECT a.*
FROM (
SELECT playerid
,typeid
,COUNT(*) playcount
FROM plays
GROUP BY playerid,typeid
) a
LEFT JOIN
(
SELECT playerid
,typeid
,COUNT(*) playcount
FROM plays
GROUP BY playerid,typeid
) b
ON a.typeid = b.typeid
AND a.playcount < b.playcount
WHERE b.playerid IS NULL
you have to put playerid column also in group by clause.
rest all is ok.
SELECT playerid,typeid,MAX(playcount) FROM
(
SELECT playerid,typeid,COUNT(*) playcount FROM plays GROUP BY playerid,typeid
) AS t GROUP BY playerid,typeid;
Would this work?
SELECT
playertypecounts.*
FROM
(SELECT
playerid,
typeid,
COUNT(*) as playcount
FROM plays
GROUP BY playerid, typeid) playertypecounts
INNER JOIN
(SELECT
typeid,
MAX(playcount) as maxplaycount
FROM
(SELECT
playerid,
typeid,
COUNT(*) as playcount
FROM plays
GROUP BY playerid, typeid) playcounts
GROUP BY typeid) maxplaycounts
ON playertypecounts.typeid = maxplaycounts.typeid
AND playertypecounts.playcount = maxplaycounts.maxplaycount
This part of the query block returns the maximum playcount for each typeid:
(SELECT
typeid,
MAX(playcount) as maxplaycount
FROM
(SELECT
playerid,
typeid,
COUNT(*) as playcount
FROM plays
GROUP BY playerid, typeid) playcounts
GROUP BY typeid) maxplaycounts
Then it's inner-joined to all the typeid/playcounts in order to filter those counts where the player(s) have the maximum counts for any given typeid.
See SQLFiddle example.
Having said all that, I actually prefer #KarlKieninger's answer since it's more elegant.

How to get 2 videos (that belongs to a program and program belogns to a category) for every category?

There 3 tables category, program, video. Every video belongs to a program, and any program belongs to a category.
Category table
id | title
1 | cartoons
2 | documental
Program table
id | programcode | title | category_id
1 | WUCU | Program Name | 1
2 | ELKI | Program Name | 2
Video table
id | videocode | title | program_id
1 | ELKI00001 | Name | 2
2 | ELKI00002 | Name | 2
3 | ELKI00003 | Name | 2
4 | WUCU00001 | Name | 1
5 | WUCU00002 | Name | 1
6 | WUCU00003 | Name | 1
I need to get last 2 videos for every category
The problem: MySQL doesn't support getting the top most N values in a group. So we have to do it ourselves. This means we need a way to group the sets together (Category.Title and a way to know which videos to return belonging to each category. We'd like to use LIMIT here to limit the results by 2 but we can't limit by 2 for each category. We'd also like to use MAX to get the highest video ID for each category but that doesn't get us the 2nd one. So we have to build those in ourselves.
This is built using logic found:
http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/
but altered to fit your data set
This is working but I don't know why I'm having to do multiple subselects for #RNUM and #VCAT. Not sure why they have to be separated at this point. fiddle
set #Rnum :=0, #VCat :='';
SELECT * FROM (
Select SequencedSet.*, #Rnum := if(mvcat = CTitle, #Rnum + 1, 1) RowNumber from (
SELECT CTitle, VCode, VTitle, VID, #vcat mvcat,
#VCat := CTitle as VCAT
FROM (
SELECT C.Title CTitle, V.Code VCode, V.Title VTitle, V.ID VID
FROM Video V
INNER JOIN Program P
on P.ID = V.Program_Id
INNER JOIN Category C
on C.ID = P.Category_ID
ORDER BY C.Title, V.ID DESC) orderedset) sequencedSet) X
where X.ROWNUMBER<=2

Order table by presences in a third table

I have a movie database with a table for actors and another one for movies, I created a third table to add an actor partecipation in a movie. I added a field "star" to distinque leading actors from not leading actors.
I wish create a list order by the actors importance and so by the the total number of "stars".
SELECT a.id, a.name, COUNT( p.star ) AS star
FROM actors a
JOIN playing p, movies m
WHERE p.id_actor = a.id
AND p.id_movie = m.id
AND p.star =1
GROUP BY p.star
ORDER BY p.star DESC;
ACTORS
+----+---------+
| id | name |
+----+---------+
| 1 | actor01 |
| 2 | actor02 |
| 3 | actor03 |
+----+---------+
MOVIES
+----+----------+
| id | title |
+----+----------+
| 1 | movie01 |
| 2 | movie02 |
| 3 | movie03 |
+----+----------+
PLAYING
+----------+----------+-------+------+
| id_movie | id_actor | char | star |
+----------+----------+-------+------+
| 1 | 1 | char1 | 0 |
| 1 | 2 | char2 | 1 |
| 2 | 3 | char3 | 1 |
+----------+----------+-------+------+
I Need output Like:
+----------+--------------+
| actor | protagonist |
+----------+--------------+
| actor01 | 2 times |
| actor02 | 3 times |
+----------+--------------+
You need to fix the group by clause to group by the actor not the star column. You need to fix the order by to group by the aggregated column, not the original column:
SELECT a.id, a.name, sum( p.star = 1) AS stars
FROM actors a join playing p
on p.id_actor = a.id join
movies m
on p.id_movie = m.id
GROUP BY a.id, a.name
ORDER BY stars DESC;
Along the way, I fixed the from so it uses proper join syntax (with an on clause). And changed the query so it returns all actors, even those who have never been the star.
1.If you want to count all stars for an actor, you should group by actor but not stars.(Unless you want to count how many times an actor gets 1 star in a movie, you may not want to group by star)
2.You may want to use ON with JOIN
3.You may want to ORDER BY star but not ORDER BY p.star since you want to order by the result.
4.You may want to use SUM instead of COUNT to get the star counts.(SUM calculates the value but COUNT calculates the number. With SUM, you can set star value to whatever you want without change your sql. You can have star=2 which shows the actor is important to the movie or have star=-1, which means the actor stinks.)
You may have a look at the sql below:
SELECT a.id, a.name, SUM( p.star ) AS sum
FROM actors a
LEFT JOIN playing p ON p.id_actor = a.id
LEFT JOIN movies m ON p.id_movie = m.id
GROUP BY a.id
ORDER BY sum DESC;

Get Max value and corresponding column

How can I get corresponding columns from a max query in mysql? I want find out how many wins a player has. I will find that out by doing a count of the number of games that player has won. The will be done by selecting the max value per game and resulting player_id. However I am not sure how to get the corresponding player_id.
I have
id | game_id | player_id | score
1 | 1 | 1 | 254
2 | 1 | 2 | 194
3 | 2 | 1 | 432
4 | 2 | 2 | 298
This query should get what you need:
SELECT
player_id, game_id, score
FROM
(
SELECT game_id,MAX(score) AS MaxScore
FROM games
GROUP BY game_id
) AS Winners
JOIN games
ON (games.game_id = Winners.game_id AND games.score = Winners.MaxScore)
It assumes that a tie is a win for both players.
SQLFiddle
If you want to get just the player and their number of wins, you can use this query:
SELECT
player_id, COUNT(*) AS wins
FROM
(
SELECT game_id,MAX(score) AS MaxScore
FROM games
GROUP BY game_id
) AS Winners
JOIN games
ON (games.game_id = Winners.game_id AND games.score = Winners.MaxScore)
WHERE player_id = {player_id}
GROUP BY player_id
Just replace {player_id} with the player you're looking for and wins is their number of wins or ties.