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

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

ただいまの
回答率

90.35%

  • MySQL

    7416questions

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

別テーブルから出てきた検索結果を用いて別のテーブルにinsertしたい

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 113

miya71ma

score 43

システム概要

csvで株価一覧をダウンロードしてくる(人が作業)
phpのページを使ってDBにインサートする

php別ページで条件に合う株銘柄があるかを検索したい
その際に検索条件が4日間"today_close "-"today_open ">0のものとしたい
この場合SQLで別テーブルに4日連続"today_close "-"today_open ">0であるかどうかをbooleanで入れておいて検索時にそちらを参照する形がいいと思っているのですがそれができずに困っています

<?php
/* HTML特殊文字をエスケープする関数 */
function h($str) {
    return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}
$double_array = [6,7,8,9,10,11,12,13,14,15,16,17,18,20,21,23,24];
// パラメータを正しい構造で受け取った時のみ実行
if (isset($_FILES['upfile']['error']) && is_int($_FILES['upfile']['error'])) {
    try {
        /* ファイルアップロードエラーチェック */
        switch ($_FILES['upfile']['error']) {
            case UPLOAD_ERR_OK:
                // エラー無し
                break;
            case UPLOAD_ERR_NO_FILE:
                // ファイル未選択
                throw new RuntimeException('File is not selected');
            case UPLOAD_ERR_INI_SIZE:
            case UPLOAD_ERR_FORM_SIZE:
                // 許可サイズを超過
                throw new RuntimeException('File is too large');
            default:
                throw new RuntimeException('Unknown error');
        }
        $tmp_name = $_FILES['upfile']['tmp_name'];
        $detect_order = 'ASCII,JIS,UTF-8,CP51932,SJIS-win';
        setlocale(LC_ALL, 'ja_JP.UTF-8');
        /* 文字コードを変換してファイルを置換 */
        $buffer = file_get_contents($tmp_name);
        if (!$encoding = mb_detect_encoding($buffer, $detect_order, true)) {
            // 文字コードの自動判定に失敗
            unset($buffer);
            throw new RuntimeException('Character set detection failed');
        }
        file_put_contents($tmp_name, mb_convert_encoding($buffer, 'UTF-8', $encoding));
        unset($buffer);
        /* データベースに接続 */
        $pdo = new PDO(
            'mysql:dbname=DB名;host=localhost;charset=UTF8',
            'root',
            '',
            array(
                // カラム型に合わない値がINSERTされようとしたときSQLエラーとする
                PDO::MYSQL_ATTR_INIT_COMMAND => "SET SESSION sql_mode='TRADITIONAL'",
                // SQLエラー発生時にPDOExceptionをスローさせる
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                // プリペアドステートメントのエミュレーションを無効化する
                PDO::ATTR_EMULATE_PREPARES => false,
            )
        );

        $stmt = $pdo->prepare('INSERT INTO tableA VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
        /* トランザクション処理 */
        $pdo->beginTransaction();
        try {
            $fp = fopen($tmp_name, 'rb');
            while (($row = fgetcsv($fp)) !== FALSE) {
        if ($row === array(null)) {
            // 空行はスキップ
            continue;
        }
        //print_r($row[1]);
        /*ここに"-"が格納されていた場合の処理を記載する*/
        for($i = 0; $i < 25; $i++){
            if(strcmp($row[$i],'-') == 0){
                //var_dump($row[1]);
                $st = $pdo->prepare('SELECT * FROM tableA where SC = ? ORDER BY date DESC LIMIT 1');

                if($st->rowCount() === 0){
                    if(in_array($i,$double_array)){
                        $row[$i]=0;
                        //var_dump($row[$i]);
                    }else{
                        $row[$i]=NULL;
                        //var_dump($row[$i]);
                    } 
                }else{
                    while($ro = $st -> fetch(PDO::FETCH_ASSOC)){
                        //一日前のデータを入れる
                    }
                }

            }else{
                //var_dump($row[$i]);
            }
        }
                if (count($row) > 10000) {
                    // カラム数が異なる無効なフォーマット
                    throw new RuntimeException('Invalid column detected');
                }
                $executed = $stmt->execute($row);
            }
            if (!feof($fp)) {
                // ファイルポインタが終端に達していなければエラー
                throw new RuntimeException('CSV parsing error');
            }
            fclose($fp);
            $pdo->commit();
        } catch (Exception $e) {
            fclose($fp);
            $pdo->rollBack();
            throw $e;
        }
        /* 結果メッセージをセット */
        if (isset($executed)) {
            // 1回以上実行された
            $msg = array('green', 'Import successful');
        } else {
            // 1回も実行されなかった
            $msg = array('black', 'There were nothing to import');
        }
    } catch (Exception $e) {
        /* エラーメッセージをセット */
        $msg = array('red', $e->getMessage());
    }
}
// XHTMLとしてブラウザに認識させる
// (IE8以下はサポート対象外w)
header('Content-Type: application/xhtml+xml; charset=utf-8');
?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>CSV to MySQL importation test</title>
</head>
<body>
<?php if (isset($msg)): ?>
  <fieldset>
    <legend>Result</legend>
    <span style="color:<?=h($msg[0])?>;"><?=h($msg[1])?></span>
  </fieldset>
<?php endif; ?>
  <form enctype="multipart/form-data" method="post" action="">
    <fieldset>
      <legend>Select File</legend>
      Filename(CSV is only supported): <input type="file" name="upfile" /><br />
      <input type="submit" value="Upload" />
    </fieldset>
  </form>
</body>
</html>
CREATE TABLE tableA(
    SC int(4) NOT NULL "証券コード",
    name varchar(32) NOT NULL "会社名",
    market varchar(16) NOT NULL "市場",
    industry varchar(16) NOT NULL "産業",
    date datetime NOT NULL "日にち",
    today_close double "当日終値",
    the_day_before_ratio double "前日との幅",
    the_day_before_ratio_per double "前日幅%",
    ago_close double "前日終値",
    today_open double "始値",
    today_high double "高値",
    today_low double "安値",
    vwap double "vwap",
    volume double "出来高",
    volume_per double "出来高%",
    trading_value double "売買代金",
    market_capitalization double "時価総額",
    price_range_low_limit double "値幅下限",
    price_range_high_limit double "値幅上限",
    high_date datetime "高値日",
    year_to_date_high_price double "年初来高値",
    year_to_date_high_price_deviation_rate double "年初来高値乖離",
    low_date datetime "安値日",
    year_to_date_low_price double "年初来安値",
    year_to_date_low_price_deviation_rate double  "年初来安値乖離"   
);

やったこと

delimiter //
CREATE PROCEDURE white()
BEGIN
    DECLARE @count INT
    SET @count = 1000

    WHILE (@count < 9999)
        SELECT today_close-ago_close into @is_white WHERE SC = @count ORDER BY date DESC LIMIT 4
             CASE
                 WHEN @is_white>0 THEN INSERT INTO tableB (SC,is_white) VALUES (@count,true) ON DUPLICATE KEY UPDATE @is_white = true
                 WHEN @is_white<=0 THEN INSERT INTO tableB (SC,is_white) VALUES (@count,false) ON DUPLICATE KEY UPDATE @is_white = false
              END
END
CALL white();
delimiter;

エラー

`1064 - SQL構文エラーです。バージョンに対応するマニュアルを参照して正しい構文を確認してください。 : '@is_white double     DECLARE @counter INT         SET @counter =0

    WHILE(@coun' 付近 3 行目`

やりたいこと

tableA

SC today_close ago_close date
1000 100 94 2019/06/20/15:00
2000 150 179 2019/06/20/15:00
3000 347 344 2019/06/20/15:00
1000 93 88 2019/06/19/15:00
2000 179 175 2019/06/19/15:00
3000 347 341 2019/06/19/15:00
1000 86 74 2019/06/18/15:00
2000 173 160 2019/06/18/15:00
3000 344 321 2019/06/18/15:00
1000 77 71 2019/06/17/15:00
2000 160 164 2019/06/17/15:00
3000 340 300 2019/06/17/15:00

のようにデータがtableAに格納されていて
SC=1000はtoday_close-ago_close>0が17~20日において全てtrue
SC=2000はtoday_close-ago_close>0が17~20日において一部false
SC=3000はtoday_close-ago_close>0が17~20日において全てtrue

なので
tableB

SC is_white date
1000 true 2019/06/20/15:00
2000 false 2019/06/20/15:00
3000 true 2019/06/20/15:00

としたいです

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+1

ある基準日から過去4日間の全てが today_close > today_open であるような銘柄、ですよね。
today_close > today_open であり、日付が日付1~日付2(4日間。ただし営業日で換算しないとダメ)の間にあるデータを探し、その個数が 4 であるもののみを抽出すればよい、のかな……

SELECT
  sc
FROM
  tableA
WHERE
  today_close > today_open AND
  date between 日付1 AND 日付2
GROUP BY
  sc
HAVING count(*) = 4


で対象の sc が取れますけど、これではダメですかね?

※この方式なら、「何日間」を可変にできますね

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/06/20 12:04

    これで取得できましたがfor文で回すなどどうすればいいのでしょうか...

    キャンセル

  • 2019/06/20 13:05

    検索が一発でできるので、tableB は不要になります。ですのでこの結果を php の別ページで使いたければ、PHP からこの SQL を投げて結果を fetch すればよいのでは?

    キャンセル

  • 2019/06/20 13:11

    確かにその通りですね!ほかにも検索条件があってこうしなきゃと頭固くなってました!試行錯誤してみます!ありがとうございます

    キャンセル

+1

もっと問題点を絞り込んで質問したほうがよいでしょう

・4日間"today_close "-"today_open ">0の銘柄を拾うという命題ですね?

today_openと前日のtoday_closeは一緒なのでしょうか?
today_openが前日のtoday_closeより100円高く、当日50円しか下がらなければ
昨日よりは値上がりした銘柄になり、4日続落とはなりませんが大丈夫ですか?

また基準日を指定する必要があると思うのですが、

  • 4日さかのぼるのか
  • 4日後までなのか
  • 基準日を含む4日間なのか

などイメージがわきません

ざっくりいらないデータを削って

CREATE TABLE tbl(
SC int(4) NOT NULL,
`date` datetime NOT NULL,
today_close double,
today_open double);


に対して、2~3社、1週間分程度サンプルをあげてどこをどうひっかけたいか例示されるとよいでしょう

追記

連続性についてはロジックがかなり煩雑になるので
期間を入れることで対応してください
以下サンプル

  • 元データ
CREATE TABLE tbl(
SC int(4) NOT NULL,
today_close double,
today_open double,
`date` datetime NOT NULL
);

insert into tbl values
(1000,100,94,'2019-06-20 15:00'),
(2000,150,179,'2019-06-20 15:00'),
(3000,347,344,'2019-06-20 15:00'),
(1000,93,88,'2019-06-19 15:00'),
(2000,179,175,'2019-06-19 15:00'),
(3000,347,341,'2019-06-19 15:00'),
(1000,86,74,'2019-06-18 15:00'),
(2000,173,160,'2019-06-18 15:00'),
(3000,344,321,'2019-06-18 15:00'),
(1000,77,71,'2019-06-17 15:00'),
(2000,160,164,'2019-06-17 15:00'),
(3000,340,300,'2019-06-17 15:00');
  • 検索
select sc
,group_concat(today_close order by date desc)=group_concat(today_close order by today_close desc) as is_down
,max(date) as date
from tbl
where `date` between '2019-06-17 00:00:00' and '2019-06-20 23:59:59'
group by sc


※注意:datetimeのbetweenは00:00:00~23:59:59を指定すること

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/06/20 10:59

    すみません...
    >>today_openと前日のtoday_closeは一緒なのでしょうか?
      いいえ、異なる場合があるので検索結果は4日+1である必要があると思っていましたが続落かどうかの判定は確かにおっしゃる通りなので質問文を訂正させていただきます

    キャンセル

  • 2019/06/20 13:23

    追記しておきました
    group_concatの裏技みたいな感じで処理するとよいでしょう

    キャンセル

  • 2019/06/20 14:25

    ありがとうございます!
    初めてみたので調べてかみ砕いてみます..

    キャンセル

+1

構文的に間違えているというエラーです。

それを解消してからの話だと思えます。

valuesで指定するなら変数か値です。変数の場合は@変数名としてしなければなりません。
いきなりVALUES (SC,true)だとSCの参照先などはないのですからエラーでしょうね。
やるなら、VALUES (@count,true)だと思いますけど。

また、SELECT の結果を変数に代入したいなら

select today_close-today_open into @is_white


先ずは基本的なところを押さえてからですね。

また、selectの結果についての処理をループで行いたいなら、カーソル使うのが一般的です。

質問の内容だけなら、insert into select 構文でループなど使用せずにSQL1文で可能だと思いますが。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/06/20 12:03

    ご指摘後最もでした...ですが'SET @count = 1000' にエラーが出てるんですよね...

    キャンセル

  • 2019/06/20 12:27 編集

    どのようなエラーですか?

    キャンセル

  • 2019/06/20 12:36

    1064 - SQL構文エラーです。バージョンに対応するマニュアルを参照して正しい構文を確認してください。 : '@is_white double DECLARE @counter INT SET @counter =0
    WHILE(@coun' 付近 3 行目`
    と出ています

    キャンセル

  • 2019/06/20 12:40

    DECLAREの前で変数宣言しているから。
    マニュアル読む癖付けないと駄目ですよ。

    キャンセル

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

  • ただいまの回答率 90.35%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • MySQL

    7416questions

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