pagetakaBlog

最近リフォームと鳥取県日南町の記事多め。写真、PC、ネット等の話題も

MySQL:前日株価との差分を1回のSQLで実現「自己結合」

本日は、RDB(リレーショナルデータベース)のことです。対象としたデータは株価です。

Microsoft:Copilotに教えてもらいました。少し簡略化してソースも載せます。

株価データを収めたテーブルの様子

テーブル「market」の一行の項目は次のようなものです。

  • id:データ逐次番号
  • date:市場日付
  • cd:銘柄コード
  • o:寄値
  • h:高値
  • l:安値
  • c:引値

実際には他の項目もありますが、説明のため簡略化しました。

[当日寄値]-[前日引値]をSQLでどう書いたら?

同じテーブルで同一CDの、異なる市場日の項目の差分を、SQLだけで求める方法を知りませんでした。

これまでは、一回のSQLでデータ取得し、Python:Pandas:DataFrameで一方の項目をshiftしたのち計算というような計算をやってました。

実は、副問い合わせ(サブ・クエリ)も数日前まで使ったことなかったです。使ってみたら便利なのを実感しました。20年くらい前、職業訓練所で「外部結合」「内部結合」とか習った記憶はあります。しかし、テーブルは一つだし…と思いつつ、最後の切り札Microsoft:Copilotに尋ねました。

「自己結合で」とのことでした。早速、持っている本を開いてみました。初心者用の本には載ってませんでした。皮肉なことに、20年前に買った厚い本には「交差結合」を含め「自己結合」も載ってました…。

勉強が足りないというのは、こういうことですね。

ひとつのテーブルでも別名(エイリアス)を使い、あたかもふたつあるようにする…らしい。

「自己結合」のポイントは、「FROM market a JOIN market b」のところのようです。ひとつのテーブルがあたかもふたつのテーブル「a」「b」として操作できることになりました。

同じ銘柄コードの[当日寄値]と[前日引値]が一回で取得できるということは、(1)JOIN:結合する当日CD(a.cd)、前日CD(b.cd)の条件を満たした上で、(2)WHERE:日付をa.date、b.dateに具体的に代入し、(3)SELECT:必要なデータを取得する、という流れが実現できるようです。

aテーブルには当市場日、bテーブルには前市場日を指定すれば、a.oで当市場日寄値、b.cで前市場日引値を取得でき、差分計算ができる準備ができました。

サンプル・コード

サンプルコードだけでは動きません。MySQLなどRDBが稼働している事、SQLで操作できることが必要です。
#以下はコメントです。
※ 3/9 スクリプト訂正:
正:SELECT a.cd AS "cd", a.o - b.c AS "dif"
誤:SELECT a.cd AS "cd", a.o - b.ac AS "dif"

SELECT a.cd AS "cd",  a.o - b.c AS "dif", a.o, b.c   # CD、差分(a.o - b.c)、検算用に、当市場日寄値(a.o)、前市場日引値(b.c)を表示
FROM `market` a      #テーブルmarketを別名 a として扱う
JOIN `market` b ON a.cd = b.cd  #テーブルmarketを別名 b として扱い、aとbの結合条件は同一cdであること
WHERE a.cd = 1332 AND a.date = "2025-03-06" AND b.date = "2025-03-05"   # データを探す日付は、a、b別日を指定する

なお、銘柄コードや日付などは、プレースホルダー、プリペアドステートメントなどを使えば変数として処理できる…と思います。また、他の項目同士の差分もSELECT文で書き分けることができそうです。

爺は、これでずいぶん楽になった気がします。

錯誤などありましたら、ご教示のほど。優し目に教えてください。今回も、Microsfot:Copilotに助けてもらいました。

3/9スクリプト補足:マッチするすべての銘柄コードを選択する場合

上記スクリプト「WHERE a.cd = 1332 AND」のうち「 a.cd = 1332 AND」を削除すると、マッチするCDすべてで、指定日間の差分計算ができます。