Print the points table of a cricket match using Mysql - mysql

I am trying to solve this question using the join and nested queries. However I am facing issue while printing the final result as there are two rows which are not correctly printed. I am posting below question and the relevant details.
Sql query to fetch the Team name, total number of matches Played by each team, no of match won by the team and no of match lost by the team .
Below is Schema and sample data:
create table cricket(
Match_no int,
Team_a varchar(20),
Team_b varchar(20),
Winner varchar(20)
);
Insert into cricket (Match_no,Team_a,Team_b,Winner) values
(1,'westindies','srilanka' ,'westindies'),
(2 ,'india ','srilanka' ,'india'),
(3 ,'australia' ,'srilanka' ,'australia'),
(4 ,'westindies' ,'srilanka', 'srilanka'),
(5 ,'australia' ,'india' ,'australia'),
(6, 'westindies' ,'srilanka' ,'westindies'),
(7 ,'india' ,'westindies' ,'westindies'),
(8 ,'westindies' ,'australia', 'australia'),
(9 ,'westindies', 'india','india'),
(10,'australia', 'westindies', 'westindies'),
(11 ,'westindies' ,'srilanka' ,'westindies'),
(12 ,'india' ,'australia', 'india'),
(13, 'srilanka' ,'newzealand', 'srilanka'),
(14 ,'newzealand' ,'india', 'india')
I am using below query, but the matches won and lost is not correct for SriLanka and Newzeland in my output.
select team.t as Teamname,count(1)as Played ,
SUM(CASE WHEN team.t = c.Winner THEN 1 ELSE 0 end ) as WON,
(SUM(CASE WHEN team.t <> c.Winner THEN 1 ELSE 0 end ) ) as Lost
from
(select distinct Team_a as t from cricket where Team_a in (
select Team_b as t from cricket)) team
join cricket c on team.t in (c.Team_a,c.Team_b)
group by team.t order by 2 desc;
My output:
Teamname Played WON Lost
westindies 8 5 3
srilanka 7 2 5
india 6 4 2
australia 5 3 2
newzealand 2 0 2
Expected outcome:
Team_name No_of_matches_played Matches_won Matches_lost
westindies 8 5 3
india 6 4 2
australia 5 3 2
srilanka 7 1 6
newzealand 2 1 1
Any help will be highly appreciated.

You can unpivot an aggregate. The idea is:
select team, count(*), count(*), sum(is_win),
count(*) - sum(is_win) as num_losses
from ((select team_a as team,
(team_a = winner) as is_win
from cricket
) union all
(select team_b as team,
(team_b = winner) as is_win
from cricket
)
) c
group by team;
This assumes there are no ties. Your question says nothing about them.

Please try this :
select
t2.team,
t2.played as played ,
COALESCE (t3.won, 0) as won,
(t2.played - COALESCE (t3.won, 0)) as lost
from
(
select sum(cnt) as played, team
from
(
select count(1) as cnt, team_a as team
from cricket
group by team_a
union ALL
select count(1) as cnt, team_b as team
from cricket
group by team_b
) t1
group by team
) t2
left join
(
select count(1) as won, winner
from cricket group by winner
) t3
on t2.team = t3.winner
order by t3.won desc;

Related

Aggregate information from one table to another with a different “layout” (mysql)

this is my starting table which provides sales information by Id.
Id
Store_Name
Market
Sales
Main_Product
1
StoreA
Rome
10
a
2
StoreB
Rome
15
b
3
StoreC
Rome
9
c
4
Mag1
Paris
10
a
5
Mag2
Paris
23
b
6
Mag3
Paris
12
c
7
Shop1
London
11
a
8
Shop2
London
31
b
9
Shop3
London
45
c
10
Shop4
London
63
d
In order to build a report and create some dynamic sentences, I will need the dataset to be "paginated" as per below table:
Id
Dimension
Dimension_Name
Sales
Main_Product
1
ShoppingCentre
StoreA
10
a
1
Market
Rome
34
a
2
ShoppingCentre
StoreB
15
b
2
Maket
Rome
34
b
3
ShoppingCentre
StoreC
9
c
3
Market
Rome
34
c
Do you have any tip about how to build the last table starting from the first one?
To sum-up:
The new table will be always by Id
Aggregation of market sales happens at row level where every single shopping centre is located
This is the query that I have built so far but wondering if there is a better and more efficient way to accomplish the same:
with store_temp_table as (
select
id
,Store_Name
,Market
, Main_Product
, sum(Sales) as Sales
from Production_Table
where 1=1
group by
1,2,3,4
)
, market_temp_table as (
select
market
, sum(Sales) as Sales
from Production_Table
where 1=1
group by
1
)
, store_temp_table_refined as(
Select
a.id
,a.Main_Product
, 'ShoppingCentre' as Dimension_Name
,SUM(a.Sales) as Sales
FROM store_temp_table a INNER JOIN
market_temp_table b on a.market = b.market
group by
1,2,3
)
, market_temp_table_refined as (
Select
a.id
,a.Main_Product
, 'Market' as DimensionName
,SUM(b.Sales) as Sales
FROM store_temp_table a INNER JOIN
market_temp_table b on a.market = b.market
group by
1,2,3
)
select * from store_temp_table_refined
union all
select * from market_temp_table_refined
Thank you
Use a CTE that returns the dimensions that you want and cross join it to a query that returns the columns of the table and an additional column with the total sales of each market:
WITH Dimensions(id, Dimension) AS (VALUES
ROW(1, 'ShoppingCentre'),
ROW(2, 'Market')
)
SELECT p.Id,
d.Dimension,
CASE d.id WHEN 1 THEN p.Store_Name ELSE p.Market END Dimension_Name,
CASE d.id WHEN 1 THEN p.Sales ELSE p.MarketSales END Sales,
p.Main_Product
FROM Dimensions d
CROSS JOIN (SELECT *, SUM(Sales) OVER (PARTITION BY Market) AS MarketSales FROM Production_Table) p
ORDER BY p.id, d.id;
Or, with UNION ALL:
SELECT Id,
'ShoppingCentre' Dimension,
Store_Name Dimension_Name,
Sales,
Main_Product
FROM Production_Table
UNION ALL
SELECT Id,
'Market',
Market,
SUM(Sales) OVER (PARTITION BY Market),
Main_Product
FROM Production_Table
ORDER BY Id,
CASE Dimension WHEN 'ShoppingCentre' THEN 1 WHEN 'Market' THEN 2 END;
See the demo.

