質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Q&A

解決済

1回答

1874閲覧

MySQL8.0にて、期間を指定してその期間内の銘柄別の最高値・最安値を表示したい。

GARYU

総合スコア8

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

0グッド

0クリップ

投稿2019/06/05 12:45

編集2019/06/08 05:04

データベース内にはA・Bの2つテーブルがあります。
Aは日付・証券コード・銘柄名・始値・高値・安値・終値が全銘柄分入ってます。
Bは市場が開いていた日(土・日・祝・正月等の休場日の日付は無し)の日付のみが1日=1レコードで入ってます。
各データは毎日csvファイルからその日の全銘柄のデータを各テーブルに読み込みます。

取得したいカラムは、各銘柄別に
証券コード・銘柄名・期間内の最高値・期間内の最高値を付けた日・期間内の最安値・期間内の最安値を付けた日・本日の前日比
となります。

『期間内』と付けた部分ですが、「テーブルB内にある最新日から〇日間(最新日を含む営業日のみ)遡った期間で」という意味で期間を括りたいと思ってます。
例:仮に19/6/9(日)に「過去7日間」の各データを取得するとしてSQLを実行したとしたら、6/9~6/3まで遡るというカレンダー上の「過去7日間」(6/9・6/8は休場日なのでテーブルBにはもともとデータがない)ではなく、6/7・6/6・6/5・6/4・6/3・5/31・5/30の休場日ではない(テーブルBにデータがある)「過去7日間」のうちの最高値・最安値を取得する。
DATE_ADD関数ではカレンダー上の「過去7日」は取得出来たのですが、ほしい値ではありません。
5日移動平均や25日移動平均といった時の期間の括り方です。
(もちろんここで質問しているので移動平均も出せていませんが・・・)

『本日』と付けた部分はSQL実行日ではなく、あくまでもテーブルB内のデータがある中の最新日という意味です。

SQLが思いつかず、ご指導いただきたいと思ってます。
お手間とは思いますが何も解かってない初心者ですので、ご指導頂けるSQL文の意味も注釈で教えて頂けると今後の為の勉強ともなります。
何卒よろしくお願いします。

《追記》
A・Bの二つのテーブルと書きましたが実際はデータインポート用のテーブルを作っておりデータベース内には計3つのテーブルがあります。
質問するにあたり簡素化のつもりで書いたのですが、情報が不正確であったことが何かしらに影響を与えたのでしたら大変申し訳ありません。

IMPはインポート用・Aは日々読み込んだデータの蓄積用・Bは営業日判別用のつもりで作りました。
以下のcreate table文で3つのテーブルをつくりました。
create table IMP (
DATE DATE,
STOCK_CD CHAR(4),
MARKET_CD CHAR(2),
STOCK_NAME VARCHAR(100),
OPEN float,
HIGH float,
LOW float,
CLOSE float,
VOLUME float,
MARKET_NAME VARCHAR(20)
);

create table A (
DATE DATE,
STOCK_CD CHAR(4),
MARKET_CD CHAR(2),
STOCK_NAME VARCHAR(100),
OPEN float,
HIGH float,
LOW float,
CLOSE float,
VOLUME float,
MARKET_NAME VARCHAR(20)
);
create table B (
DATE date primary key
);

データの取り込みは最初にcsvファイルを保存しMySQL Workbench内のテーブル表示を右クリック「Table Data Import Wizard」でテーブルIMPにデータを取り込み
insert into A
select
DATE,
STOCK_CD,
MARKET_CD,
STOCK_NAME,
OPEN,
HIGH,
LOW,
CLOSE,
VOLUME,
MARKET_NAME
from IMP;
で本日のデータを前日分までのデータを蓄積しているAに追加しています。
insert ignore into B
select distinct
DATE
from IMP;
でテーブルIMPから日付のみを同様に前日までの営業日が蓄積されているBに追加しています。

