競艇の結果データベースを自分で作る|欠場・中止で壊れない表の形

競艇の結果データベースの作り方|欠場・中止で壊れない表の分け方(見出し画像)

ZEN AI LAB のキャラクター ZEN

監修:ZEN AI LAB(ZEN)

人間1人とAI社員で動く会社です。記事の数値は自社の作業ログの実測、仕様や料金は公式の一次情報で確認しています。確認した日付は本文に書いています。

過去のレース結果を自分のデータベースにためようとすると、1枚の大きな表に全部入れたくなります。困るのは、欠場や失格、中止のレースが出てきたときです。結果のデータベースは、レース・出走・結果・払戻の4つに表を分けて、レースの番号(race_id)でつなぎます。

欠場・失格・中止は行を消さずに、空欄と「状態」の列で残します。こうしておくと、勝率の分母をあとから自分で選べます。

この記事では、4つの表の作り方と、普通でないレースの入れ方を書きます。ZEN BOAT LAB の研究用データベースで、2023〜2025年の168,252レースを数えた件数も載せます。データは、ZEN AI LAB が作って販売している自社ツールで集めました。

なお、過去のレースの結果を画面で見て調べるだけなら、公式のアプリや、過去のレースを検索できるアプリで足ります(7つを比べた記事は競艇のデータサイト・アプリ7つを比較)。この記事は、結果を自分でためて数えたい人向けの作り方です。

競艇のデータで何が数えられるかの全体は、競艇のデータの見方と集め方にまとめています。

表は4つ。「1行が何か」で分ける

表を分ける基準は1つです。その表の1行が、何を表しているか。競艇の結果なら、1行の意味は3種類しかありません。

  • 1レース(いつ・どの場の・何レース目か)
  • 1艇(そのレースの1号艇〜6号艇)
  • 払戻の1つの組み合わせ(3連単の1-2-3、など)

この3種類で分けると、表は次の4つになります。数字は ZEN の研究用データベースの、2023〜2025年の行数です。

表1行は何か3年の行数
レース(races)1レース168,252
出走(race_entries)1艇。選手・モーターなど1,009,512
結果(race_results)1艇。着順・失格など1,009,512
払戻(payouts)券種×組み合わせ1,658,287

出走と結果は、どちらも1行=1艇です。それでも分けるのは、分かる時刻が違うからです。出走表はレースの前に、結果はレースの後に決まります。分けておくと、「レース前に分かっていたことだけ」で数えたいときに、結果の列が混ざりません。

レースの状態(普通に終わった・中止になった)も、結果の側に置きます。レースが終わるまで決まらないからです。ZEN のデータベースでは、結果の側にレースごとの表(race_outcomes)をもう1つ持っています。

4つの表は、race_id という1つの列でつなぎます。ZEN のデータベースでは「20250105_01_01」のように、日付・場の番号・レース番号を並べた文字です。同じレースなら、どの表でも同じ race_id になります。

レース・出走・結果・払戻の4つの表を race_id でつないだ図。2023〜2025年の行数(レース168,252・出走1,009,512・結果1,009,512・払戻1,658,287)と、1枚の表にまとめた場合の9,949,722行を並べている

1枚の表にまとめると、行が約10倍になる

では、4つを1枚にまとめるとどうなるか。出走・結果の6行に、そのレースの払戻の行をすべて付けた表を、件数だけ数えてみました。

3年分で9,949,722行です。結果の表の1,009,512行の、約10倍になります。払戻の行は1レースに7〜14行あり、そのぶん艇の行が複製されるからです。1レースは42〜84行になりました。

この表で、1号艇の1着を数えると904,001回です。実際の1号艇の1着は90,421回です。艇の行が払戻の行の数だけ重なるので、回数が約10倍になります。

厄介なのは、割合にするとほぼ同じ数字に見えることです。904,001回を1号艇の行の数で割ると54.51%です。中止を除いて1号艇の行で数えた54.50%と、ほとんど変わりません。割合だけ見ていると、表が壊れていることに気づけません。

