I have made a website for a 'walking challenge', which has a table that logs miles walked.
The target is 2105 miles (Newcastle, UK to Istanbul).
On the home page i have a leaderboard which currently shows the 5 teams who have racked up the most miles.
I am using the following query to achive this:
SELECT
SUM(log.distance) AS l,
log.*,
team.*
FROM
team
RIGHT JOIN
log ON team.teamname = log.teamname
GROUP BY
log.teamname
ORDER BY
l DESC
However i want this leaderboard to show the 5 teams that finished first rather than who have walked the furthest. ie, the teams who reached 2105 miles first.
The current website can be viewed here
Add a nullable completedDate field to the table and populate it whenever someone completes the race. Order by the completed date.
There'd be no way to order by who finished first otherwise.
Since you have a timestamp field that gets the current time everytime a team enters the number of miles it has walked, you could do domething like this:
SELECT
SUM(log.distance) AS l,
MAX(log.timestamp) AS t,
log.*,
team.*
FROM
team
RIGHT JOIN
log ON team.teamname = log.teamname
GROUP BY
log.teamname
WHERE
l >= 2105
ORDER BY
t ASC
Keep in mind that this will only work if you don't allow a team to add extra miles after completing the target distance.
If they are able to add extra miles after completing the target, let me know, and i'll try looking for another query
Related
I am trying to make a MySQLi query in PHP to a database that I have full of NHL Players and their projected stats/positions.
This is my query string - my goal is for it to return the top 10 projected goal scorers:
$goalSQL = 'SELECT * FROM players ORDER BY G LIMIT 10';
In my table, G is the column which holds the projected goal count for every player. I also have a column called "Position" which holds the position for every player (G, LW, RW, C, D).
However, I get back an object containing 10 goalies. I am guessing that the SQL is somehow taking my ORDER BY G to mean order by Position:G, but in reality I have no clue what is going wrong.
Any ideas?
Thanks!
If I had to guess, goalies have the lowest projected goal count. Try using desc:
SELECT p.*
FROM players p
ORDER BY p.G DESC
LIMIT 10;
I have a database where the results from a shooter game are stored. I put them to 3NF to allow extensions of the system. So it looks like this:
Player
-------------------
GameId integer
PlayerId integer
TeamId integer
Hits
-------------------
GameId integer
FromId integer
ToId integer
Hits integer
So basically for every game there is a ID and every Player and Team has its ID (with their names stored in other databases)
Now I want to calculate points for each player. I need the points for each game but more importantly the total per player. The points are basically: 3 Points for each hit on opponent, -2 points for each hit of a team member and -2 points for each hit taken.
Alone the calculation of the number of team hits requires a JOIN with 3 tables and I fear for performance in production environment. (Each game has ~8 players-> PlayerDB-Size is 8n and HitsDB-Size is (8-1)^2*n)
And at the end: I need to calculate the points per player for each game and sum those up because the minimum points per game should be zero. And finally get a rank for each player (player x has the 2nd most total points etc)
I feel like I'm getting lost in overly complicated queries that will kill the database' performance at some point.
Could anyone judge the design and maybe give me some pointers where to start looking further? I though about storing the TeamHits and Points per Game in the players Database (Points for summing over them, teamHits for statistical purposes) but that would of course break normalization.
PS: I'm working with PHP 5 and MYSQL. I also thought about getting each game from the database, calculating the points in PHP (which I'm already doing when I show the game) and writing this back (optimally on putting in the game to the DB but also when the parameters for the points change)
Edit: Idea to avoid subselects would be:
SELECT p.*, SUM(h.Hits) AS TeamHits, SUM(h2.Hits) as Hits
FROM player p
LEFT JOIN
(hits h
INNER JOIN player p2
ON h.GameId=p2.GameId AND h.ToId=p2.PlayerId
)
ON p.GameId=p2.GameId AND h.FromId=p.PlayerId AND p.TeamId=p2.TeamId
GROUP BY p.PlayerId, p.GameId
LEFT JOIN hits h2
ON h2.GameId=p.GameId AND h2.FromId=p.PlayerId
But of course this does not work. Is it even possible to combine groupings with joins or will I have to use subqueries?
Best I have is:
SELECT p.PlayerId, SUM((-2-3)*IFNULL(th.TeamHits, 0) + (3)*IFNULL(h.Hits, 0) + (-2)*IFNULL(ht.HitsTaken, 0)) AS Points
FROM player p
LEFT JOIN
(SELECT p.GameId, p.PlayerId, SUM(h.Hits) AS TeamHits
FROM player p
INNER JOIN hits h
ON h.GameId=p.GameId AND p.PlayerId=h.FromId
INNER JOIN player p2
ON p.GameId=p2.GameId AND p2.PlayerId=h.ToId AND p.TeamId=p2.TeamId
GROUP BY p.PlayerId, p.GameId) th
ON p.GameId=th.GameId AND p.PlayerId=th.PlayerId
LEFT JOIN
(SELECT p.GameId, p.PlayerId, SUM(h.Hits) AS Hits
FROM player p
INNER JOIN hits h
ON h.GameId=p.GameId AND p.PlayerId=h.FromId
GROUP BY p.PlayerId, p.GameId) h
ON p.GameId=h.GameId AND p.PlayerId=h.PlayerId
LEFT JOIN
(SELECT p.GameId, p.PlayerId, SUM(h.Hits) AS HitsTaken
FROM player p
INNER JOIN hits h
ON h.GameId=p.GameId AND p.PlayerId=h.ToId
INNER JOIN player p2
ON p.GameId=p2.GameId AND p2.PlayerId=h.FromId AND p.TeamId!=p2.TeamId
GROUP BY p.PlayerId, p.GameId) ht
ON p.GameId=ht.GameId AND p.PlayerId=ht.PlayerId
GROUP BY p.PlayerId
Fiddle: http://sqlfiddle.com/#!9/dc0cb/4
Current problem: For a database with about 10,000 games calculating the points for all players takes about 18s. This is unusable, so I need to improve this...
Joins are not that expensive, subqueries are. as long as you can avoid subqueries you're not hitting too bad.
Remember, a database is built for this stuff these days.
Just make sure you have the proper indexes on the right fields so its optimised. Like teamID and GameID and playerID should be indexes.
Just run it in phpmyadmin and see how many milliseconds it takes to execute. if it takes more than 50 its a heavy query, but usually its pretty hard to hit this... I once managed to make a very heavy query that joined 100.000+ rows out of different tables and views and still did that in 5ms...
What numbers of requests a hour are we talking about? 200 players a day? 200.000 players a day? How often do the requests happen? 10 per second per player? once a minute? how loaded is your database?
I think that all these parameters are low, so you shouldnt worry about this optimisation yet.
Get your game up and running, clean up the php code where real gains can be had, and stay clear of complex subqueries or views.
As long as your table does joins and unions its pretty darn fast. and if you must do a subquery see if there is not an alternative way by using a linking table to link certain results to certain other tables so you can do a join instead of a subquery.
I have a MySQL database where I add soccer games shown on TV. Each team is represented as an number. I can't really figure out how I can make a query to list how many times a team has been shown on TV, no matter if they played at home or away.
I'm trying to make a top 20 list of teams thats been shown on TV. The two columns I have team id in are called "hjemmehold" and "udehold" (it's danish :)).
Anyone can help me here?
SELECT Team, Count(*)
FROM (select Away as Team from Games union all select Home as Team from Games) t
GROUP BY Team
ORDER BY Count(*) Desc
LIMIT 20
SELECT SUM(Away)+SUM(Home) AS NumGames
FROM Games
WHERE Team=#Team
Obviously this is pseudocode, but put the proper tables/fields/params in and you should be good to go.
For all 20 teams:
SELECT TOP 20 Team, SUM(Away)+SUM(Home) AS NumGames
FROM Games
ORDER BY SUM(Away)+SUM(Home) desc
t.his should be able to give you the top 20 teams that have played. This will also allow you to find which teams have not yet played a game (if you remove the top 20 part).
SELECT TOP 20
team_id,
(SELECT COUNT(1) FROM GAMES WHERE HOME = t.team_id) + (SELECT COUNT(1) FROM GAMES WHERE AWAY = team_id) AS team_count
FROM TEAMS T
ORDER BY team_count DESC
I am writing a php script to determine the fuel usage of trucks. I use mysql db table for this.
There are several locations that a truck can get fuel, say A, B, C, D locations.
The truck gets fuel from one of these locations which is the closest. And every time the truck gets fuel, the person responsible will enter "the amount of the fuel" and value of "odometer" to program.
sequence_id locations fuelDispensed odometer
1 C 700 8100
2 A 400 9700
3 B 500 15500
4 C 600 17950
and so on.
With this info from db, It is easy to find how many KMs or miles the truck travelled from a location to another just by calculating "odometer" difference between successive rows by using "sequence_id".
The problem is: People may forget or not be able to enter the values to the program and do it later. the data becomes like this:
sequence_id locations fuelDispensed odometer
1 C 700 8100
2 B 500 15500
3 C 600 17950
4 A 400 9700
In this case, it is not possible to calculate between successive rows based on sequence_id. Maybe, by sorting odometer values ascending and then doing successive calculation between rows seems logical but I could not find out how I can do this.
Edit: My query is something like this:
SELECT
t1.odometer AS km1,
t2.odometer AS km2,
FROM fueldispensed AS t2, fueldispensed AS t1
WHERE (t1.sequence_id+1= t2.sequence_id) AND (t1.truck_id='$truckid') AND (t2.truck_id='$truckid') ORDER BY t1.sequence_id";
adding ORDER BY to this query has no effect since I get the succession on "sequence_id".
Add an ORDER BY to your SQL select statement
ORDER BY odometer ASCENDING
EDIT
OK! I think I understand your problem now.
SELECT t1.truck_id,
t1.odometer AS km1,
MIN(t2.odometer) AS km2
FROM fueldispensed AS t1,
fueldispensed AS t2
WHERE t2.truck_id = t1.truck_id
AND T2.odometer > t1.odometer
ORDER BY t1.truck_id,
t1.odometer
GROUP BY t1.truck_id,
t1.odometer
Should give you something that will work, though not as efficient as it could be
Edit your truck_id selection into the query as appropriate
I've searched the site for similar posts but i found just one where the developer tried to do his calculations (win-lose-draws) with an enormous SQL query. I would like to do the calculations in my controller but don't really know where to start.
I have 2 tables which look like this:
Teams
teamID teamName
Games
gameID matchday homeTeamID awayTeamID homeScore awayScore
Now i'm trying to produce a league ranking out of this match results, But i need some insights on how to look at this...
At the moment, I have a query which selects all the match results and assigns the correct teamID's to the home or away Team like this:
"SELECT g.gameID, g.matchday, g.homeTeamID, g.awayTeamID, g.homeScore, g.awayScore, th.teamName as homeTeam, ta.teamName as awayTeam,
FROM games AS g
INNER JOIN teams as th ON g.homeTeamID = th.teamID
INNER JOIN teams as ta ON g.awayTeamID = ta.teamID
JOIN submenu_teams AS s ON g.submenuID = s.submenuID"
Can anybody try to explain where to go from here to get a nice ranking of the teams according to how many points they won during the season?
Thnx!
I would suggest to keep track of the points in a table (season1) so that every time a page is requested, you don't have to compute the rankings again : you just fetch from the table.
Everytime a new match is played, run a script that adds X point to winner and substracts Y points from loser.
To display, fetch the results and order by score.
You're done !
(was it my post that you read on rankings and SQL ?)