インポートするcsvファイルは1日 ×4千数百銘柄のデータの形で各カラムと同じ内容の列が並んでいます。

何卒ご指導よろしくお願いします。

《追記2》
教えて頂いたコードを実行したところ

13:09:05 with date_range as ( -- 指定した期間内(最新日付より過去7日) select date from b hst where date <= (select max(date) from b) and (select count() from b where date>=hst.date) <= 7 ) , peak as ( --期間高値:指定した期間内の最高値、最安値 select STOCK_CD, STOCK_NAME, Max(HIGH) max_peak, Min(LOW) min_peak from a where date in (select date from date_range) group by STOCK_CD, STOCK_NAME ) , rasio as ( --前日比 :テーブルB内にある最新日の終値とその前営業日の終値との比較 select date, STOCK_CD , close - lag(CLOSE) over (partition by STOCK_CD order by date) rasio from a ) select pk. --・高値日 :期間高値を付けた日 , (select max(date) from a where STOCK_CD=pk.STOCK_CD and HIGH=pk.max_peak and date in (select date from date_range) ) --・安値日 :期間安値を付けた日 , (select max(date) from a where STOCK_CD=pk.STOCK_CD and LOW=pk.min_peak and date in (select date from date_range) ) , (select max(rasio) from rasio where date = (select max(date) from b) and STOCK_CD=pk.STOCK_CD ) from peak pk Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '--期間高値:指定した期間内の最高値、最安値 select STOCK_' at line 9 0.000 sec

のエラーが返ってきました。
MySQL Workbenchdeしました。
上から
use データベース名;
withから始まる教えて頂いたSQLをペースト
となってますがwithの左横にエラーがあった時の赤い×が付いてます。

indexについては①使い方をよく理解していないこと ②記事を探しましたがどのカラムに対して作成するのが良いのか により手を着けられていません。「現状インデックスがないなら使い物にならないほど低速」とおっしゃっている部分が非常に気になっています。
インデックスを使えば解消するのか? またよく見かける記事の「PHP+SQL」や「python+SQL」といった他プログラミング言語でのSQL操作の方が良いのか(他言語は1からの勉強となりますが・・・)。
ゆくゆくはSQL内からデータを取り出し他言語で分析というのが目的ではありますが、まずはSQLからと思い質問させていただいています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Orlofsky

2019/06/05 17:26

質問のテーブルの定義情報は、できれば CREATE TABLE に修正できると適切なコメントが付きやすいです。
guest

回答1

0

ベストアンサー

取り敢えず集計していないSQLです。

SQL

1select ta.* 2from ta inner join ( 3 select * from tb t1 4 where 日付 <= date() 5 and (select count(*) from tb where 日付>=t1.日付)<=7 6 ) tc 7 on ta.日付=tc.日付

追記

MySQL8.0はwith分析関数が使えるので利用すると簡潔になります。
MySQL8.0は手元にないのでpostgresを使用して検証しました。

キーワードとしてはwithlag位ですね。
最終的に相関副問合せを用いてますが、集計を別テーブルに分けて結合する方法もあると思います。
現状インデックスが無いなら使い物にならないほど低速です。
また、日付と証券コードで一意になっていないのも前日比などでは問題です。

SQL