払戻を3連単だけに絞ってつないでも、問題は残ります。

  • 中止になった2,346レースは、払戻の行が無いので、表から消えます
  • 同着で3連単の払戻が2つあった52レースは、1号艇の行が2回数えられます

消える行と、2回数える行が同時に出ます。1枚の表をやめて、払戻は払戻の表で数えるほうが確かです。

3年で、普通でないレースは約12レースに1回あった

対象は、ZEN の研究用データベースの2023年1月1日から2025年12月31日の168,252レースです。

中止・欠場・失格・同着・不成立・特払いのどれかがあったレースは、14,244レースでした。全体の8.5%で、約12レースに1回です。

起きたこと3年の件数入れ方
中止2,346レースレースの状態を「中止」に。払戻は0行
フライング欠場3,959艇着順は空。状態の列に残す
出遅れ欠場92艇同上
欠場(そのほか)2,182艇同上
失格(転覆など)8,290艇着順は空。状態の列に残す
同着52レース払戻の行を2つ入れる
不成立577行払戻の行は残し、金額は空
特払い107行払戻の行は残し、状態を記録

同着の52は、3連単の払戻が2つあったレースの数です。不成立と特払いは、払戻の表の行の数です。不成立は226レースで、特払いは105レースで起きていました。

失格8,290艇の内訳は、転覆4,655・落水1,319・妨害910・エンスト903・不完走375・沈没96・そのほかの失格32です。

中止は、分母から外す

中止になったレースは、結果の表に6艇の行があります。ただし着順はすべて空で、払戻の行はありません。ZEN のデータベースでは、レースの状態の列が「CANCELLED」になっています。

1号艇の1着率を、中止を入れたまま数えると53.74%です。中止の2,346レースを外すと54.50%になります。走っていないレースは、1着ではなかったレースではありません。分母から外します。

欠場は、行を消さずに状態で残す

欠場には、フライング欠場・出遅れ欠場・それ以外の欠場の3つがあります。どれも着順の対象から外れ、その艇への投票は返還になります。3年で6,233艇、5,126レースでした。

欠場の艇の行は、消さないでください。ZEN のデータベースでは、欠場があったレースも、結果の表は必ず6行そろっています。行を消すと、「何艇立てのレースだったか」を行の数で数えたときに、取りこぼします。

欠場の1号艇を分母から外すかは、数える前に決めます。中止を外したうえで、欠場の1号艇も外すと、54.95%です。

失格は、返還されないので分母に残す

転覆や落水などの失格は、着順が付かなかった艇です。着順の列は空になります。欠場と違って、その艇への投票は返還されません。1着ではなかった艇として、分母に残すのが基本です。

中止と欠場を外した54.95%から、さらに失格の1号艇も外すと、55.26%に上がります。0.31ポイントの差です。失格の1号艇を分母から消すと、そのぶん1号艇が強く見えます。

どの分母を使うかは、問いで決まります。舟券の返還を除いた1着率を知りたいなら、中止と欠場を外した54.95%の数え方です。着順が付いた艇だけの数え方は、失格を「無かったこと」にするので、勝率には使いません。

Excel で同じ数え方をするときの式は、競艇のデータ分析をエクセルでに書きました。着順が空の行を分母に残す式と、外す式の両方を載せています。

同着は、払戻の行を2つにする

同着になると、同じ着順の数字が2艇に付きます。3年で、1着の同着が3レース、2着が6レース、3着が43レースありました。

同着のレースでは、3連単の払戻が2つの組み合わせに出ます。払戻を「1レース1行、3連単の列が1つ」の表にすると、2つめが入りません。払戻の表は、券種と組み合わせで1行にします。

不成立は、金額を0にしない

不成立は、その券種で払戻になる組み合わせが成立せず、全額返還になったものです。3年で577行あり、3連複226行・拡連複207行・3連単62行・複勝41行・2連複41行でした。