Rank standings table of soccer matches by H2H

Let me start explaining this with an example, I have a table with records of matches played in a soccer league, by using this table and its matches results am able to generate a standings table for the teams in this league via a mysql query.
Table [matches] (example)
--------------------------------------------------------
|id | hometeam |goalsfor|goalsagainst| awayteam |
--------------------------------------------------------
--------------------------------------------------------
| 8 | Real Madrid | 2 | 0 | Inter Milan |
--------------------------------------------------------
| 9 | Inter Milan | 3 | 3 | Real Madrid |
--------------------------------------------------------
Generated standings by query
Pos Team Pld W D L F A GD Pts
1 FC Barcelona 5 2 3 0 8 5 3 9
2 Inter Milan 6 2 2 2 11 10 1 8
3 Real Madrid 6 2 2 2 8 8 0 8
4 AC Milan 5 0 3 2 8 12 -4 3
The query:
select
team,
count(*) played,
count(case when goalsfor > goalsagainst then 1 end) wins,
count(case when goalsagainst> goalsfor then 1 end) lost,
count(case when goalsfor = goalsagainst then 1 end) draws,
sum(goalsfor) goalsfor,
sum(goalsagainst) goalsagainst,
sum(goalsfor) - sum(goalsagainst) goal_diff,
sum(
case when goalsfor > goalsagainst then 3 else 0 end
+ case when goalsfor = goalsagainst then 1 else 0 end
) score
from (
select hometeam team, goalsfor, goalsagainst from scores
union all
select awayteam, goalsagainst, goalsfor from scores
) a
group by team
order by score desc, goal_diff desc;
What I want to do is to order the standings based on Head to Head matches, so it would first order by points, then if there's a draw in points the second sorting would be to look at the two teams matches and compare who has more wins, or scored more than the other, then use that to sort the table.
By doing this as in the example Real Madrid will become ranked as 2nd and then Inter Milan as 3rd.
How can I achieve this?
I want to compare the two teams matches when they are equal in points, and use that to sort.
ORDER BY score DESC, h2h DESC; goal_diff DESC
Update: I ended going with a solution mix of sql and php, first I find equaled teams in rank, and then generate mini h2h standings for those team and update the rank based on it. I still see this doable with just sql, but with my heavy query its too complicated to implement with just sql, thats why I mixed with php in the implementation.
You need to process this in two steps. First, run the query above and store the results in a work table (call it work below). Then you need to get a tie breaker score for each team that is on the same score. Below, I join the matches table to the work table for each team, and ignore any where the work rows do not have the same score, as they are not important. Then give the team 1 if they won. Have to do it again for the other side. You might want to change this to the 3 for win, 1 for draw.
Sum these results up, join that result to the team row in work, and you have a tie break score for each row where where the score is the same.
You need to check what happens if you have many teams on the same score, and see if this is the result you want.
select w.*, b.hth
From work w
left outer join (
select team, SUM(hth) hth
from (
Select hometeam team, case when m.goalsfor > m.goalsagainst then 1 else 0 end hth
from matches m
inner join work w1 on m.hometeam = w1.team
inner join work w2 on m.awayteam = w2.team
where w1.score = w2.score
union all
Select awayteam team, case when m.goalsAgainst > m.goalsFor then 1 else 0 end hth
from matches m
inner join work w1 on m.hometeam = w1.team
inner join work w2 on m.awayteam = w2.team
where w1.score = w2.score
) a --all hth at same points
group by team
) b --summed to one row per team
on b.team = w.team
order by w.score desc, b.hth desc;