1with 2 date_range as ( 3 -- 指定した期間内(最新日付より過去7日) 4 select date from b hst 5 where date <= (select max(date) from b) 6 and (select count(*) from b where date>=hst.date)<=7 7 ) 8, peak as ( 9 --期間高値:指定した期間内の最高値、最安値 10 select STOCK_CD, STOCK_NAME, Max(HIGH) max_peak, Min(LOW) min_peak 11 from a where date in (select date from date_range) 12 group by STOCK_CD, STOCK_NAME 13 ) 14 , rasio as ( 15 --前日比 :テーブルB内にある最新日の終値とその前営業日の終値との比較 16 select date, STOCK_CD 17 , close - lag(CLOSE) over (partition by STOCK_CD order by date) rasio 18 from a 19 ) 20select pk.* 21 --・高値日 :期間高値を付けた日 22 , (select max(date) from a 23 where STOCK_CD=pk.STOCK_CD and HIGH=pk.max_peak 24 and date in (select date from date_range) 25 ) 26 --・安値日 :期間安値を付けた日 27 , (select max(date) from a 28 where STOCK_CD=pk.STOCK_CD and LOW=pk.min_peak 29 and date in (select date from date_range) 30 ) 31 , (select max(rasio) from rasio 32 where date = (select max(date) from b) and STOCK_CD=pk.STOCK_CD 33 ) 34from peak pk

投稿2019/06/05 14:39

編集2019/06/08 03:37
sazi

総合スコア25173

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

GARYU

2019/06/08 10:56 編集

説明能力が低くてすみません。 SQL実行時以下のような結果を望んでいます。 |証券コード|銘柄名|期間高値|高値日|期間安値|安値日|前日比| |:--:|:--|--:|--:|--:|--:|--:| |2345|○○商事|3300|2019/05/21|2995|2019/06/03|-120| |2346|〇△◇銀行|2265|2019/06/08|2005|2019/05/25|+15| |2347|××証券|10750|2019/06/04|9900|2019/05/23|+1250| |…|…|…|…|…|…|…| |5678|△△―|650|2019/05/22|550|2019/06/05|+70| |5679|◇◇商店|1680|2019/05/23|1440|2019/06/05|+10| |5680|◎◎工業|2220|2019/05/22|1800|2019/06/04|+200| |5681|△△開発|4500|2019/06/08|4250|2019/05/28|+50| |…|…|…|…|…|…|…| |7123|〇×食品|5600|2019/05/25|4550|2019/06/06|+750| |7124|□□フーズ|3100|2019/05/23|2980|2019/06/04|+35| |7125|◇△冷食|1950|2019/05/25|1500|2019/06/02|+15| |…|…|…|…|…|…|…| 注)表内の値は架空のもので曜日も考慮していません。 ・期間高値:指定した期間内の最高値 ・高値日 :期間高値を付けた日 ・期間安値:指定した期間内の最安値 ・安値日 :期間安値を付けた日 ・前日比 :テーブルB内にある最新日の終値とその前営業日の終値との比較 最終的には期間高値と期間安値を比較し、一定の条件を満たしたものを抽出したいと思ってますがまずは上の表のような全銘柄の一覧が欲しいと考えています。 何卒ご指導よろしくお願いします。
sazi

2019/06/06 14:43

create table および サンプルデータ投入データのinsert 文を質問に追記して下さい。
GARYU

2019/06/07 13:52

質問文に追記させていただきました。 分析をするうえで、「過去〇日(〇営業日)の・・・」という期間の括りはごく一部の手法を除き必須となりますので何としても身に付けたいと思ってます。 知識不足で的外れな質問をしてしまうかもしれませんが、身に付けられるようどうかご指導お願いします。
sazi

2019/06/07 14:45

実際のSQLではなく、こちらで再現するためのテストデータ用の insert into テーブル values (~ をお願いします。
GARYU

2019/06/07 15:32

すみません、初心者につき意味を理解出来ていません。 ネット上のサイトからCSVをダウンロードし自分のPCに保存してからインポートているのですが・・・。 再現していただけるとのことですので、そのサイトのアドレスという認識で良いでしょうか? こちらがcsvファイルダウンロード元になります。 http://mujinzou.com/
GARYU

2019/06/08 00:14

この中の ■データ・ダウンロード■ 内の ■当日株価データに入り、該当日をクリックcsvを取得しています。
GARYU

2019/06/10 11:20

お付き合い・ご指導ありがとうございました。 まだ望むところには辿りつけてませんが、一から違った形で考えてみます。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問