So I have aggregation table (Players_Tournaments) of two others table: Players and Tournament. In aggregation table I save points for each player and each tournament. Tournaments have also relationship with table Season which defined in which Season was Tournament (etc. 2020, 2019...).
I want to delete rows from Player_Tournaments which are zeroes. But I want to delete only rows when they are grouped by Season in SUM gives zeroes. Becaues when I entering points for players in each tournament i get list of all my players and if they dont play they automaticly get 0 points. The main reason why I want to do this because many player didn't play all season and I want to delete those records.
I hope that was enough detailed.
EDIT:
Players_Tournaments: Player_id, Tournament_id, Points
Player: id, name...
Tournament: id, name, season_id...
Season: id, year
If you just want to remove the rows from a result set, you would use a HAVING clause:
HAVING SUM(points) <> 0
Related
I currently have the following three tables in a football db:
teams(name)
season(name, beginning, end)
game(id, Date, season, hometeam, awayteam, HomeTeamScore, AwayTeamScore)
(hometeam, awayteam and season are foreign keys)
Now I'd like to have a new table where I keep track about the goals scored and conceded from every team, as well as their points (one for each draw and three for each win) in every season. This would make it possible to easily get rankings.
I have thought about making a table like this:
stats(season, team, goalsscored, goalsconcedded, points)
Then I would also update it every time a new game is inserted. This table would contain one row for each team+season combination. I am not sure this is the best solution, since I know I am introducing a redundancy, but since this information needs to be calculated often I think it might be useful. I'd like to create a trigger where this information is updated, but do not really know how to do this: I would have to update two rows in the stats table depending on which teams are playing that game, and depending on the fact that they are playing home or away I need to update those with different values.
Ideally, this trigger should create an entry in this new table if the team has not yet been inserted for the season the game is referring to, but I am not even sure such conditions are possible in MySQL.
I know I have not provided any test I have done, but this is because I really can't find similar requests online (or more generally to be able to query the information requested easily).
Also, I am open to better ideas of how to deal with this situation.
Much easier than maintaining redundant data with triggers is to just have a view; this is just a basic sum of a union:
create view stats as (
select season, team, sum(goalsscored) goalsscored, sum(goalsconcedded) goalsconcedded, sum(points) points
from (
select season, hometeam team, HomeTeamScore goalsscored, AwayTeamScore goalsconcedded,
case when HomeTeamScore > AwayTeamScore then 3 when HomeTeamScore=AwayTeamScore then 1 else 0 end points
from game
union all
select season, awayteam team, AwayTeamScore goalsscored, HomeTeamScore goalsconcedded,
case when AwayTeamScore > HomeTeamScore then 3 when AwayTeamScore=HomeTeamScore then 1 else 0 end points
from game
) games
group by season, team
);
I think you should consider something like this:
Teams(id,name)
Seasons(id, year,begin_date,end_date)
Games(id, date, season (foreign key), hometeam (foreign key), awayteam (foreign key), HomeTeamScore, AwayTeamScore)
This is also sub-optimal.
In my humble opinion you could do better like this
Teams(id,name)
Seasons(id, year,begin_date,end_date)
Matches(id, date, season (foreign key), home_team (foreign key), away_team (foreign key))
Goals(id,team,game,player?)
Goal table will be used to register every goal and then you can construct the match results from there avoiding "HomeTeamScore" and "AwayTeamScore" fields.
As for Stats table you need to know who won the points so let's stick to our last table set:
Teams(id,name)
Seasons(id, year,begin_date,end_date)
Matches(id, date, season (foreign key), home_team (foreign key), away_team (foreign key), status)
Goals(id,team,game,player?)
Status field value in Matches can be: ['1','X','2']
1 - Home team winning
X - Tie match
2 - Away team winning
This way you can easily have everything to calculate your stats with, for example for a team having 12 as ID:
Select * from Matches where home_team = 12 and result = '1';
Select * from Matches where away_team = 12 and result = '2';
Select * from Matches where home_team = 12 or away_team=12 and result='X';
You can use this as a starting point to build a slightly more complex query using group by and group functions to calculate team stats.
Once you managed to create a query like this I suggest to use a view
By the way these you want to perform are not heavy queries and you don't necessarily need triggers, just think about good database design first!
I'm working with a database of football games with corresponding dates, locations, a home team, away team, and venue. The games table has keys that representing each of the aforementioned values. I'm currently trying to display each location with with its respective id along with the number of times that it appears throughout the games database as shown below. I coded it like this but for some reason its only displaying one venue and id with a count of the total number instances instead of each individual instance and I can't figure out why.
I'm new to MySQL so I apologize for any mistakes.
SELECT id, venue, count(games.location_id) AS game_count
FROM locations
JOIN games
ON locations.id=games.location_id
you need to add group by as you'are using aggregate function
SELECT venue, count(games.location_id) AS game_count
FROM locations
JOIN games
ON locations.id=games.location_id
group by venue
I have project to analyze premier league stats 2011/12 and I wanna operate on one column (scored goals) when playerd from start(1) or substituted(0) and I wanna show name,surname and sum of scored goal when player started game and substituted. which looks like this only for score at home:
and I wanna make this looks like this
I know that this subquery is wrong because it summing all goals not by the player.
How to make it looks separate like for van persie 28 scored from start(1) and from bench (0) supposed to be 2?
erd diagram if you wanna see:
https://postimg.org/image/u46b6lve3/
Your sub query counts all the goals because you are not passing player id to it, try changing the query to the following:
select player_id as pid, //other columns
select sum(goals) from projekt.statictics where starts = 0 and player_id = pid) as wyjazd
from //conditions
You may need to change the column names based on what they are named in the tables.
I have two tables, one named scores and one named dem0n123.
I am trying to take the AVG of all of the kills in the section of the demon123 table and insert that value into the AverageKills section of scores but only where the Player section of scores equals dem0n123.
I have tried a multitude of different ways and have yet to find anything that works.
* edit *
Better explanation, there are two tables:
-scores
-dem0n123
inside scores there are individual players and there average scores (Average Kills/Deaths/Assists... etc)
inside dem0n123 there are game scores (kills/deaths/assists... etc)
so taking from the dem0n123 table, I need the average of all his kills and then insert that value into the scores table "AverageKills" value
hope that is a better explanation
If I'm guessing what you mean correctly, I think you want this:
UPDATE scores AS s
JOIN (SELECT Player, AVG(kills) AS avkills
FROM dem0n123
GROUP BY Player) AS d
ON s.Player = d.Player
SET s.AverageKills = d.avkills
DEMO
You will need to perform a function on the column. The function you would like is AVG. For example
Select AVG(kills) from scores
Then after that you will want to insert into your other table.
insert into dem0n123(average)
select AVG(kills) from scores
I have 3 tables in this scenario: Teams, Players and PlayersInTeams.
A Player is just a registered user. No W/L data is associated with a Player.
A Team maintains win/loss records. If a player is playing by himself, then he plays with his "solo" team (a Team with only that Player in it). Every time Bob and Jan win together, their Team entry gets wins++. Every time Jason and Tommy lose together, their Team entry gets losses++.
The PlayersInTeams table only has 2 columns, and it's an intersection table between Players and Teams:
> desc PlayersInTeams ;
+------------+---------+
| Field | Type |
+------------+---------+
| fkPlayerId | int(11) |
| fkTeamId | int(11) |
+------------+---------+
So here is the tough part:
Because a Player can be part of multiple Teams, it is important to fetch the right TeamId from the Teams table at the beginning of a match.
A Player's SOLO team is given by
select fkTeamId from PlayersInTeams where
fkPlayerId=1 HAVING count(fkTeamId)=1;
NO IT'S NOT!! But I don't understand why.
I'm trying to say:
Get the fkTeamId from PlayersInTeams where
the fkPlayerId=1, but also, the count of rows
that have this particular fkTeamId is exactly 1.
The query returns (empty set), and actually if I change the HAVING clause to being incorrect (HAVING count(fkTeamId)<>1;), it returns the row I want.
To fix your query, add a group by. To compute the count per team, you'll need to change the where clause to return all teams that player 1 is on:
select fkTeamId
from PlayersInTeams
where fkTeamId in
(
select fkTeamId
from PlayersInTeams
where fkPlayerId = 1
)
group by
fkTeamId
having count(*) = 1;
Example at SQL Fiddle.
Below a detailed explanation of why your count(*) = 1 condition works in a surprising way. When a query contains an aggregate like count, but there is no group by clause, the database will treat the entire result set as a single group.
In databases other than MySQL, you could not select a column that is not in a group by without an aggregate. In MySQL, all those columns are returned with the first value encountered by the database (essentially a random value from the group.)
For example:
create table YourTable (player int, team int);
insert YourTable values (1,1), (1,2), (2,2);
select player
, team
, count(team)
from YourTable
where player = 2
-->
player team count(team)
1 1 1
The first two columns come from a random row with player = 1. The count(team) value is 2, because there are two rows with player = 1 and a non-null team. The count says nothing about the number of players in the team.
The most natural thing to do is to count the rows to see what is going on:
select fkTeamId, count(*)
from PlayersInTeams
where fkPlayerId=1
group by fkTeamId;
The group by clause is a more natural way to write the query:
select fkTeamId
from PlayersInTeams
where fkPlayerId=1
having count(fkteamid) = 1
However, if there is only one row for a player, then your original version should work -- the filtering would take it to one row, the fkTeamId would be the team on the row and the having would be satisfied. One possibility is that you have duplicate rows in the data.
If duplicates are a problem, you can do this:
select fkTeamId
from PlayersInTeams
where fkPlayerId=1
having count(distinct fkteamid) = 1
EDIT for "solo team":
As pointed out by Andomar, the definition of solo team is not quite what I expected. It is a player being the only player on the team. So, to get the list of teams where a given player is the team:
select fkTeamId
from PlayersInTeams
group by fkTeamId
having sum(fkPlayerId <> 1) = 0
That is, you cannot filter out the other players and expect to get this information. You specifically need them, to be sure they are not on the team.
If you wanted to get all solo teams:
select fkTeamId
from PlayersInTeams
group by fkTeamId
having count(*) = 1
HAVING is usually used with a GROUP BY statement - it's like a WHERE which gets applied to the grouped data.
SELECT fkTeamId
FROM PlayersInTeams
WHERE fkPlayerId = 1
GROUP BY fkTeamId
HAVING COUNT(fkPlayerId) = 1
SqlFiddle here: http://sqlfiddle.com/#!2/36530/21
Try finding teams with one player first, then using that to find the player id if they are in any of those teams:
select DISTINCT PlayersInTeams.fkTeamId
from (
select fkTeamId
from PlayersInTeams
GROUP BY fkTeamId
HAVING count(fkPlayerId)=1
) AS Sub
INNER JOIN PlayersInTeams
ON PlayersInTeams.fkTeamId = Sub.fkTeamId
WHERE PlayersInTeams.fkPlayerId = 1;
Everybody's answers here were very helpful. Besides missing GROUP BY, I found that my problem was mainly that my WHERE clause was "too early".
Say we had
insert into PlayersInTeams values
(1, 1), -- player 1 is in solo team id=1
(1, 2),(2,2) -- player 1&2 are on duo team id=2
;
Now we try:
select fkTeamId from PlayersInTeams
where fkPlayerId=1 -- X kills off data we need
group by fkTeamId
HAVING count(fkTeamId)=1;
In particular the WHERE was filtering the temporary resultset so that any row that didn't have fkPlayerId=1 was being cut out of the result set. Since each fkPlayerId is associated with each fkTeamId only once, of course the COUNT of the number of occurrences by fkTeamId is always 1. So you always get back just a list of the teams player 1 is part of, but you still don't know his SOLO team.
Gordon's answer with my addendum
select fkPlayerId,fkTeamId
from PlayersInTeams
group by fkTeamId
having count(fkTeamId) = 1
and fkPlayerId=1 ;
Was particularly good because it's a cheap query and does what we want. It chooses all the SOLO teams first, (chooses all fkTeamIds that only occur ONCE in the table (via HAVING count(*)=1)), then from there we go and say, "ok, now just give me the one that has this fkPlayerId=1". And voila, the solo team.
DUO teams were harder, but similar. The difficulty was similar to the problem above only with ambiguity from teams of 3 with teams of 2. Details in an SQL Fiddle.