ZEN のデータベースでは、不成立の行の払戻金はすべて空です。0円で入っている行は1つもありません。0で埋めると、払戻金の平均や合計を出したときに、0円の払戻があったように数えてしまいます。行は残して、状態の列に「不成立」と書きます。

特払いは、払戻になる組み合わせを買った票が無かったときの払戻です。こちらは金額があります。3年で107行で、95行が単勝でした。

取得元が2つあると、値が食い違う

結果を2つの取得元から集めると、同じ艇の値が食い違うことがあります。ZEN のデータベースは、BOATRACE 公式サイトの競走成績のファイルと、有志が公開している非公式の API の2つから結果を取っています。

3年分で、着順の状態が食い違った艇は10,440艇ありました。BoatData の取り込みでは、公式のファイル側が区別の無い「失格」になっていた艇が、もう片方では「転覆失格」や「欠場」と分かれていたものです。そのうち2,182艇は、片方が「欠場」でした。

欠場と失格の違いは、分母に入れるかどうかに関わります。どちらを使うか決めずに上書きすると、数字が知らないうちに動きます。

ZEN のデータベースは、食い違いを別の表(value_conflicts)に記録しています。3年で35,588件です。どちらを採ったかも、1件ずつ残しています。自分で作るときも、取得元が2つあるなら、元の値を捨てない作りにしておきます。

自分で作るなら、SQLite で4つの表から

ここまでの考え方を、SQLite の表にすると次のようになります。列は最小限に絞りました。中止・欠場・同着・不成立を入れられる形です。

CREATE TABLE races (
  race_id     TEXT PRIMARY KEY,
  race_date   TEXT NOT NULL,
  venue_code  INTEGER NOT NULL,
  race_no     INTEGER NOT NULL
);
CREATE TABLE race_entries (
  race_id     TEXT NOT NULL REFERENCES races(race_id),
  boat_number INTEGER NOT NULL,
  racer_id    INTEGER,
  PRIMARY KEY (race_id, boat_number)
);
CREATE TABLE race_results (
  race_id         TEXT NOT NULL REFERENCES races(race_id),
  boat_number     INTEGER NOT NULL,
  finish_position INTEGER,
  finish_status   TEXT NOT NULL,
  PRIMARY KEY (race_id, boat_number)
);
CREATE TABLE race_outcomes (
  race_id     TEXT PRIMARY KEY REFERENCES races(race_id),
  race_status TEXT NOT NULL
);
CREATE TABLE payouts (
  race_id       TEXT NOT NULL REFERENCES races(race_id),
  bet_type      TEXT NOT NULL,
  combination   TEXT,
  payout_yen    INTEGER,
  popularity    INTEGER,
  payout_status TEXT NOT NULL,
  UNIQUE (race_id, bet_type, combination)
);
  • 出走と結果は「race_id と艇番」の組で1行です。同じ艇を2回入れようとすると、エラーで止まります
  • 着順(finish_position)は空を許し、そのかわり状態(finish_status)は必ず入れます。「1着」「転覆失格」「フライング欠場」などです
  • 払戻は「レース・券種・組み合わせ」の組で1行です。同着なら行が2つになります。不成立なら金額は空のまま、状態に「不成立」と入れます

1号艇の1着率を、中止と欠場を外して数えるSQLです。

SELECT COUNT(*) AS races,
       SUM(r.finish_position = 1) AS wins,
       ROUND(100.0 * SUM(r.finish_position = 1) / COUNT(*), 1) AS pct
FROM race_results r
JOIN race_outcomes o USING (race_id)
WHERE r.boat_number = 1
  AND o.race_status <> 'CANCELLED'
  AND r.finish_status NOT IN ('フライング欠場', '出遅れ欠場', '欠場');

失格の1号艇は分母に残ります。WHERE の2行を消せば、中止も欠場も入れた数え方になります。

このSQLは、架空の5レースを入れて実行し、答えを確かめました。1号艇が普通に1着・転覆失格・フライング欠場・中止・同着のレースで1着、の5つです。答えは3レース中2勝で、66.7%です。同じ5レースを、3連単の払戻とつないだ表で数えると、5行中3勝になりました。

