MySQL - Column to Row - mysql

In the original problem, we have a table that stores the date and win/loss information for each game played by a team.
the matches table
We can use the following SQL statements to get information about the number of games won and lost for each day.
SELECT match_date AS match_date,
SUM(IF(result = 'win',1,0)) AS win,
SUM(IF(result = 'lose',1,0)) AS lose
FROM matches
GROUP BY date;
We store the query results in the matches_2 table.the matches_2 table
My question is, how can we get the matches table based on the matches_2 table with a query?
In the simpler case, we can achieve the task of 'column to row' using union/union all. But that doesn't seem to work in this problem.
All relevant sql code can be found in the following fiddle:
https://dbfiddle.uk/rM-4Y_YN

You can use recursive CTE for this:
WITH RECURSIVE wins (mdate, w) AS
(
SELECT match_date as mdate, 1
FROM matches
WHERE win>0
UNION ALL
SELECT match_date, w + 1 FROM matches
JOIN wins on match_date=mdate
WHERE w < win
),
losses (mdate, l) AS
(
SELECT match_date as mdate, 1
FROM matches
WHERE lose>0
UNION ALL
SELECT match_date, l + 1 FROM matches
JOIN losses on match_date=mdate
WHERE l < lose
)
SELECT mdate as match_date, 'lose' FROM losses
UNION ALL
SELECT mdate as match_date, 'win' FROM wins
See a db-fiddle

Related

How to get the sum of country values and have them only appear once

I have my current sql query which I will later convert to a HIVE query.
SELECT home_team, COUNT(home_team)
from results
WHERE results.home_score < results.away_score
GROUP BY home_team
UNION
SELECT away_team, COUNT(away_team)
FROM results
WHERE results.away_score < results.home_score
GROUP BY away_team
And it currently returns two occurrences of a country, once as a home_team and once as an away_team. Current results
How can I modify this query so it adds the count(home_team) and makes the country only appear once? Ex. Argentina : 50
I've tried to put both select queries in brackets and then count the sum being returned but I seem to always get an error when I do order by.
This should resolve your issue
-- Create a temporary table
WITH counted AS (
SELECT home_team, COUNT(home_team) AS row_nb FROM results WHERE results.home_score < results.away_score GROUP BY home_team
UNION
SELECT away_team, COUNT(away_team) FROM results WHERE results.away_score < results.home_score GROUP BY away_team
)
-- And then sum the row_nb
SELECT home_team, SUM(row_nb) FROM counted;
After unioning the results, aggregate by team and add up the lost games with SUM.
And you must use UNION ALL instead of UNION [DISTINCT]. Otherwise, for a team that lost five games at home and five games away, five games will only counted once instead of twice. (I.e. the team will be shown with five lost games instead of with the ten games they really lost.)
Remember: UNION removes duplicates and is very seldom needed. UNION ALL is used more often.
SELECT team, SUM(lost) AS lost_games
FROM
(
SELECT home_team AS team, COUNT(*) AS lost
FROM results
WHERE home_score < away_score
GROUP BY home_team
UNION ALL
SELECT away_team AS team, COUNT(*) AS lost
FROM results
WHERE away_score < home_score
GROUP BY away_team
)
GROUP BY team
ORDER BY team;

How to return 0 value in SQL query?