Sum query for collection

I have two tables:
Fixture (id, homeId, awayId...)
FixtureStats(id,playerId, teamOwnerId, rating, goals)
I want to show both sum of goals for each players and team goals in which the player belongs to.
PlayerId TeamOwnerId Goals TeamGoals
1 2 0 9
2 2 1 9
3 2 3 9
4 2 5 9
5 3 0 12
....
The sql query below still lacks the teamgoals
SELECT TOP (100)
PERCENT fs.teamownerid,
fs.playerid,
Count(f.id) AS Apps,
Sum(fs.goal) AS Goals
FROM dbo.fixturestats AS fs
INNER JOIN dbo.fixture AS f ON fs.fixtureid = f.id
WHERE ( fs.rating > 0 )
GROUP BY fs.playerid, fs.teamownerid
Try this :
SELECT
X.playerid,
X.teamownerid,
X.goals,
( SELECT Sum(goal)
FROM fixturestats
WHERE X.teamownerid = teamownerid
) AS TeamGoals
FROM (
SELECT
TOP (100) PERCENT fs.teamownerid AS TeamOwnerId,
fs.playerid AS PlayerId,
Count(f.id) AS Apps,
Sum(fs.goal) AS Goals
FROM dbo.fixturestats AS fs
INNER JOIN dbo.fixture AS f ON fs.fixtureid = f.id
WHERE ( fs.rating > 0 )
GROUP BY fs.playerid,fs.teamownerid
) AS X
you can use Sum-Over for this :
select
*,
Sum(Goals) over (partition by TeamOwnerId)
from
FixtureStats
where
(Rating > 0)

MySQL Joining two queries for sports team

I am trying to display a list of teams with the number of goals they have scored (and order them by greatest to smallest) but am having trouble with joining all the queries together
Table 1: Teams
teamid teamname
1 team1
2 team2
3 team3
Table 2: Results
id gameid teamid gf
1 1 1 5
2 2 1 3
3 1 2 0
4 2 2 2
5 3 3 0
What I'm trying to achieve
1. Team1 8
2. Team2 2
3. Team3 0
Get list of all teams
SELECT team.teamid, team.teamname
FROM teams team
Gets sum of goals for 1 team
SELECT COALESCE( SUM( gf ) , 0 ) goalsfor
FROM results
WHERE teamid = 1
Joining of queries
SELECT team.teamid,
team.teamname,
COALESCE(res.gf, 0) goalsfor
FROM teams team
LEFT JOIN
(SELECT COALESCE(SUM(res.gf), 0) goalsfor
FROM results res
GROUP BY teamid) res ON team.teamid = res.teamid
ORDER BY goalsfor DESC
Been stuck on joining the queries all day
SELECT teams.teamname, res.goals FROM teams JOIN (
SELECT COALESCE(SUM(results.gf),0) AS goals, results.teamid AS teamid FROM results
group by results.teamid) res
ON teams.teamid=res.teamid ORDER BY goals DESC;
My solution is:
SELECT t.id,
t.name,
SUM(r.gf) goalsfor
FROM team t
LEFT JOIN
results r ON t.id = r.teamId
GROUP BY t.id
ORDER BY goalsfor DESC
My result from my dummy table:
id name goalsfor
1 Apple 8
2 Banana 2
3 Carrot 0
I don't think you need COALESCE if you made your columns have a default of 0 and cannot be null.

How to resolve this problem with aggregates and UNION in MySQL?

If my data is this
match homeTeam awayTeam homeTeamID awayTeamID homePoints awayPoints
1 Alpha Beta 1 2 4 2
2 Gamma Delta 3 4 6 0
3 Alpha Gamma 1 3 2 4
4 Delta Beta 4 2 3 3
I need to make a ladder for them but I can't get it just right
The results should look like this
Name played Points
Gamma 2 10
Alpha 2 6
Beta 2 5
Delta 2 3
So far my code looks like this
$query = "SELECT *
FROM (
SELECT homeTeam AS teamName,
COUNT(homeTeamID) AS matches_played,
SUM(if(homeTeamID, homePoints, 0)) AS total_points
FROM matches
UNION ALL SELECT awayTeam AS teamName,
COUNT(awayTeamID) AS matches_played,
SUM(if(awayTeamID, awayPoints, 0)) AS total_points
FROM matches
) all_points
GROUP BY teamName
ORDER BY total_points DESC ";
but all it did was show ALPHA played 4 games for 15 points and BETA played 4 games for 9 points - Gamma & Delta were gone :(
You do not have GROUP BY clause in inner query.
But it's still incorrect. try:
SELECT teamName, COUNT(*) AS played, SUM(points) as points
FROM (
SELECT homeTeam AS teamName,
homePoints AS points
FROM matches
UNION ALL SELECT awayTeam AS teamName,
awayPoints AS points
FROM matches
) all_points
GROUP BY teamName
ORDER BY total_points DESC