From 94a76871bbccd37acb48685d4dff5cf756e2b52f Mon Sep 17 00:00:00 2001 From: tbrittain Date: Sat, 13 May 2023 17:14:43 -0500 Subject: [PATCH 1/6] Add SeasonAverageBatterStats.sql (for league-wide OPS currently) --- .../Resources/Sql/SeasonAverageBatterStats.sql | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 SMB3Explorer/Resources/Sql/SeasonAverageBatterStats.sql diff --git a/SMB3Explorer/Resources/Sql/SeasonAverageBatterStats.sql b/SMB3Explorer/Resources/Sql/SeasonAverageBatterStats.sql new file mode 100644 index 0000000..bf5e791 --- /dev/null +++ b/SMB3Explorer/Resources/Sql/SeasonAverageBatterStats.sql @@ -0,0 +1,16 @@ +SELECT AVG( + ([hits] + [baseOnBalls] + [hitByPitch]) / + CAST(NULLIF([atBats] + [baseOnBalls] + [hitByPitch] + [sacrificeFlies], 0) AS [REAL]) + + (([hits] - [doubles] - [triples] - [homeruns]) + 2 * [doubles] + 3 * [triples] + + 4 * [homeruns]) / CAST(NULLIF([atBats], 0) AS [REAL]) + ) + AS ops +FROM [v_baseball_player_info] vbpi + LEFT JOIN t_baseball_player_local_ids tbpli ON vbpi.baseballPlayerGUID = tbpli.GUID + LEFT JOIN t_stats_players tsp ON tbpli.localID = tsp.baseballPlayerLocalID + LEFT JOIN t_stats ts ON tsp.statsPlayerID = ts.statsPlayerID + LEFT JOIN t_stats_batting tsb ON ts.aggregatorID = tsb.aggregatorID + LEFT JOIN t_baseball_players tbp ON tbpli.GUID = tbp.GUID + LEFT JOIN t_season_stats tss ON ts.aggregatorID = tss.aggregatorID + JOIN t_seasons tsea ON tss.seasonID = tsea.ID +WHERE tsea.ID = @seasonId \ No newline at end of file From f45e35f9f8ef46f85056474e3b33e41826054609 Mon Sep 17 00:00:00 2001 From: tbrittain Date: Sat, 13 May 2023 17:16:37 -0500 Subject: [PATCH 2/6] Add OPS+ calculation in top performers batting SQL files --- SMB3Explorer/Resources/Sql/TopPerformersBatting.sql | 9 +++++++-- .../Resources/Sql/TopPerformersRookiesBatting.sql | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/SMB3Explorer/Resources/Sql/TopPerformersBatting.sql b/SMB3Explorer/Resources/Sql/TopPerformersBatting.sql index 7ec3255..d6bae22 100644 --- a/SMB3Explorer/Resources/Sql/TopPerformersBatting.sql +++ b/SMB3Explorer/Resources/Sql/TopPerformersBatting.sql @@ -28,6 +28,12 @@ SELECT baseballPlayerGUID, ELSE vbpi.[pitcherRole] END AS pitcherRole, CAST(secondaryPosition.optionValue AS INTEGER) AS secondaryPosition, tsb.*, + 100 * (( + ([hits] + [baseOnBalls] + [hitByPitch]) / + CAST(NULLIF([atBats] + [baseOnBalls] + [hitByPitch] + [sacrificeFlies], 0) AS [REAL]) + + (([hits] - [doubles] - [triples] - [homeruns]) + 2 * [doubles] + 3 * [triples] + + 4 * [homeruns]) / CAST(NULLIF([atBats], 0) AS [REAL]) + ) / @leagueOps) AS opsPlus, currentTeam.teamName AS currentTeam, previousTeam.teamName AS previousTeam, tbp.age AS age @@ -56,5 +62,4 @@ FROM [v_baseball_player_info] vbpi LEFT JOIN teams previousTeam ON tt2.GUID = previousTeam.teamGUID WHERE tl.GUID = CAST(@leagueId AS BLOB) -ORDER BY homeruns DESC -LIMIT 25 \ No newline at end of file +ORDER BY homeruns DESC \ No newline at end of file diff --git a/SMB3Explorer/Resources/Sql/TopPerformersRookiesBatting.sql b/SMB3Explorer/Resources/Sql/TopPerformersRookiesBatting.sql index 5e1f980..816e36d 100644 --- a/SMB3Explorer/Resources/Sql/TopPerformersRookiesBatting.sql +++ b/SMB3Explorer/Resources/Sql/TopPerformersRookiesBatting.sql @@ -37,6 +37,12 @@ SELECT vbpi.baseballPlayerGUID, ELSE vbpi.[pitcherRole] END AS pitcherRole, CAST(secondaryPosition.optionValue AS INTEGER) AS secondaryPosition, tsb.*, + 100 * (( + ([hits] + [baseOnBalls] + [hitByPitch]) / + CAST(NULLIF([atBats] + [baseOnBalls] + [hitByPitch] + [sacrificeFlies], 0) AS [REAL]) + + (([hits] - [doubles] - [triples] - [homeruns]) + 2 * [doubles] + 3 * [triples] + + 4 * [homeruns]) / CAST(NULLIF([atBats], 0) AS [REAL]) + ) / @leagueOps) AS opsPlus, currentTeam.teamName AS currentTeam, previousTeam.teamName AS previousTeam, tbp.age AS age @@ -67,5 +73,4 @@ FROM [v_baseball_player_info] vbpi LEFT JOIN teams previousTeam ON tt2.GUID = previousTeam.teamGUID WHERE tl.GUID = CAST(@leagueId AS BLOB) -ORDER BY homeruns DESC -LIMIT 25 \ No newline at end of file +ORDER BY homeruns DESC \ No newline at end of file From fae53c892f48a18b74f3dee7c6905c336ccbcdf3 Mon Sep 17 00:00:00 2001 From: tbrittain Date: Sat, 13 May 2023 17:42:04 -0500 Subject: [PATCH 3/6] Add SeasonAveragePitcherStats.sql for ERA- and integrate in TopPerformersPitching.sql and rookie version, including an improved sort order based on ERA- and outs pitched --- .../Sql/SeasonAveragePitcherStats.sql | 17 +++++++++++++++++ .../Resources/Sql/TopPerformersPitching.sql | 19 +++++++++++++++---- .../Sql/TopPerformersRookiesPitching.sql | 15 +++++++++++++-- 3 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 SMB3Explorer/Resources/Sql/SeasonAveragePitcherStats.sql diff --git a/SMB3Explorer/Resources/Sql/SeasonAveragePitcherStats.sql b/SMB3Explorer/Resources/Sql/SeasonAveragePitcherStats.sql new file mode 100644 index 0000000..2488ae3 --- /dev/null +++ b/SMB3Explorer/Resources/Sql/SeasonAveragePitcherStats.sql @@ -0,0 +1,17 @@ +SELECT AVG( + CASE + WHEN tspitch.outsPitched = 0 THEN NULL + ELSE (tspitch.earnedRuns * 9) / (tspitch.outsPitched / 3.0) + END) AS era +FROM [v_baseball_player_info] vbpi + LEFT JOIN t_baseball_player_local_ids tbpli ON vbpi.baseballPlayerGUID = tbpli.GUID + LEFT JOIN t_stats_players tsp ON tbpli.localID = tsp.baseballPlayerLocalID + LEFT JOIN t_stats ts ON tsp.statsPlayerID = ts.statsPlayerID + JOIN t_stats_pitching tspitch ON ts.aggregatorID = tspitch.aggregatorID + + LEFT JOIN t_baseball_players tbp ON tbpli.GUID = tbp.GUID + + LEFT JOIN t_season_stats tss ON ts.aggregatorID = tss.aggregatorID + + JOIN t_seasons tsea ON tss.seasonID = tsea.ID +WHERE tsea.ID = @seasonId \ No newline at end of file diff --git a/SMB3Explorer/Resources/Sql/TopPerformersPitching.sql b/SMB3Explorer/Resources/Sql/TopPerformersPitching.sql index 2723f8e..0083927 100644 --- a/SMB3Explorer/Resources/Sql/TopPerformersPitching.sql +++ b/SMB3Explorer/Resources/Sql/TopPerformersPitching.sql @@ -8,7 +8,7 @@ FROM t_seasons JOIN t_leagues ON t_seasons.historicalLeagueGUID = t_leagues.GUID JOIN t_franchise tf ON t_leagues.GUID = tf.leagueGUID - WHERE t_leagues.GUID = CAST(@leagueId AS BLOB) + WHERE t_leagues.name = 'Baseball United v2' ORDER BY ID DESC LIMIT 1) SELECT baseballPlayerGUID, @@ -28,6 +28,18 @@ SELECT baseballPlayerGUID, WHEN tsp.[baseballPlayerLocalID] IS NULL THEN tsp.[pitcherRole] ELSE vbpi.[pitcherRole] END AS pitcherRole, tspitch.*, + CASE + WHEN tspitch.outsPitched = 0 THEN NULL + ELSE 100 * ( + @leagueEra / + ((tspitch.earnedRuns * 9) / (tspitch.outsPitched / 3.0)) + ) + END AS eraMinus, + -- sortOrder is a weighted eraMinus based on innings pitched + tspitch.outsPitched * 100 * ( + @leagueEra / + ((tspitch.earnedRuns * 9) / (tspitch.outsPitched / 3.0)) + ) AS sortOrder, currentTeam.teamName AS currentTeam, previousTeam.teamName AS previousTeam, tbp.age AS age @@ -51,7 +63,7 @@ FROM [v_baseball_player_info] vbpi ON ts.[previousRecentlyPlayedTeamLocalID] = tt2.[localID] LEFT JOIN teams currentTeam ON tt1.GUID = currentTeam.teamGUID LEFT JOIN teams previousTeam ON tt2.GUID = previousTeam.teamGUID -WHERE tl.GUID = CAST(@leagueId AS BLOB) +WHERE tl.name = 'Baseball United v2' AND outsPitched > (SELECT AVG(tspitch.outsPitched) FROM [v_baseball_player_info] vbpi LEFT JOIN t_baseball_player_local_ids tbpli ON vbpi.baseballPlayerGUID = tbpli.GUID @@ -63,5 +75,4 @@ WHERE tl.GUID = CAST(@leagueId AS BLOB) JOIN t_seasons tsea ON tss.seasonID = tsea.ID JOIN mostRecentSeason s ON tsea.ID = s.seasonID) -ORDER BY strikeOuts DESC -LIMIT 25 \ No newline at end of file +ORDER BY sortOrder DESC \ No newline at end of file diff --git a/SMB3Explorer/Resources/Sql/TopPerformersRookiesPitching.sql b/SMB3Explorer/Resources/Sql/TopPerformersRookiesPitching.sql index 4dd92b5..11579ea 100644 --- a/SMB3Explorer/Resources/Sql/TopPerformersRookiesPitching.sql +++ b/SMB3Explorer/Resources/Sql/TopPerformersRookiesPitching.sql @@ -37,6 +37,18 @@ SELECT vbpi.baseballPlayerGUID, WHEN tsp.[baseballPlayerLocalID] IS NULL THEN tsp.[pitcherRole] ELSE vbpi.[pitcherRole] END AS pitcherRole, tspitch.*, + CASE + WHEN tspitch.outsPitched = 0 THEN NULL + ELSE 100 * ( + @leagueEra / + ((tspitch.earnedRuns * 9) / (tspitch.outsPitched / 3.0)) + ) + END AS eraMinus, + -- sortOrder is a weighted eraMinus based on innings pitched + tspitch.outsPitched * 100 * ( + @leagueEra / + ((tspitch.earnedRuns * 9) / (tspitch.outsPitched / 3.0)) + ) AS sortOrder, currentTeam.teamName AS currentTeam, previousTeam.teamName AS previousTeam, tbp.age AS age @@ -74,5 +86,4 @@ WHERE tl.GUID = CAST(@leagueId AS BLOB) JOIN t_seasons tsea ON tss.seasonID = tsea.ID JOIN mostRecentSeason s ON tsea.ID = s.seasonID) -ORDER BY strikeOuts DESC -LIMIT 25 \ No newline at end of file +ORDER BY sortOrder DESC \ No newline at end of file From 69cbb061ff366958ac779682dd5c27de4d28bc5a Mon Sep 17 00:00:00 2001 From: tbrittain Date: Sat, 13 May 2023 17:45:37 -0500 Subject: [PATCH 4/6] Add similar sort order to batting as added with pitchers --- SMB3Explorer/Resources/Sql/TopPerformersBatting.sql | 9 ++++++++- .../Resources/Sql/TopPerformersRookiesBatting.sql | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/SMB3Explorer/Resources/Sql/TopPerformersBatting.sql b/SMB3Explorer/Resources/Sql/TopPerformersBatting.sql index d6bae22..1f0b6fe 100644 --- a/SMB3Explorer/Resources/Sql/TopPerformersBatting.sql +++ b/SMB3Explorer/Resources/Sql/TopPerformersBatting.sql @@ -34,6 +34,13 @@ SELECT baseballPlayerGUID, (([hits] - [doubles] - [triples] - [homeruns]) + 2 * [doubles] + 3 * [triples] + 4 * [homeruns]) / CAST(NULLIF([atBats], 0) AS [REAL]) ) / @leagueOps) AS opsPlus, + -- sortOrder is a weighted OPS+ based on number of at bats + atBats * 100 * (( + ([hits] + [baseOnBalls] + [hitByPitch]) / + CAST(NULLIF([atBats] + [baseOnBalls] + [hitByPitch] + [sacrificeFlies], 0) AS [REAL]) + + (([hits] - [doubles] - [triples] - [homeruns]) + 2 * [doubles] + 3 * [triples] + + 4 * [homeruns]) / CAST(NULLIF([atBats], 0) AS [REAL]) + ) / @leagueOps) AS sortOrder, currentTeam.teamName AS currentTeam, previousTeam.teamName AS previousTeam, tbp.age AS age @@ -62,4 +69,4 @@ FROM [v_baseball_player_info] vbpi LEFT JOIN teams previousTeam ON tt2.GUID = previousTeam.teamGUID WHERE tl.GUID = CAST(@leagueId AS BLOB) -ORDER BY homeruns DESC \ No newline at end of file +ORDER BY sortOrder DESC \ No newline at end of file diff --git a/SMB3Explorer/Resources/Sql/TopPerformersRookiesBatting.sql b/SMB3Explorer/Resources/Sql/TopPerformersRookiesBatting.sql index 816e36d..f6cccb2 100644 --- a/SMB3Explorer/Resources/Sql/TopPerformersRookiesBatting.sql +++ b/SMB3Explorer/Resources/Sql/TopPerformersRookiesBatting.sql @@ -43,6 +43,13 @@ SELECT vbpi.baseballPlayerGUID, (([hits] - [doubles] - [triples] - [homeruns]) + 2 * [doubles] + 3 * [triples] + 4 * [homeruns]) / CAST(NULLIF([atBats], 0) AS [REAL]) ) / @leagueOps) AS opsPlus, + -- sortOrder is a weighted OPS+ based on number of at bats + atBats * 100 * (( + ([hits] + [baseOnBalls] + [hitByPitch]) / + CAST(NULLIF([atBats] + [baseOnBalls] + [hitByPitch] + [sacrificeFlies], 0) AS [REAL]) + + (([hits] - [doubles] - [triples] - [homeruns]) + 2 * [doubles] + 3 * [triples] + + 4 * [homeruns]) / CAST(NULLIF([atBats], 0) AS [REAL]) + ) / @leagueOps) AS sortOrder, currentTeam.teamName AS currentTeam, previousTeam.teamName AS previousTeam, tbp.age AS age @@ -73,4 +80,4 @@ FROM [v_baseball_player_info] vbpi LEFT JOIN teams previousTeam ON tt2.GUID = previousTeam.teamGUID WHERE tl.GUID = CAST(@leagueId AS BLOB) -ORDER BY homeruns DESC \ No newline at end of file +ORDER BY sortOrder DESC \ No newline at end of file From bef8c4cf4eaa761d71331445295538c046234d57 Mon Sep 17 00:00:00 2001 From: tbrittain Date: Sat, 13 May 2023 18:54:02 -0500 Subject: [PATCH 5/6] Modify top performer (batting, pitching) exports to include wOBA, OPS+ (for batters) and ERA- (for pitchers) --- .../BattingMostRecentSeasonStatistic.cs | 41 +++++++++++ .../Models/Exports/BattingSeasonStatistic.cs | 13 ++-- .../PitchingMostRecentSeasonStatistic.cs | 44 ++++++++++++ .../Sql/SeasonAverageBatterStats.sql | 12 +++- .../Sql/SeasonAveragePitcherStats.sql | 15 ++-- .../Resources/Sql/TopPerformersPitching.sql | 6 +- .../Sql/TopPerformersRookiesPitching.sql | 2 +- SMB3Explorer/SMB3Explorer.csproj | 4 ++ .../DataServiceMostRecentSeason.cs | 71 +++++++++++++++++-- .../Services/DataService/IDataService.cs | 4 +- SMB3Explorer/Utils/SqlRunner.cs | 6 ++ 11 files changed, 197 insertions(+), 21 deletions(-) create mode 100644 SMB3Explorer/Models/Exports/BattingMostRecentSeasonStatistic.cs create mode 100644 SMB3Explorer/Models/Exports/PitchingMostRecentSeasonStatistic.cs diff --git a/SMB3Explorer/Models/Exports/BattingMostRecentSeasonStatistic.cs b/SMB3Explorer/Models/Exports/BattingMostRecentSeasonStatistic.cs new file mode 100644 index 0000000..4990100 --- /dev/null +++ b/SMB3Explorer/Models/Exports/BattingMostRecentSeasonStatistic.cs @@ -0,0 +1,41 @@ +using CsvHelper.Configuration.Attributes; + +namespace SMB3Explorer.Models.Exports; + +public class BattingMostRecentSeasonStatistic : BattingSeasonStatistic +{ + public BattingMostRecentSeasonStatistic(BattingSeasonStatistic battingSeasonStatistic) + { + PlayerId = battingSeasonStatistic.PlayerId; + FirstName = battingSeasonStatistic.FirstName; + LastName = battingSeasonStatistic.LastName; + CurrentTeam = battingSeasonStatistic.CurrentTeam; + PreviousTeam = battingSeasonStatistic.PreviousTeam; + PositionNumber = battingSeasonStatistic.PositionNumber; + SecondaryPositionNumber = battingSeasonStatistic.SecondaryPositionNumber; + GamesBatting = battingSeasonStatistic.GamesBatting; + GamesPlayed = battingSeasonStatistic.GamesPlayed; + AtBats = battingSeasonStatistic.AtBats; + Runs = battingSeasonStatistic.Runs; + Hits = battingSeasonStatistic.Hits; + Doubles = battingSeasonStatistic.Doubles; + Triples = battingSeasonStatistic.Triples; + HomeRuns = battingSeasonStatistic.HomeRuns; + RunsBattedIn = battingSeasonStatistic.RunsBattedIn; + StolenBases = battingSeasonStatistic.StolenBases; + CaughtStealing = battingSeasonStatistic.CaughtStealing; + Walks = battingSeasonStatistic.Walks; + Strikeouts = battingSeasonStatistic.Strikeouts; + HitByPitch = battingSeasonStatistic.HitByPitch; + SacrificeHits = battingSeasonStatistic.SacrificeHits; + SacrificeFlies = battingSeasonStatistic.SacrificeFlies; + PassedBalls = battingSeasonStatistic.PassedBalls; + CompletionDate = battingSeasonStatistic.CompletionDate; + SeasonId = battingSeasonStatistic.SeasonId; + SeasonNum = battingSeasonStatistic.SeasonNum; + Age = battingSeasonStatistic.Age; + } + + [Name("OPS+"), Index(46)] + public double OnBasePercentagePlus { get; set; } +} \ No newline at end of file diff --git a/SMB3Explorer/Models/Exports/BattingSeasonStatistic.cs b/SMB3Explorer/Models/Exports/BattingSeasonStatistic.cs index 8130596..dd177b1 100644 --- a/SMB3Explorer/Models/Exports/BattingSeasonStatistic.cs +++ b/SMB3Explorer/Models/Exports/BattingSeasonStatistic.cs @@ -141,15 +141,20 @@ public class BattingSeasonStatistic [Name("extra_base_hit_percentage"), Index(40)] public double ExtraBaseHitPercentage => ExtraBaseHits / (double) Hits; - [Name("season_completion_date"), Index(41)] + // Caveat with this, the denominator should be subtracting intentional walks, but that data is not available + [Name("wOBA"), Index(41)] + public double WeightedOnBaseAverage => ((0.69 * Walks) + (0.72 * HitByPitch) + (0.89 * Singles) + (1.27 * Doubles) + + (1.62 * Triples) + (2.10 * HomeRuns)) / (AtBats + Walks + SacrificeFlies + HitByPitch); + + [Name("season_completion_date"), Index(42)] public DateTime? CompletionDate { get; set; } - [Name("season_id"), Index(42)] + [Name("season_id"), Index(43)] public int SeasonId { get; set; } - [Name("season_num"), Index(43)] + [Name("season_num"), Index(44)] public int SeasonNum { get; set; } - [Name("age"), Index(44)] + [Name("age"), Index(45)] public int Age { get; set; } } \ No newline at end of file diff --git a/SMB3Explorer/Models/Exports/PitchingMostRecentSeasonStatistic.cs b/SMB3Explorer/Models/Exports/PitchingMostRecentSeasonStatistic.cs new file mode 100644 index 0000000..18019af --- /dev/null +++ b/SMB3Explorer/Models/Exports/PitchingMostRecentSeasonStatistic.cs @@ -0,0 +1,44 @@ +using CsvHelper.Configuration.Attributes; + +namespace SMB3Explorer.Models.Exports; + +public class PitchingMostRecentSeasonStatistic : PitchingSeasonStatistic +{ + public PitchingMostRecentSeasonStatistic(PitchingSeasonStatistic pitchingSeasonStatistic) + { + PlayerId = pitchingSeasonStatistic.PlayerId; + FirstName = pitchingSeasonStatistic.FirstName; + LastName = pitchingSeasonStatistic.LastName; + CurrentTeam = pitchingSeasonStatistic.CurrentTeam; + PreviousTeam = pitchingSeasonStatistic.PreviousTeam; + PositionNumber = pitchingSeasonStatistic.PositionNumber; + PitcherRole = pitchingSeasonStatistic.PitcherRole; + GamesPlayed = pitchingSeasonStatistic.GamesPlayed; + GamesStarted = pitchingSeasonStatistic.GamesStarted; + Wins = pitchingSeasonStatistic.Wins; + Losses = pitchingSeasonStatistic.Losses; + CompleteGames = pitchingSeasonStatistic.CompleteGames; + Shutouts = pitchingSeasonStatistic.Shutouts; + TotalPitches = pitchingSeasonStatistic.TotalPitches; + Saves = pitchingSeasonStatistic.Saves; + OutsPitched = pitchingSeasonStatistic.OutsPitched; + HitsAllowed = pitchingSeasonStatistic.HitsAllowed; + EarnedRuns = pitchingSeasonStatistic.EarnedRuns; + HomeRunsAllowed = pitchingSeasonStatistic.HomeRunsAllowed; + WalksAllowed = pitchingSeasonStatistic.WalksAllowed; + Strikeouts = pitchingSeasonStatistic.Strikeouts; + HitByPitch = pitchingSeasonStatistic.HitByPitch; + BattersFaced = pitchingSeasonStatistic.BattersFaced; + GamesFinished = pitchingSeasonStatistic.GamesFinished; + RunsAllowed = pitchingSeasonStatistic.RunsAllowed; + WildPitches = pitchingSeasonStatistic.WildPitches; + CompletionDate = pitchingSeasonStatistic.CompletionDate; + SeasonId = pitchingSeasonStatistic.SeasonId; + SeasonNum = pitchingSeasonStatistic.SeasonNum; + Age = pitchingSeasonStatistic.Age; + } + + + [Name("ERA-"), Index(47)] + public double EarnedRunsAllowedMinus { get; set; } +} \ No newline at end of file diff --git a/SMB3Explorer/Resources/Sql/SeasonAverageBatterStats.sql b/SMB3Explorer/Resources/Sql/SeasonAverageBatterStats.sql index bf5e791..1ed4aa5 100644 --- a/SMB3Explorer/Resources/Sql/SeasonAverageBatterStats.sql +++ b/SMB3Explorer/Resources/Sql/SeasonAverageBatterStats.sql @@ -1,4 +1,12 @@ -SELECT AVG( +WITH mostRecentSeason AS (SELECT id AS seasonID, + RANK() OVER (ORDER BY id) AS seasonNum + FROM t_seasons + JOIN t_leagues ON t_seasons.historicalLeagueGUID = t_leagues.GUID + JOIN t_franchise tf ON t_leagues.GUID = tf.leagueGUID + WHERE t_leagues.GUID = CAST(@leagueId AS BLOB) + ORDER BY ID DESC + LIMIT 1) +SELECT AVG( ([hits] + [baseOnBalls] + [hitByPitch]) / CAST(NULLIF([atBats] + [baseOnBalls] + [hitByPitch] + [sacrificeFlies], 0) AS [REAL]) + (([hits] - [doubles] - [triples] - [homeruns]) + 2 * [doubles] + 3 * [triples] + @@ -13,4 +21,4 @@ FROM [v_baseball_player_info] vbpi LEFT JOIN t_baseball_players tbp ON tbpli.GUID = tbp.GUID LEFT JOIN t_season_stats tss ON ts.aggregatorID = tss.aggregatorID JOIN t_seasons tsea ON tss.seasonID = tsea.ID -WHERE tsea.ID = @seasonId \ No newline at end of file + JOIN mostRecentSeason ON mostRecentSeason.seasonID = tsea.ID \ No newline at end of file diff --git a/SMB3Explorer/Resources/Sql/SeasonAveragePitcherStats.sql b/SMB3Explorer/Resources/Sql/SeasonAveragePitcherStats.sql index 2488ae3..66ccf5d 100644 --- a/SMB3Explorer/Resources/Sql/SeasonAveragePitcherStats.sql +++ b/SMB3Explorer/Resources/Sql/SeasonAveragePitcherStats.sql @@ -1,4 +1,12 @@ -SELECT AVG( +WITH mostRecentSeason AS (SELECT id AS seasonID, + RANK() OVER (ORDER BY id) AS seasonNum + FROM t_seasons + JOIN t_leagues ON t_seasons.historicalLeagueGUID = t_leagues.GUID + JOIN t_franchise tf ON t_leagues.GUID = tf.leagueGUID + WHERE t_leagues.GUID = CAST(@leagueId AS BLOB) + ORDER BY ID DESC + LIMIT 1) +SELECT AVG( CASE WHEN tspitch.outsPitched = 0 THEN NULL ELSE (tspitch.earnedRuns * 9) / (tspitch.outsPitched / 3.0) @@ -8,10 +16,7 @@ FROM [v_baseball_player_info] vbpi LEFT JOIN t_stats_players tsp ON tbpli.localID = tsp.baseballPlayerLocalID LEFT JOIN t_stats ts ON tsp.statsPlayerID = ts.statsPlayerID JOIN t_stats_pitching tspitch ON ts.aggregatorID = tspitch.aggregatorID - LEFT JOIN t_baseball_players tbp ON tbpli.GUID = tbp.GUID - LEFT JOIN t_season_stats tss ON ts.aggregatorID = tss.aggregatorID - JOIN t_seasons tsea ON tss.seasonID = tsea.ID -WHERE tsea.ID = @seasonId \ No newline at end of file + JOIN mostRecentSeason ON mostRecentSeason.seasonID = tsea.ID \ No newline at end of file diff --git a/SMB3Explorer/Resources/Sql/TopPerformersPitching.sql b/SMB3Explorer/Resources/Sql/TopPerformersPitching.sql index 0083927..1148285 100644 --- a/SMB3Explorer/Resources/Sql/TopPerformersPitching.sql +++ b/SMB3Explorer/Resources/Sql/TopPerformersPitching.sql @@ -8,7 +8,7 @@ FROM t_seasons JOIN t_leagues ON t_seasons.historicalLeagueGUID = t_leagues.GUID JOIN t_franchise tf ON t_leagues.GUID = tf.leagueGUID - WHERE t_leagues.name = 'Baseball United v2' + WHERE t_leagues.GUID = CAST(@leagueId AS BLOB) ORDER BY ID DESC LIMIT 1) SELECT baseballPlayerGUID, @@ -29,7 +29,7 @@ SELECT baseballPlayerGUID, ELSE vbpi.[pitcherRole] END AS pitcherRole, tspitch.*, CASE - WHEN tspitch.outsPitched = 0 THEN NULL + WHEN tspitch.outsPitched = 0 THEN 0 ELSE 100 * ( @leagueEra / ((tspitch.earnedRuns * 9) / (tspitch.outsPitched / 3.0)) @@ -63,7 +63,7 @@ FROM [v_baseball_player_info] vbpi ON ts.[previousRecentlyPlayedTeamLocalID] = tt2.[localID] LEFT JOIN teams currentTeam ON tt1.GUID = currentTeam.teamGUID LEFT JOIN teams previousTeam ON tt2.GUID = previousTeam.teamGUID -WHERE tl.name = 'Baseball United v2' +WHERE tl.GUID = CAST(@leagueId AS BLOB) AND outsPitched > (SELECT AVG(tspitch.outsPitched) FROM [v_baseball_player_info] vbpi LEFT JOIN t_baseball_player_local_ids tbpli ON vbpi.baseballPlayerGUID = tbpli.GUID diff --git a/SMB3Explorer/Resources/Sql/TopPerformersRookiesPitching.sql b/SMB3Explorer/Resources/Sql/TopPerformersRookiesPitching.sql index 11579ea..a9e7e7c 100644 --- a/SMB3Explorer/Resources/Sql/TopPerformersRookiesPitching.sql +++ b/SMB3Explorer/Resources/Sql/TopPerformersRookiesPitching.sql @@ -38,7 +38,7 @@ SELECT vbpi.baseballPlayerGUID, ELSE vbpi.[pitcherRole] END AS pitcherRole, tspitch.*, CASE - WHEN tspitch.outsPitched = 0 THEN NULL + WHEN tspitch.outsPitched = 0 THEN 0 ELSE 100 * ( @leagueEra / ((tspitch.earnedRuns * 9) / (tspitch.outsPitched / 3.0)) diff --git a/SMB3Explorer/SMB3Explorer.csproj b/SMB3Explorer/SMB3Explorer.csproj index b42d5c4..83e4043 100644 --- a/SMB3Explorer/SMB3Explorer.csproj +++ b/SMB3Explorer/SMB3Explorer.csproj @@ -91,6 +91,10 @@ + + + + diff --git a/SMB3Explorer/Services/DataService/DataServiceMostRecentSeason.cs b/SMB3Explorer/Services/DataService/DataServiceMostRecentSeason.cs index 5e14de9..453a3ed 100644 --- a/SMB3Explorer/Services/DataService/DataServiceMostRecentSeason.cs +++ b/SMB3Explorer/Services/DataService/DataServiceMostRecentSeason.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Microsoft.Data.Sqlite; using Newtonsoft.Json; using SMB3Explorer.Enums; @@ -11,9 +12,11 @@ namespace SMB3Explorer.Services.DataService; public partial class DataService { - public async IAsyncEnumerable GetMostRecentSeasonTopBattingStatistics( + public async IAsyncEnumerable GetMostRecentSeasonTopBattingStatistics( bool isRookies = false) { + var seasonAverageOps = await GetAverageSeasonOps(); + var command = Connection!.CreateCommand(); var sqlFile = isRookies ? SqlFile.TopPerformersRookiesBatting : SqlFile.TopPerformersBatting; @@ -25,6 +28,11 @@ public async IAsyncEnumerable GetMostRecentSeasonTopBatt { Value = _applicationContext.SelectedFranchise!.LeagueId.ToBlob() }); + + command.Parameters.Add(new SqliteParameter("@leagueOps", SqliteType.Real) + { + Value = seasonAverageOps + }); var reader = await command.ExecuteReaderAsync(); @@ -32,13 +40,20 @@ public async IAsyncEnumerable GetMostRecentSeasonTopBatt { var positionPlayerStatistic = GetPositionPlayerSeasonStatistic(true, reader); - yield return positionPlayerStatistic; + var mostRecentSeasonStatistic = new BattingMostRecentSeasonStatistic(positionPlayerStatistic); + + var opsPlus = reader["opsPlus"].ToString()!; + mostRecentSeasonStatistic.OnBasePercentagePlus = string.IsNullOrEmpty(opsPlus) ? 0 : double.Parse(opsPlus); + + yield return mostRecentSeasonStatistic; } } - public async IAsyncEnumerable GetMostRecentSeasonTopPitchingStatistics( + public async IAsyncEnumerable GetMostRecentSeasonTopPitchingStatistics( bool isRookies = false) { + var seasonAverageEra = await GetAverageSeasonEra(); + var command = Connection!.CreateCommand(); var sqlFile = isRookies ? SqlFile.TopPerformersRookiesPitching : SqlFile.TopPerformersPitching; @@ -50,6 +65,11 @@ public async IAsyncEnumerable GetMostRecentSeasonTopPit { Value = _applicationContext.SelectedFranchise!.LeagueId.ToBlob() }); + + command.Parameters.Add(new SqliteParameter("@leagueEra", SqliteType.Real) + { + Value = seasonAverageEra + }); var reader = await command.ExecuteReaderAsync(); @@ -57,7 +77,12 @@ public async IAsyncEnumerable GetMostRecentSeasonTopPit { var pitcherStatistic = GetPitchingSeasonStatistic(true, reader); - yield return pitcherStatistic; + var mostRecentSeasonStatistic = new PitchingMostRecentSeasonStatistic(pitcherStatistic); + + var eraMinus = reader["eraMinus"].ToString()!; + mostRecentSeasonStatistic.EarnedRunsAllowedMinus = string.IsNullOrEmpty(eraMinus) ? 0 : double.Parse(eraMinus); + + yield return mostRecentSeasonStatistic; } } @@ -162,4 +187,42 @@ public async IAsyncEnumerable GetMostRecentSeasonTeams() yield return seasonTeam; } } + + private async Task GetAverageSeasonOps() + { + var command = Connection!.CreateCommand(); + + var commandText = SqlRunner.GetSqlCommand(SqlFile.SeasonAverageBatterStats); + command.CommandText = commandText; + + command.Parameters.Add(new SqliteParameter("@leagueId", SqliteType.Blob) + { + Value = _applicationContext.SelectedFranchise!.LeagueId.ToBlob() + }); + + var reader = await command.ExecuteReaderAsync(); + reader.Read(); + + var opsOrdinal = reader.GetDouble(0); + return opsOrdinal; + } + + private async Task GetAverageSeasonEra() + { + var command = Connection!.CreateCommand(); + + var commandText = SqlRunner.GetSqlCommand(SqlFile.SeasonAveragePitcherStats); + command.CommandText = commandText; + + command.Parameters.Add(new SqliteParameter("@leagueId", SqliteType.Blob) + { + Value = _applicationContext.SelectedFranchise!.LeagueId.ToBlob() + }); + + var reader = await command.ExecuteReaderAsync(); + reader.Read(); + + var eraOrdinal = reader.GetDouble(0); + return eraOrdinal; + } } \ No newline at end of file diff --git a/SMB3Explorer/Services/DataService/IDataService.cs b/SMB3Explorer/Services/DataService/IDataService.cs index 247d49f..259b9b5 100644 --- a/SMB3Explorer/Services/DataService/IDataService.cs +++ b/SMB3Explorer/Services/DataService/IDataService.cs @@ -29,8 +29,8 @@ public interface IDataService IAsyncEnumerable GetFranchiseSeasonStandings(); IAsyncEnumerable GetFranchisePlayoffStandings(); - IAsyncEnumerable GetMostRecentSeasonTopBattingStatistics(bool isRookies = false); - IAsyncEnumerable GetMostRecentSeasonTopPitchingStatistics(bool isRookies = false); + IAsyncEnumerable GetMostRecentSeasonTopBattingStatistics(bool isRookies = false); + IAsyncEnumerable GetMostRecentSeasonTopPitchingStatistics(bool isRookies = false); IAsyncEnumerable GetMostRecentSeasonPlayers(); IAsyncEnumerable GetMostRecentSeasonTeams(); diff --git a/SMB3Explorer/Utils/SqlRunner.cs b/SMB3Explorer/Utils/SqlRunner.cs index a04a615..6f4d7f2 100644 --- a/SMB3Explorer/Utils/SqlRunner.cs +++ b/SMB3Explorer/Utils/SqlRunner.cs @@ -68,6 +68,12 @@ public enum SqlFile [Description("MostRecentSeasonTeams.sql")] MostRecentSeasonTeams, + + [Description("SeasonAverageBatterStats.sql")] + SeasonAverageBatterStats, + + [Description("SeasonAveragePitcherStats.sql")] + SeasonAveragePitcherStats, } public static class SqlRunner From 1b2485645b75b8803c151ee4f2dbf3fff4592dae Mon Sep 17 00:00:00 2001 From: tbrittain Date: Sat, 13 May 2023 19:01:25 -0500 Subject: [PATCH 6/6] Add isolated power to BattingSeasonStatistic --- .../Exports/BattingMostRecentSeasonStatistic.cs | 2 +- SMB3Explorer/Models/Exports/BattingSeasonStatistic.cs | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/SMB3Explorer/Models/Exports/BattingMostRecentSeasonStatistic.cs b/SMB3Explorer/Models/Exports/BattingMostRecentSeasonStatistic.cs index 4990100..7ef063d 100644 --- a/SMB3Explorer/Models/Exports/BattingMostRecentSeasonStatistic.cs +++ b/SMB3Explorer/Models/Exports/BattingMostRecentSeasonStatistic.cs @@ -36,6 +36,6 @@ public BattingMostRecentSeasonStatistic(BattingSeasonStatistic battingSeasonStat Age = battingSeasonStatistic.Age; } - [Name("OPS+"), Index(46)] + [Name("OPS+"), Index(47)] public double OnBasePercentagePlus { get; set; } } \ No newline at end of file diff --git a/SMB3Explorer/Models/Exports/BattingSeasonStatistic.cs b/SMB3Explorer/Models/Exports/BattingSeasonStatistic.cs index dd177b1..7cb6f08 100644 --- a/SMB3Explorer/Models/Exports/BattingSeasonStatistic.cs +++ b/SMB3Explorer/Models/Exports/BattingSeasonStatistic.cs @@ -146,15 +146,18 @@ public class BattingSeasonStatistic public double WeightedOnBaseAverage => ((0.69 * Walks) + (0.72 * HitByPitch) + (0.89 * Singles) + (1.27 * Doubles) + (1.62 * Triples) + (2.10 * HomeRuns)) / (AtBats + Walks + SacrificeFlies + HitByPitch); - [Name("season_completion_date"), Index(42)] + [Name("ISO"), Index(42)] + public double IsolatedPower => SluggingPercentage - BattingAverage; + + [Name("season_completion_date"), Index(43)] public DateTime? CompletionDate { get; set; } - [Name("season_id"), Index(43)] + [Name("season_id"), Index(44)] public int SeasonId { get; set; } - [Name("season_num"), Index(44)] + [Name("season_num"), Index(45)] public int SeasonNum { get; set; } - [Name("age"), Index(45)] + [Name("age"), Index(46)] public int Age { get; set; } } \ No newline at end of file