How many (sum) goals were scored by each footballer in a given tournament in ascending order.
For those footballers with 0 goals, we should return name of the footballer with value 0. Point being, footballers with 0 goals should also be part of output.
Footballer name | Goal | Tournament
Messi | 3 | La liga
Ronaldo | 5 | UEFA
Suarez | 2 | La liga
Output should be for 'La Liga' output should be:
Ronaldo 0
Suarez 2
Messi 3
Try this
select footballer, sum(goals)
from (
select footballer, CASE
WHEN tournament = 'LA_LIGA' THEN goals
else 0
END
from tableA) AS tabA
group by footballer
Hope it help.
I'm not sure what's the structure of your database, I think normally the score is rewarded to a team instead of individuals. Anyway, here is just the concept:
Tables:
Players = {playerID, name, age, gender, height, etc..}
Games = {gameID, playerID, score...}
Tournaments = {tournamentID, gameID, tournamentName...}
select p.name, IFNULL(g.score,0), t.tournamentName
from players p
left join Games g on p.playerID = g.playerID
left join Tournaments t on g.GameID = t.GameID
where t.tournamentName = 'La liga'
Solution:
My point is you may need to use IFNULL(..) and set the default value to 0.
try this....
Select FootballerName,
sum(CASE WHEN tournament = 'LA LIGA' THEN Goal else 0 END) as Goal
from #Matches group by FootballerName
want to get all goals by players in all tournament
Select FootballerName, sum(Goal) as Goal
from #Matches group by FootballerName
want to know goals touranmentwise
Select FootballerName, sum(Goal) as Goal,Tournament
from #Matches group by FootballerName,Tournament
Source Of Information: Pivot query help us to generate an interactive table that quickly combines and compares large amounts of data. We can rotate its rows and columns to see different summaries of the source data, and we can display the details for areas of interest at a glance. It also help us to generate Multidimensional reporting.
Create Table script
Create table Matches(FootballerName varchar(100),Goal int ,Tournament varchar(100))
Sql Server Insert Records script
insert into Matches(FootballerName,Goal,Tournament)
select 'Messi ', 3 ,'La liga' union
select 'Ronaldo ', 5 ,'UEFA' union
select 'Surez ', 2 ,'La liga'
MySql Server script
Create table Matches(FootballerName varchar(100),Goal int ,Tournament varchar(100));
insert into Matches(FootballerName,Goal,Tournament)
select 'Messi ', 3 ,'La liga' union
select 'Ronaldo ', 5 ,'UEFA' union
select 'Surez ', 2 ,'La liga';
MYSQL Version
Select FootBallerName,
Sum(CASE WHEN Tournament= 'La liga' THEN goal ELSE 0 END) AS 'La liga',
Sum(CASE WHEN Tournament= 'UEFA' THEN goal ELSE 0 END) AS 'UEFA'from Matches
group by FootBallerName order by FootBallerName;
SQL Server Query using Pivot --- for Only [La liga]
SELECT FootballerName,isnull([La liga],0) as'La liga'
FROM (
SELECT
FootballerName ,isnull(goal,0) as'goal',
Tournament
FROM Matches
) as s
PIVOT
(
SUM(goal)
FOR Tournament IN ([La liga],[UEFA])
)AS pvt order by [La liga]
SQL Server Query using Pivot --- Only [La liga] and [UEFA]
SELECT FootballerName,isnull([La liga],0) as'La liga',isnull([UEFA],0) as'UEFA'
FROM (
SELECT
FootballerName ,isnull(goal,0) as'goal',
Tournament
FROM Matches
) as s
PIVOT
(
SUM(goal)
FOR Tournament IN ([La liga],[UEFA])
)AS pvt order by [La liga],[UEFA]
You can read more [https://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx]
Unless you have 3 tables (players, tournaments, and goals) you'll need to create 3 sets using subselects and join them together. You need the cross-product of all tournaments and all footballers.
SELECT footballer_name, tournament FROM
(SELECT DISTINCT footballer_name FROM your_table) AS players
JOIN
(SELECT DISTINCT tournament FROM your_table) AS tournaments
The above should get you one record per unique pairing of footballer and tournament. See if you can get this working in your database and then finish it off with a final join for scores

MYSQL For/While Loop

Is it possible to do a For or While loop in MYSQL?
I've got the following code extract, but the full code goes up to home_id_15, home_score_15, away_id_15 and away_score_15:
$query3 = '
SELECT match_date, fixture_id, COUNT(a.home) AS home, SUM(a.points) AS points FROM
(
SELECT match_date, fixture_id, home_id_1 AS home, home_score_1 AS points FROM scores
WHERE home_id_1 =' .intval($_REQUEST['ID']).'
UNION ALL
SELECT match_date, fixture_id, away_id_1 AS home, away_score_1 AS points
FROM scores
WHERE away_id_1 =' .intval($_REQUEST['ID']).'
UNION ALL
SELECT match_date, fixture_id, home_id_2 AS home, home_score_2 AS points
FROM scores
WHERE home_id_2 =' .intval($_REQUEST['ID']).'
UNION ALL
SELECT match_date, fixture_id, away_id_2 AS home, away_score_2 AS points
FROM scores
WHERE away_id_2 =' .intval($_REQUEST['ID']).'
UNION ALL) a
GROUP BY match_date'
The first and second sub-SELECTS are basically being repeated until they reach 15.
This seems a bit long-winded and I was wondering if it's possible to use a loop in MYSQL to output
home_id_1, home_score_1, away_id_1, away_score_1 [up to] home_id_15, home_score_15, away_id_15, away_score_15
, respectively?
Thanks,
Dan.
It looks like you might need to normalize your database a little bit more. Let's say you had 6 scores for each row. Instead of making each score a column, make a separate table called "scores" or something like that with a foreign key column and a score column. Then join the table with this scores table.
Example:
TABLE: team
team_id
name
TABLE: scores
team_id
score
SELECT t.*, s.score
FROM team t
join scores s
on t.team_id=s.team_id;
Todo: Add the concept of matches into your schema and the Join

Group by in mysql [some stuff to foo the bot]

I have this query:
SELECT *,
COUNT(*) AS SeasonP,
SUM(Goals) AS SeasonG,
SUM(Disposals) AS SeasonD,
SUM(Kicks) AS SeasonK,
SUM(Handballs) AS SeasonHB,
SUM(Marks) AS SeasonM,
SUM(Behinds) AS SeasonB,
SUM(Tackles) AS SeasonT,
SUM(HitOuts) AS SeasonHO,
SUM(I50) AS SeasonI50,
((SELECT COUNT(*) FROM `PlayerDetails` WHERE PlayerID = $PlayerID AND WL LIKE '%W%' )) AS W,
((SELECT COUNT(*) FROM `PlayerDetails` WHERE PlayerID = $PlayerID AND WL LIKE '%L%' )) AS L,
((SELECT COUNT(*) FROM `PlayerDetails` WHERE PlayerID = $PlayerID AND WL='D' )) AS D
FROM `PlayerDetails` WHERE PlayerID = $PlayerID GROUP BY Season, Team, League
Which almost gives me the correct output - It correctly totals games, goals, kicks, marks etc per season. But what I'm trying to do is display the games won, lost and drawn for each season and for each team. So for eg. 2015 should read Won=12, Lost 5 so just adding the wins and losses for that season but it's displaying the total won/lost for all 32 games his played rather than breaking it down per season.
I'm sure its an easy fix to my query but I'm a bit stuck.
Instead of your sub-queries populating W,L,D, use mysql IF() function as described below,
SELECT *, COUNT(*) AS `SeasonP`, SUM(`Goals`) AS `SeasonG`, SUM(`Disposals`) AS `SeasonD`,
SUM(`Kicks`) AS `SeasonK`, SUM(`Handballs`) AS `SeasonHB`, SUM(`Marks`) AS `SeasonM`,
SUM(`Behinds`) AS `SeasonB`, SUM(`Tackles`) AS `SeasonT`, SUM(`HitOuts`) AS `SeasonHO`,
SUM(`I50`) AS `SeasonI50`,
SUM(IF(`WL` LIKE '%W%', 1, 0)) AS `W`,
SUM(IF(`WL` LIKE '%L%', 1, 0)) AS `L`,
SUM(IF(`WL` = 'D', 1, 0)) AS `D`,
FROM `PlayerDetails` WHERE `PlayerID` = $PlayerID GROUP BY `Season`, `Team`, `League`
The root of all evil is this one:
((SELECT COUNT(*) FROM `PlayerDetails` WHERE PlayerID = $PlayerID AND WL='...' ))
First of all, you should avoid a SELECT as a value at all, it causes severe performance issues, since it has to be executed for every row in your result - and this may get biiiiig.
In your case, there's no filter condition in the subquery - you always ask "how many games were won EVER", that's why you always get the total value. Your group-by gets skipped this way.
Since you already work with the wanted table "PlayerDetails", try to replace it with this:
sum(if(WL='W',1,0)) AS W,
sum(if(WL='D',1,0)) AS D,
sum(if(WL='L',1,0)) AS L
Think of it as a counter. For each row it checks the condition and - depending on the result - adds 1 or 0.

Average on a count() in same query

I'm currently working on an assignment which requires me to find the average on the number of resources for each module. The current table looks like this:
ResourceID ModulID
1 1
2 7
3 2
4 4
5 1
6 1
So basically, I'm trying to figure out how to get the average number of resources. The only
relevant test data here is for module 1, which has 3 different resources connected to it. But I need to display all of the results.
This is my code:
select avg(a.ress) GjSnitt, modulID
from
(select count(ressursID) as ress
from ressursertiloppgave
group by modulID) as a, ressursertiloppgave r
group by modulID;
Obviously it isn't working, but I'm currently at loss on what to change at this point. I would really appreciate any input you guys have.
This is the query you are executing, written in a slightly less obtuse syntax.
SELECT
avg(a.ress) as GjSnitt
, modulID
FROM
(SELECT COUNT(ressursID) as ress
FROM ressursertiloppgave
GROUP BY modulID) as a
CROSS JOIN ressursertiloppgave r <--- Cross join are very very rare!
GROUP BY modulID;
You are cross joining the table, making (6x6=) 36 rows in total and condensing this down to 4, but because the total count is 36, the outcome is wrong.
This is why you should never use implicit joins.
Rewrite the query to:
SELECT AVG(a.rcount) FROM
(select count(*) as rcount
FROM ressursertiloppgave r
GROUP BY r.ModulID) a
If you want the individual rowcount and the average at the bottom do:
SELECT r1.ModulID, count(*) as rcount
FROM ressursertiloppgave r1
GROUP BY r1.ModulID
UNION ALL
SELECT 'avg = ', AVG(a.rcount) FROM
(select count(*) as rcount
FROM ressursertiloppgave r2
GROUP BY r2.ModulID) a
I got the solution
SELECT AVG(counter)
FROM
(
SELECT COUNT(column to count) AS counter FROM table
) AS counter
Note that the nickname {counter} was added in SELECT COUNT and at the end of the inner SELECT