表が壊れていないかは、行の数で確かめます。結果の表で、6行ではないレースを数えるSQLです。

SELECT COUNT(*) FROM (
  SELECT race_id FROM race_results
  GROUP BY race_id HAVING COUNT(*) <> 6
);

答えが0なら、どのレースも6艇そろっています。ZEN のデータベースの3年分では0でした。行を消してしまった抜けは、ここで見つかります。

表は作れても、ためるのが手間になる

表の形が決まっても、中身を入れるのが大仕事です。3年分で、結果の表だけで約100万行、払戻で約166万行あります。

公式のファイルを自分で落として表にする方法は、競艇の過去データをダウンロードする方法に書きました。ファイルの形から、欠場・失格・不成立を読み分けて、4つの表に振り分ける作業が毎日分つづきます。

その作業が重くなったら、集めてデータベースに入れるところをツールに任せる方法もあります。

集めてデータベースにするところを任せるなら

ZEN AI LAB の自社ツール BoatData Collector Pro は、この記事と同じ考え方の SQLite にためていきます。競艇の公開データを、期間と競艇場を選んでまとめて集める Windows 用のツールです。この記事の研究用データベースも、このツールで集めました。

  • 出走表・展示/直前情報・結果・払戻を取得して、SQLite にためます。次からは新しい分だけを取ります
  • 同梱のデータベース設計の資料では、表は15個(ほかに管理用が1つ)です。欠場の艇も6行そろえ、不成立は0円で埋めない作りです
  • 取得元が2つで値が食い違ったときは、別の表に記録して、決めた優先順で採ります(同梱ドキュメント)
  • Excel・CSV には、「レースごとに1行」「艇ごとに1行」の形で書き出せます

使う前に知っておいてほしいことです。

  • 予想・買い目・自動投票の機能はありません。集めて保存し、出力するところまでです
  • 公式サイトや BOATRACE とは関係のない、非公式のツールです。データの正確性は保証していません
  • 無料版があります。取得できる期間は直近30日までです。製品版は期間を自分で選べます(保存できるのは2016年10月1日以降のレース。2026年11月に実際に取得して確かめた範囲)

くわしくはBoatData Collector Pro 無料版のページと、BoatData Collector Pro のページにあります。自分で取得の仕組みを作る場合の注意は、競艇のデータをAPIで取得するときの注意にまとめました。

競艇のデータを、何か月分も自分で集めて数えるなら

BoatData Collector Pro の商品画像。全国24場の競艇データを集めて Excel・CSV に出力、重複取得しない、月額0円の買い切り

BoatData Collector Pro は、競艇の公開データを期間と競艇場を選んで集め、Excel・CSV に書き出す自社ツールです。予想や買い目は出しません。保存できるのは2016年10月1日以降のレースです。

  • BoatData Collector Pro:6,000円(買い切り・note。ココナラでも6,000円)
  • 分析版 BOAT DATA PRO:10,000円(ココナラ)。集めたデータを進入コース別・選手別などに集計する画面つき
  • 無料版:直近30日まで(LINEで受け取り)
実際の画面7枚で使い方を見るnote で購入する(6,000円)分析版 BOAT DATA PRO を見る(ココナラ)まず無料版を受け取る

価格は2026年11月7日の表示です。変わることがあるので、買う前に各ページで確かめてください。Windows 11(64bit)用です。

確かめたことと、データでは分からないこと

確かめたことは、次のとおりです。

  • 件数はすべて、研究用データベースを読み取り専用で開いて数えました。2023〜2025年の168,252レースです
  • 1枚の表の行数は、表を実際には作らず、レースごとの行数の掛け算で数えました
  • 記事のSQLは、架空の5レースを入れた SQLite で実行し、答えが合うことを確かめました
  • 販売ページ2つは、2026年10月20日に開いて読みました

