I am writing a hockey stat database. I have the need to calculate how many players were on the ice when a goal is scored.
I have set up the following sqlfiddle:
http://sqlfiddle.com/#!9/ed8fa
problem I am having is how to filter the results such that only goals that are scored at regular strength (shot type "reg") or goals that are scored while shorthanded (shot type "sh") count towards this total.
I need all players to be listed in the output, even if their number is zero. After finding the players "Plus rating", I will calculate each players "minus rating" and subtract the two. Once I figure out how to accurately find the "Plus rating", I should be able to figure out how to do the rest.
For the given data in the sqlfiddle, the desired output should be:
player_id Plus_count
20 1
21 0
22 2
23 1
24 1
25 0
26 1
27 1
28 1
29 0
30 0
31 2
32 1
33 0
I am having trouble figuring out how the join would work such that I can use where to filter out all goals that are "pp".
Thanks for any pointers you might be able to give...
adding what I have tried. This is from my dev db, so just slightly different from the sqlfiddle:
SELECT players.player_id as pp_id,
COALESCE(plus_players.count, 0) as Plus_Count
FROM players
LEFT JOIN (SELECT plus_players.fk_player_id, COUNT(*) as count
FROM plus_players
GROUP BY plus_players.fk_player_id) plus_players
ON plus_players.fk_player_id = players.player_id
left join (select * from shots_for
where regular_powerplay_shorthanded = 'reg' or regular_powerplay_shorthanded = 'sh') sf on sf.fk_player_id = players.player_id
union
SELECT players.player_id as pp_id,
COALESCE(plus_players.count, 0) as Plus_Count
FROM players
LEFT JOIN (SELECT plus_players.fk_player_id, COUNT(*) as count
FROM plus_players
GROUP BY plus_players.fk_player_id) plus_players
ON plus_players.fk_player_id = players.player_id
right join (select * from shots_for
where regular_powerplay_shorthanded = 'reg' or regular_powerplay_shorthanded = 'sh') sf2 on sf2.fk_player_id = players.player_id
left join goals_for on goals_for.fk_shot_for_id = sf2.shot_for_id
where regular_powerplay_shorthanded = 'reg' or regular_powerplay_shorthanded = 'sh'
you can see my various attempts above to use the where to eliminate the "pp" goals.
Related
I currently have a list of all games played by team in which the list produces the team name, score, opponent name and score and either a W (Won), L (Lost) or D (Draw) which are all derived from my table "MatchDetails2017". What I want to do is display the cumulative win percentage after each game.
I have spent a few hours trying to find help online and have hit a brick wall.
SELECT Game, WL, ((SELECT COUNT(WL) FROM MatchDetails2017 WHERE Team = 'TeamName' AND WL = 'W')/COUNT(*))*100
FROM MatchDetails2017
WHERE Team = 'TeamName'
GROUP BY Game
For example I want the data to display like this...
Game|Result|Win%
1|W|100.00
2|W|100.00
3|W|100.00
4|L|75.00
5|D|60.00
6|W|66.67
This is my results I am currently getting...
1 W 5200.0000
2 W 5200.0000
3 W 5200.0000
4 L 5200.0000
5 D 5200.0000
6 W 5200.0000
To make this work the COUNT(*) to compute total games also needs to be over only the preceding games, so you need to bring it into your subquery. You also need to restrict the subquery to only games including and preceding the current one:
SELECT Game,
WL AS Result,
(SELECT SUM(WL = 'W') / COUNT(*) FROM MatchDetails2017 m2 WHERE m2.Game <= m1.Game AND m2.Team = m1.Team) * 100 AS `Win%`
FROM MatchDetails2017 m1
WHERE Team = 'TeamName'
Output:
Game Result Win%
1 W 100
2 W 100
3 W 100
4 L 75
5 D 60
6 W 66.6667
Demo on dbfiddle
Note that this query takes advantage of the fact that MySQL treats boolean values as either 1 or 0 in a numeric context, so we can SUM(WL = 'W') to get the total number of wins.
In MySQL 8+ we can try using COUNT as an analytic function:
SELECT
TeamID,
Game,
WL,
COUNT(CASE WHEN WL = 'W' THEN 1 END) OVER (PARTITION BY TeamId ORDER BY Game) /
COUNT(*) OVER (PARTITION BY TeamId) win_pct
FROM MatchDetails2017
ORDER BY
TeamID,
Game;
I have a query:
SELECT p.NAME, r.DATE, c.NAME, SUM(hs.result), SUM(h.par), (SUM(hs.result) - SUM(h.par)) AS "Score"
FROM hole_scores hs
JOIN players p ON hs.player_id = p.id
JOIN rounds r ON r.id = hs.session_id
JOIN holes h ON h.id = hs.hole_id
JOIN courses c ON c.id = r.course_id
GROUP BY p.NAME, r.id
ORDER BY Score ASC
The query gives me this result (first rows):
NAME DATE NAME SUM(hs.result) SUM(h.par) Score
Player 1 29.7.2014 Course 1 50 57 -7
Player 2 7.6.2014 Course 2 48 54 -6
Player 1 22.5.2014 Course 1 51 57 -6
Player 3 6.6.2014 Course 1 52 57 -5
Player 1 19.8.2013 Course 1 53 57 -4
Player 4 1.9.2011 Course 1 56 59 -3
Player 5 15.10.2011 Course 1 56 59 -3
Player 4 2.8.2013 Course 1 54 57 -3
Player 1 3.6.2014 Course 1 54 57 -3
Player 6 8.7.2014 Course 1 54 57 -3
Player 4 16.7.2014 Course 1 54 57 -3
Player 1 21.4.2015 Course 1 53 56 -3
Player 2 23.6.2012 Course 2 52 54 -2
How would I get average of each player scores?
Please try the following...
SELECT players.id AS player_id,
players.name AS player_name,
AVG( Score ) AS avg_score
FROM ( SELECT hole_scores.player_id AS player_id,
( SUM( hole_scores.result ) - SUM( holes.par ) ) AS Score
FROM hole_scores
JOIN holes ON holes.id = hole_scores.hole_id
JOIN rounds ON rounds.id = hole_scores.session_id
GROUP BY hole_scores.player_id,
rounds.id
) AS scoreFinder
JOIN players ON players.id = scoreFinder.player_id
GROUP BY players.id
ORDER BY player_name,
player_id;
This statement uses a subquery based on a reduced version of your supplied statement to find the scores for each player for each round.
Note that normally name can not be safely assumed to be unique as it is normally possible, even if it is not normally the case, that two players can have the same name. As such I have chosen the id value to uniquely identify each player. Since this value can be found in hole_scores.player_id there is no need to join with players at this stage.
It then performs an INNER JOIN between the subquery's results and players so that the name of each player may be included in the results. I chose to join with players at this stage rather than in the subquery as the results of the subquery will have only one record for each player to join to rather than potentially many for each player in the subquery's source dataset. I hope that this will make the statement slightly more efficient.
The statement then groups the joined dataset's records by the unique identifier for each player, and returns the id and name values for each player along with the average value of their Score at the end of each round.
If you have any questions or comments, then please feel free to post a Comment accordingly.
If you want the average, I think you can do:
SELECT p.NAME, (SUM(hs.result) - SUM(h.par))/COUNT(*) AS "Score"
FROM hole_scores hs JOIN
players p
ON hs.player_id = p.id JOIN
rounds r
ON r.id = hs.session_id JOIN
holes h
ON h.id = hs.hole_id JOIN
courses c
ON c.id = r.course_id
GROUP BY p.NAME
ORDER BY Score ASC
I am fetching data from 4 different tables:
leads
payu_transactions
corporate_user_rides
corporate_users
And there are some conditions:
user rides should be grater than 0
There should be some number of registered and active users
There will be some time period
I have written some SQL queries but i am not getting expected result-
The problem is with number of rides count and user count.
For e.g-
Lets say corporate x actually having 38 rides and 23 users but it's showing 7866 rides and 7866 users.
Another corporate y is actually having 18 rides and 5 users but it's showing 90 rides and 90 users.
Can anyone please help, i am not sure what's i am doing here.
I tried this-
query
SELECT l.id AS leadId,
l.corporate_id AS CorporateID,
"P-1" AS priority,
l.source,
l.user_name AS FirstName,
l.user_name AS LastName,
l.corporate_name AS corpName,
l.user_mail_id AS email,
l.phone_number AS phone,
l.created_At AS leadCreation,
l.comments,
Count(CU.id) AS users,
Count(CUR.id) AS rides,
PUT.amount AS payment
FROM leads l
LEFT JOIN payu_transactions PUT
ON l.user_mail_id = PUT.email
LEFT JOIN corporate_user_rides CUR
ON l.corporate_id = CUR.corporate_id
LEFT JOIN corporate_users CU
ON l.corporate_id = CU.corporate_id
WHERE l.created_at BETWEEN '2015-03-16 12:00:00' AND '2016-03-17 12:00:00'
GROUP BY l.user_mail_id
HAVING Count(CUR.id) > 0
AND Count(CU.id) > 0
AND Count(CASE
WHEN CU.status IN ( 'active' ) THEN 1
END) > 0;
Help will be appreciated.
Use Count (Distinct column.name) instead of Count(column.name).
I have a spendings table and a dates table, that are joined by date_id and id...
What I'm trying to do, is get from 1 query all the info from spendings, plus the sum of all the spendings but with a limit and/or offset
This is the query right now
SELECT spendings.id, spendings.price, spendings.title,
dates.date, users.username, currencies.value,
( SELECT SUM(sum_table.price)
FROM (
SELECT s.price
FROM spendings s, dates d
WHERE s.date_id = d.id
AND day(d.date) = 25
LIMIT 2 OFFSET 0
) as sum_table
) AS sum_price
FROM spendings, dates, users, currencies
WHERE spendings.date_id = dates.id
AND day(dates.date) = 25
AND spendings.user_id = users.id
AND spendings.curr_id = currencies.id
LIMIT 2 OFFSET 0
Output
id price title date username value sum_price
3 6.00 title1 2013-11-25 alex € 21.00
4 15.00 title2 2013-11-25 alex € 21.00
It works, but only if the date here day(d.date) = 25 is the same as the outer one here day(dates.date) = 25
If instead I put day(d.date) = day(dates.date) which seems the logic thing to do, I get #1054 - Unknown column 'dates.date' in 'where clause'
If anyone has an idea to make this simpler let me know :)
Try to join instead of using nested correlated subqueries:
SELECT spendings.id, spendings.price, spendings.title,
dates.date, users.username, currencies.value,
y.sum_price
FROM spendings, dates, users, currencies
JOIN (
SELECT day, SUM(sum_table.price) As sum_price
FROM (
SELECT day(d.date) As day,
s.price
FROM spendings s, dates d
WHERE s.date_id = d.id
AND day(d.date) = 25
LIMIT 2 OFFSET 0
) sum_table
GROUP BY day
) y
ON y.day = day(dates.date)
WHERE spendings.date_id = dates.id
-- AND day(dates.date) = 25 <== commented since it's redundant now
AND spendings.user_id = users.id
AND spendings.curr_id = currencies.id
Some remarks:
Using old join syntax with commas is not recommended: FROM table1,table2,table2 WHERE
The recommended way of expressing joins is "new" ANSI SQL join syntax:
FROM table1
[left|right|cross|[full] outer|natural] JOIN table2 {ON|USING} join_condition1
[left|right|cross|[full] outer|natural] JOIN table3 {ON|USING} join_condition2
....
Actually this "new syntax" is quite old now, since is has been published, as I remember, in 1992 - 22 years ago. In IT industry 22 years is like 22 ages.
I have a table for terminal
Id status
1 Online
2 Offline
3 Offline
and I have a separate table where I can find the total hours/date of the up and downtime.
total_time
Id up down
1 10 14
2 20 4
3 15 9
1 5 19
2 4 20
3 10 14
I want to display the terminal id, status and the TOTAL up and downtime(1 = 15(up), 2 = 24(up), 3 = 25(up). I'm using inner join and I have no idea how i will be able to get the sum of the up and downtime..
SELECT terminal.Id, terminal.status, total_time.Id, SUM(total_time.up),SUM(total_time.down)
FROM terminal
INNER JOIN total_time
ON terminal.Id = total_time.Id
WHERE terminal.Id = total_time.Id
Something like this should do the trick. I am interpreting your question as asking for only the sum of the time of the current status. If this is not what you want (and maybe you want the sum of both times), please let me know.
SELECT t.id, t.status, IF(t.status = 'Online', ttlTime.upTime, ttlTime.downTime) as totalTime
FROM terminal t
JOIN
(SELECT tt.id, SUM(tt.up) as upTime, SUM(tt.down) AS downTime
FROM total_time tt
GROUP BY tt.id) ttlTime ON t.id = ttlTime.id
See the SQLFiddle
You get "inner sums" by using the GROUP BY clause.
Try:
SELECT terminal.Id, SUM(total_time.up), SUM(total_time.down)
FROM terminal
INNER JOIN total_time
ON terminal.Id = total_time.Id
GROUP BY terminal.Id
SELECT DISTINCT terminal.Id, terminal.status, total_time.Id, SUM(total_time.up),SUM(total_time.down)
FROM terminal
INNER JOIN total_time
ON terminal.Id = total_time.Id
Should do it. The DISTINCT clause acts as a filter to remove duplicate records from a result set.