nar_jockey_stats
Analyze NAR local horse racing jockey statistics including win rate, place rate, and number of rides. Specify jockey name, venue, and year range.
Instructions
NAR地方競馬の騎手成績を分析
地方競馬の騎手名を指定して、勝率・複勝率・騎乗数などを調べられます。
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| jockey_name | Yes | ||
| venue | No | ||
| year_from | No |
Implementation Reference
- Public API function 'get_nar_jockey_stats' that delegates to the shared '_jockey_stats_impl' with source='nar'. This is the entry point for NAR jockey stats logic.
def get_nar_jockey_stats( db_connection, jockey_name: str, venue: Optional[str] = None, year_from: Optional[str] = None ) -> Dict[str, Any]: """NAR地方競馬の騎手成績を取得(JRA版に委譲)""" return _jockey_stats_impl( db_connection, jockey_name=jockey_name, venue=venue, year_from=year_from, source='nar' ) - Shared implementation '_jockey_stats_impl' that builds SQL queries, executes them, and returns structured jockey stats (rides, wins, places, rates). Used by both JRA and NAR variants.
def _jockey_stats_impl( db_connection, jockey_name: str, venue: Optional[str] = None, year_from: Optional[str] = None, distance: Optional[int] = None, source: str = 'jra' ) -> Dict[str, Any]: """騎手成績の共通実装(JRA/NAR兼用)""" tables = _SOURCE_TABLES[source] conditions = [] query_params: List = [] condition_desc = [f"騎手名: {jockey_name}(部分一致)"] if source == 'nar': condition_desc.append("NAR地方競馬") conditions.append("s.KisyuRyakusyo LIKE ?") query_params.append('%' + jockey_name + '%') conditions.append("s.KakuteiJyuni IS NOT NULL") conditions.append("s.KakuteiJyuni > 0") if venue: venue_code = _resolve_venue(venue, source) conditions.append("s.JyoCD = ?") query_params.append(venue_code) condition_desc.append(f"{venue}競馬場") if year_from: year_val = _validate_year(year_from) conditions.append("s.Year >= ?") query_params.append(year_val) condition_desc.append(f"{year_val}年以降") if distance: conditions.append("r.Kyori = ?") query_params.append(distance) condition_desc.append(f"{distance}m") where_clause = " AND ".join(conditions) if distance: query = f""" SELECT s.KisyuRyakusyo as jockey_name, COUNT(*) as total_rides, SUM(CASE WHEN s.KakuteiJyuni = 1 THEN 1 ELSE 0 END) as wins, SUM(CASE WHEN s.KakuteiJyuni IN (1, 2) THEN 1 ELSE 0 END) as places_2, SUM(CASE WHEN s.KakuteiJyuni IN (1, 2, 3) THEN 1 ELSE 0 END) as places_3 FROM {tables['se']} s JOIN {tables['ra']} r ON s.Year = r.Year AND s.MonthDay = r.MonthDay AND s.JyoCD = r.JyoCD AND s.Kaiji = r.Kaiji AND s.Nichiji = r.Nichiji AND s.RaceNum = r.RaceNum WHERE {where_clause} GROUP BY s.KisyuRyakusyo """ else: query = f""" SELECT s.KisyuRyakusyo as jockey_name, COUNT(*) as total_rides, SUM(CASE WHEN s.KakuteiJyuni = 1 THEN 1 ELSE 0 END) as wins, SUM(CASE WHEN s.KakuteiJyuni IN (1, 2) THEN 1 ELSE 0 END) as places_2, SUM(CASE WHEN s.KakuteiJyuni IN (1, 2, 3) THEN 1 ELSE 0 END) as places_3 FROM {tables['se']} s WHERE {where_clause} GROUP BY s.KisyuRyakusyo """ df = db_connection.execute_safe_query(query, params=tuple(query_params)) if df.empty: return { 'jockey_name': jockey_name, 'total_rides': 0, 'wins': 0, 'places_2': 0, 'places_3': 0, 'win_rate': 0.0, 'place_rate_2': 0.0, 'place_rate_3': 0.0, 'conditions': ', '.join(condition_desc), 'query': query } total_rides = int(df['total_rides'].sum()) wins = int(df['wins'].sum()) places_2 = int(df['places_2'].sum()) places_3 = int(df['places_3'].sum()) matched_jockey = df.loc[df['total_rides'].idxmax(), 'jockey_name'] return { 'jockey_name': matched_jockey, 'total_rides': total_rides, 'wins': wins, 'places_2': places_2, 'places_3': places_3, 'win_rate': (wins / total_rides * 100) if total_rides > 0 else 0.0, 'place_rate_2': (places_2 / total_rides * 100) if total_rides > 0 else 0.0, 'place_rate_3': (places_3 / total_rides * 100) if total_rides > 0 else 0.0, 'conditions': ', '.join(condition_desc), 'matched_jockeys': df['jockey_name'].tolist(), 'query': query } - Template definition for 'nar_jockey_stats' with SQL query aggregating NAR jockey stats from NL_SE_NAR table, and parameter descriptions.
"nar_jockey_stats": { "description": "NAR地方競馬の騎手成績を集計", "parameters": { "jockey_name": {"type": "str", "description": "騎手名(部分一致可)", "required": False}, "year": {"type": "str", "description": "対象年(YYYY形式)", "required": False}, "limit": {"type": "int", "description": "表示件数", "required": False, "default": 20}, }, "sql": """ SELECT KisyuRyakusyo as jockey_name, COUNT(*) as total_rides, SUM(CASE WHEN KakuteiJyuni = 1 THEN 1 ELSE 0 END) as wins, SUM(CASE WHEN KakuteiJyuni <= 3 THEN 1 ELSE 0 END) as top3, ROUND(100.0 * SUM(CASE WHEN KakuteiJyuni = 1 THEN 1 ELSE 0 END) / COUNT(*), 1) as win_rate, ROUND(100.0 * SUM(CASE WHEN KakuteiJyuni <= 3 THEN 1 ELSE 0 END) / COUNT(*), 1) as top3_rate FROM NL_SE_NAR WHERE KakuteiJyuni IS NOT NULL AND KakuteiJyuni > 0 {jockey_condition} {year_condition} GROUP BY KisyuRyakusyo ORDER BY wins DESC, win_rate DESC LIMIT {limit} """, - src/jvlink_mcp_server/server.py:593-606 (registration)MCP tool registration via @mcp.tool(name='nar_jockey_stats') decorator. Defines the 'analyze_nar_jockey_stats' handler which calls the high-level API function.
@mcp.tool(name="nar_jockey_stats") def analyze_nar_jockey_stats( jockey_name: str, venue: Optional[str] = None, year_from: Optional[str] = None ) -> dict: """NAR地方競馬の騎手成績を分析 地方競馬の騎手名を指定して、勝率・複勝率・騎乗数などを調べられます。 """ with DatabaseConnection() as db: return _get_nar_jockey_stats( db, jockey_name=jockey_name, venue=venue, year_from=year_from ) - src/jvlink_mcp_server/server.py:39-39 (registration)Import of 'get_nar_jockey_stats' from high_level_api, aliased as '_get_nar_jockey_stats'.
get_nar_jockey_stats as _get_nar_jockey_stats,