このデータでは分からないことは、次のとおりです。

  • まだ確かめられていないこと:取得元が食い違った10,440艇について、どちらの値が正しかったかを、元の画面で1艇ずつ見てはいません
  • 中止・欠場・失格の扱いは、ZEN の数え方です。ほかのサイトの勝率と比べるときは、数え方が同じとは限りません
  • 記事のSQLを動かしたのは SQLite です。Access や MySQL など、ほかのデータベースはこの記事の範囲に入れていません

数字はどれも過去のレースを数えたものです。この先の結果を約束するものではなく、買い方の良し悪しを示すものでもありません。

まとめ

競艇の結果データベースは、1行の意味で表を分けて、race_id でつなぎます。欠場・失格・中止は、消さずに状態で残します。

  1. レース・出走・結果・払戻の4つの表を作り、結果の側にレースの状態を持たせます
  2. 欠場・失格は着順を空にして、状態の列に必ず書きます。不成立の払戻金は0にしません
  3. 数える前に、中止・欠場・失格を分母に入れるかを決め、数字の横に書いておきます

LAB 記録(読み飛ばしてかまいません)

  • 対象は2023年1月1日〜2025年12月31日です。研究用データベース全体は、2023年1月1日〜2026年9月27日の1,366日・210,600レースです
  • 2026年のぶん(42,348レース)は、あとで確かめるために残していて、件数だけを数えました
  • 1号艇の1着率の4つの数え方の分母は、168,252(すべて)・165,906(中止を除く)です
  • 続く2つは、164,543(中止と欠場を除く)・163,625(着順が付いた行だけ)です。分子はどれも90,421です
  • 中止も入れた53.74%は、データベースの行をそのまま数えた値です。54.50%は、開催されたレースの1号艇の1着率です
  • 165,906から欠場1,363と失格917を引くと163,626で、1つずれます。中止ではないレースに、状態が空の1号艇が1艇あるためです
  • 1枚の表の1号艇の行は1,658,287行、そのうち1着の行は904,001行です。3連単だけでつなぐと165,958行で、165,906レースぶんです
  • 中止の判定は、結果の側のレースの表(race_outcomes)の状態です
  • レースの表(races)にも状態の列がありますが、ZEN のデータベースでは168,252レースすべてが「UNKNOWN」のままでした
  • 番組を取り込んだ時点では決まらない列なので、確定した状態は結果の側だけに入っています。同じ意味の列が2か所にあるときは、どちらを使うかを決めておきます
  • 欠場と失格は、着順の状態のコード(14〜16が欠場、7〜13が失格)で分けました。BoatData の同梱ドキュメント(異常系データのレポート)の分け方です
  • 不成立は、3連単・3連複・拡連複などの券種ごとの行です。同じレースで2つ以上の券種が不成立になることがあります
  • 14,244レースに入る同着は、払戻に関わる52レースだけです。4着・5着の同着(それぞれ47・43)は数に入っていません
  • 中止の2,346レースには、艇の状態にフライング欠場が付いた艇が115艇あります。中止の形で分けると、その日の全レースが中止になった141日・1,692レース、途中のレースから最後まで中止になった129日・633レース、1レースだけの中止が21レースです(2026年11月6日に研究用データベースで集計)。天候や事故などの理由は、データベースにも公式の競走成績にも列が無いので、このデータでは分かりません
  • 取得元の食い違いは、すべて公式の競走成績のファイルと非公式の API の間で、着順の状態に関するものでした
  • 採ったのは、細かく分かれていた API 側の値です。公式の競走成績ファイル(手元にある2026年9月15日の1日分)を2026年11月6日に読むと、着順の欄に欠場は「K0」、失格は「S0」「S1」「S2」、フライングは「F」と書かれ、公式のファイルでも欠場と失格は区別されていました
  • 集計の計画は、数える前に書きました。1回目の結果を見たあとに、1号艇の分母の4通りと、中止のレースの中身を足しています(追記した日付つき)

2 COMMENTS

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です