diff --git a/SMB3Explorer/Models/Exports/BattingMostRecentSeasonStatistic.cs b/SMB3Explorer/Models/Exports/BattingMostRecentSeasonStatistic.cs new file mode 100644 index 0000000..7ef063d --- /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(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 8130596..7cb6f08 100644 --- a/SMB3Explorer/Models/Exports/BattingSeasonStatistic.cs +++ b/SMB3Explorer/Models/Exports/BattingSeasonStatistic.cs @@ -141,15 +141,23 @@ 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("ISO"), Index(42)] + public double IsolatedPower => SluggingPercentage - BattingAverage; + + [Name("season_completion_date"), Index(43)] public DateTime? CompletionDate { get; set; } - [Name("season_id"), Index(42)] + [Name("season_id"), Index(44)] public int SeasonId { get; set; } - [Name("season_num"), Index(43)] + [Name("season_num"), Index(45)] public int SeasonNum { get; set; } - [Name("age"), Index(44)] + [Name("age"), Index(46)] 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 new file mode 100644 index 0000000..1ed4aa5 --- /dev/null +++ b/SMB3Explorer/Resources/Sql/SeasonAverageBatterStats.sql @@ -0,0 +1,24 @@ +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] + + 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 + 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 new file mode 100644 index 0000000..66ccf5d --- /dev/null +++ b/SMB3Explorer/Resources/Sql/SeasonAveragePitcherStats.sql @@ -0,0 +1,22 @@ +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) + 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 + JOIN mostRecentSeason ON mostRecentSeason.seasonID = tsea.ID \ No newline at end of file diff --git a/SMB3Explorer/Resources/Sql/TopPerformersBatting.sql b/SMB3Explorer/Resources/Sql/TopPerformersBatting.sql index 7ec3255..1f0b6fe 100644 --- a/SMB3Explorer/Resources/Sql/TopPerformersBatting.sql +++ b/SMB3Explorer/Resources/Sql/TopPerformersBatting.sql @@ -28,6 +28,19 @@ 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, + -- 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 @@ -56,5 +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 -LIMIT 25 \ No newline at end of file +ORDER BY sortOrder DESC \ No newline at end of file diff --git a/SMB3Explorer/Resources/Sql/TopPerformersPitching.sql b/SMB3Explorer/Resources/Sql/TopPerformersPitching.sql index 2723f8e..1148285 100644 --- a/SMB3Explorer/Resources/Sql/TopPerformersPitching.sql +++ b/SMB3Explorer/Resources/Sql/TopPerformersPitching.sql @@ -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 0 + 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 @@ -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/TopPerformersRookiesBatting.sql b/SMB3Explorer/Resources/Sql/TopPerformersRookiesBatting.sql index 5e1f980..f6cccb2 100644 --- a/SMB3Explorer/Resources/Sql/TopPerformersRookiesBatting.sql +++ b/SMB3Explorer/Resources/Sql/TopPerformersRookiesBatting.sql @@ -37,6 +37,19 @@ 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, + -- 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 @@ -67,5 +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 -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..a9e7e7c 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 0 + 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 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