20200327のMySQLに関する記事は8件です。

後輩に毎年説明している気がするデータベースのインデックスのはなし

はじめに

いつも後輩から質問をされた場合は、面倒くさいので先人が丁寧な説明の記事を書いているので、いい感じのQiitaの記事とかを探して渡している。しかし、データベースのインデックスのはなしに関しては意外と上手く説明されている記事が無かったため、仕方がなく自分で書くことにした。

インデックスとは

インデックスとは探索木とかを使ってデータの取得を効率化しているやつのことである。
例えば以下のようなテーブル「player」があるとする。

name(名前) age(年齢) height(身長) birthday(誕生日)
Kurl 31 193 1988-04-03
Santon 29 187 1991-01-02
Taylor 34 186 1986-01-23
Tiote 34 180 1986-06-21
Anita 30 168 1989-04-04
Cabaye 34 175 1986-01-14
Obertan 31 185 1989-02-06

ここで以下のような身長が180の選手を取得するSQLを流したとする。

SELECT name FROM player WHERE height = 180;

インデックスが無い場合は全てのレコード、ここでは7つのレコードを順番に参照してheightが180のものを探してくることになる。1つのレコードを参照してheightを比較するのに1秒かかるとすると、全部で7秒かかることになる。この方式の場合、例えばレコードが1023個あった場合は1023レコードを参照する必要があり1023秒かかり、n個あった場合はnレコードを参照するのでn秒かかる計算になる。

ここで、以下のような木を用意する。すべてのノードに対して、子が存在するとき、左の子は自ノードより値が小さく、右の子は値が大きいといった感じのものだ。
def.png

ここの木を次のような使いかたをする。ノード(初回は根)の値を参照して、対象の場合は探索完了。対象の値が参照したノードより小さい場合は左のノード、大きい場合は右を参照する。実際に「height=180」を探索する場合は以下のようになる
2.png
1. 根の値は185で、探索している値の180は小さいので左のCabayeへ
2. Cabayeの値は175で、探索している値の180は大きいので右のTioteへ
3. Tioteの値は探索していた180なので終了

この方法だとどの値でも最大3回(木の深さ)の操作でレコードを取得することができ、1操作を1秒とすると3秒となる。この方法の場合だと1023レコードの場合は10秒、nレコードの場合は$log_2n$でレコードを取得することが出来る。以下のように、全探索とインデックスを利用した場合を比較すると、レコードが増えれば増えるほどインデックスを利用したほうが嬉しいことがわかる。

レコード数(個) 全探索 インデックス
1 1秒 1秒
3 3秒 2秒
7 7秒 3秒
$2^{10}-1=1023$ 1023秒=約17分 10秒
$2^{20}-1=1048575$ 1048575秒=約291時間 20秒
$2^{30}-1=1073741823$ 1073741823秒=約12427日 30秒

複合インデックス

更にインデックスは複数のカラムを対象にして作成することが出来る。たとえば(age,height)でインデックスを作成した場合は以下のように、age,heightの順に優先して値の大小を決めた木になる。まずはageで大小を決めて、ageが同じならheightで大小を決めるといった感じだ。
21.png
このような複合インデックスは例えば「age=34 AND height=180」といったレコードを探すときに有効で、まずは「age=34」で探索をした後に
22.png
「height=180」を探すといった感じになる。
23.png
複合インデックスはどのカラムが上位かが重要である。上記のインデックスの場合、たとえば「height=180」だけといった探索は、上位のageが優先でノードが並んでいるためするころができない。しかし「age=34」みたいな探索はすることができる。一般化すると、(A,B,C,D…)の順番のインデックスがある場合に、インデックスを使うことが出来るカラムの指定はA,AB,ABC,ABCD,…といった上位から順番にカラムを指定した感じで、一方それ以外のB,CとかBDといった使い方はできない。

その他

主キーには必ずインデックスができる

主キーには必ずインデックスができるよ。

全部のカラムに対してインデックスを作成すれば最強じゃん

インデックスに使われているカラムに対しての更新、レコードの追加・削除があるたびにインデックスも更新をしなくてはいけないので、それらの処理が重くなるデメリットがある。あとインデックス自体もデータなので容量を食うことも忘れずに。

数値は比較できるからインデックスを作成できるけど、文字列の場合はできないの?

文字列に対しては辞書列順などの順序を入れることが出来る。辞書に先に乗っている単語を小さいとみなす感じ。たとえば「Cabaye<Tiote」がなりたつ。日付などでも、昔のほうが小さいといった感じで比較がされている。

インデックスを使っているつもりなのに早くならないよ。

だいたい以下が原因とかで、インデックスが使えていない。

LIKEは前方一致で

文字列の部分一致で使うLIKEだが、文字列の比較に使われている辞書順は文字列の文字を先頭から順に比較するため、前方一致ではインデックスが使われるが、それ以外の場合はインデックスが使われない。

条件にORを使っている

DBがSQLを解釈してデータの取得方法を考えるときに、インデックスを使うより全探索をしたほうが早いと思ったらインデックスを使わないことがある。たとえば前に使った以下の例で「身長が168 OR 180 OR 186」の選手を探すことになったとする。
def.png
この場合に実装方法にもよるが、毎回根から対象を探そうとしたのなら9回の操作が必要になり、全探索より遅くなってしまう。そんなこんなで、条件にORを使うとDBが気を使ってあえてインデックスを使わないことがある。しかし、インデックスを使ったほうが早いと思うのなら、使っているDBのSQLにインデックスを使うことを促す文法(Oracleのヒント句とか)が用意されていればそれを用いてみたり、UNIONをつかうとインデックスを使ってくれたりする。

インデックス対象のカラムに対して関数を使っている

前述のテーブルplayerので「身長が180cm台」の選手を探したいとする。この時に整数に切り下げる関数FLOORを用いて「FLOOR(height/10)=18」といった条件で探索をするとする。このようにインデックスに使われているカラムを関数に入れてしまった場合にDBは上手く気を使ってインデックスを使ってくれたりはしない。この場合は「height>=180 AND height<190」といったようにカラムを関数に入れないような書き方を心がけよう。

暗黙の型変換を使っている

暗黙の型変換を使った場合もインデックスを使ってくれないことがある。以下のように日付型のカラムと文字列の比較をしたときに、DBが気を利かせてくれて文字列をいい感じに日付として扱ってくれたりするように、DBが優しさで良い感じに型変換を行ってくれるやつである。

SELECT * FROM player WHERE birthday = '1986-06-21';

なので、インデックスのカラムを条件に入れるときはちゃんと型変換をした形(ORACLEならTO_DATE関数など)で指定をしよう。

そもそも、暗黙の型変換はSQLを実行する環境の設定に依存してしまうため、SQLを実行する環境次第で結果が変わってしまうことがある。そのため、インデックスどうこう以前に、バグを引き起こしやすいので開発の際は使うのはやめよう。例えば日付1988年4月3日を、設定がイギリスの場合で文字列で暗黙の型変換を使おうとすると、dd-mm-yyyy形式とかになっていたりして'03-04-1988'となる。しかしながら、設定がアメリカとなってしまっていた場合はmm-dd-yyyy形式だったりして1988年3月4日と解釈されてしまったり、日本でyyyy-mm-dd形式だったりして「そんな日付ねーよ!」と怒られてしまったりする。(実際にこの暗黙の型変換とExceptionの握り潰しという2つの悲しみがあわさった悲しみを見たことがある)

まとめ

・インデックスとは探索木とかを使ってデータの取得を効率化しているやつのこと
・インデックスにはカラムの順番があるからちゃんと守ろう
・主キーには自動的にインデックスができる
・LIKEを使うときは前方一致で
・インデックスを使うときはORは慎重に、関数、暗黙の型変換は使っちゃだめだよ(そもそも暗黙の型変換はつかうな)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GoogleスプレットシートのデータをWordPressのMySQLにコピーする方法【PHPでまるっと処理】

Googleスプレットシートのデータを、WordPressのMySQLにコピーする方法を説明します。

スプレットシートのデータをWordPressのMySQLにコピーする方法

PHPファイルでまるっと処理しますが、スプレットシートを公開してJSONファイルでデータを取得可能にした上で、WordPressのサーバからJSONを取得しにいって、MySQLにデータを流し込んでいくというのが大まかな流れです。

前提(データセットとスプレットシートの下処理)

【例として扱うデータセット】
過去記事でも扱っているGoogleフォームで募った会議参加者の情報を管理することを例にあげます。

(過去記事)
Googleフォームで取得した画像をスプレットシートで表示する方法【セル内に画像で表示】

(参考)
今回扱うデータはこちらにて公開しておりますので、必要に応じてコピペして使ってください。データセットとして{image, name, birthplace, performance}の4つを扱います。
Screen-Shot-2019-12-08-at-19.48.57.png

WordPress側の独自テーブルの作成にあたっては、必要に応じて以下を参照してください。wp_member_listという独自テーブルを作成しています。

(その他 参考記事)
WordPressのMySQL独自テーブルの作成と利用方法【wp-db.phpの更新必須】

【スプレットシートの公開】
スプレットシートに外部からアクセスできるように公開する必要があります。(取り扱うデータの観点から、公開先を限定する必要があればSpreadSheet APIを活用してください。)

wordpress_mysql_from_spreadsheet_01.jpg

その上で、スプレットシートをJSONで取得できるURLを作成します。公開したスプレッドシートのIDを、黄色下線部の部分に指定してください。

Screen Shot 2020-03-27 at 23.53.01.png

きちんとJSON取得用のURLになっていると、ブラウザでアクセスした際にスプレットシートの結果が返ってくることが確認できます。

wordpress_mysql_from_spreadsheet_02.jpg

データをコピーするPHPスクリプト

以下のPHPコードにて、スプレットシートからデータ取得を行って、MySQLへデータを格納します。

sample.php
<?php

require_once(dirname(__FILE__) . "../../../../wp-load.php"); //実行環境に合わせてパスを設定

// スプレットシートからJSONの値を取得
$data = "https://spreadsheets.google.com/feeds/list/1SZCuyk2H7FBOxoeLp93imOlUxjBu2gBFhUpHk_PVaBc/od6/public/values?alt=json";
$json = file_get_contents($data);
$json_decode = json_decode($json);
$names = $json_decode->feed->entry;

global $wpdb;

// スプレットシートの行ごとに処理を繰り返す
foreach ($names as $name) {

    // JSONからそれぞれの値を取り出す
    $m_image = $name->{'gsx$image'}->{'$t'};
    $m_name = $name->{'gsx$name'}->{'$t'};
    $m_birthplace = $name->{'gsx$birthplace'}->{'$t'};
    $m_performance = $name->{'gsx$performance'}->{'$t'};

    // JSONから取り出した値を独自テーブル(member_list)へinsertする
    $wpdb->insert($wpdb->member_list, array(
        'image' => $m_image,
        'name' => $m_name,
        'birthplace' => $m_birthplace,
        'performance' => $m_performance
        ), array('%s', '%s', '%s','%s',));
}
return;

正しく実行できていれば、準備しておいた独自テーブル(WordPressのホスティングサーバのMySQL内)の中に、スプレットシートから取得したデータが格納されていることが確認できると思います。

b_spreadsheet_demo_insert.php_03.jpg

上手くいかない場合は、スプレットシートの公開設定や過去記事に記載したWordPressのMySQLで独自テーブルを設定する方法について確認してみてくださいね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WordPressのMySQL独自テーブルの作成と利用方法【wp-db.phpの更新必須】

『WordPressのMySQLに独自テーブルを作りたい!!』というときに必要となる作業と、独自テーブルへの接続方法についての説明です。

WordPressのMySQL独自テーブルの作成と利用方法

ということで、早速ですがMySQLへのテーブルを用意します。

【前提(取り扱うデータ)】
過去記事でも扱っているGoogleフォームで募った会議参加者の情報を管理することを例にあげます。

(参考となる過去記事)
Googleフォームで取得した画像をスプレットシートで表示する方法【セル内に画像で表示】

管理するデータは以下になりまして、{プロフィール画像URL、名前、出身地、主な実績}をこれらを管理する独自テーブルを作ります。

Screen-Shot-2019-12-08-at-18.15.34-1024x378.png

データベースの作成とwp-db.phpの更新

早速ですが、お好きな手順で独自テーブルを作成してください。ホスティングサーバーのphpMyAdminから作るのが手っ取り早いかと思います。

【独自テーブルの追加】
デフォルトだと、wp_dbというデータベースが作成されていると思うので、その中に新しい独自テーブルとしてwp_member_listを追加しました。

wordpress_mysql_original_table_01.jpg

wp_の部分はプレフィックス(接頭辞)となりまして、他のテーブルの前にも規則的なプレフィックスがついていると思うので、そちらに合わせて独自テーブルのテーブル名の先頭に付与するようにしてください。(デフォルトではwp_になっています。)

【wp-db.phpへの独自テーブルの登録】
[WordPressフォルダ] → [wp-includesフォルダ]の中に、wp-db.phpというファイルがありまして、こちらに独自テーブルの情報を更新する必要があります。

当該のファイルを開いたら、$tablesの配列(おそらく260行目あたりにあると思います。)に独自テーブルmember_listを追加して更新してください。※この際にはプレフィックスを除いた文字列を追加するようにしてください(下記、最下行参照)。

wp-db.php
var $tables = array(
    'posts',
    'comments',
    'links',
    'options',
    'postmeta',
    'terms',
    'term_taxonomy',
    'term_relationships',
    'termmeta',
    'commentmeta',
    'products',
    'member_list', //独自テーブルを新規で追加
);

データベースへの接続

では、独自テーブルに接続できるかを確認したいと思います。疎通試験だけするスクリプトを用意しました。wordpressのテンプレートフォルダにconnection_check.phpというファイルを作っています。

私はMacでMAMP環境を整えているので、こんなパスになります。

/Applications/MAMP/htdocs/wordpress/wp-content/themes/twentytwelve/connection_check.php

【独自テーブルへの疎通確認スクリプト】
SELECT文で、データベースに繋げるかどうかを見ています。テーブルにデータが入っていなくても、データベースに接続さえできればSELECT結果0件として戻ってくるので、$wpdbの実行結果に値が入って接続成功となります。

データベースの接続にあたってWordPressの設定情報がいるのでrequire_once関数で取得しています。wp-load.phpへの相対パスはお手元の環境に合わせて修正してください。

wp-load.php
<?php

require_once(dirname(__FILE__) . "../../../../wp-load.php");

global $wpdb;
$rows = $wpdb->get_results("SELECT count(*) FROM $wpdb->member_list");

echo "<br> MySQLの独自テーブルへアクセス <br>";

if(empty($rows)){
    echo "<br> 接続失敗 <br>";
}else{
    echo "<br> 接続成功 <br>";
}

return;

【phpファイルの実行】
念の為ですが、上記の私の環境だと、phpファイルを置いたフォルダにアクセスすれば実行結果が得られます。(パスは適宜修正してください。)

http://localhost:8888/wordpress/wp-content/themes/twentytwelve/connection_check.php

その上で、以下の実行結果が返ってきたら接続に成功しています!!

MySQLの独自テーブルへアクセス
接続成功


とうことで、WordPressのMySQL独自テーブルの作成と接続方法についての説明でした。wp-db.phpの更新を忘れると、永遠に接続できないので注意してくださいね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【MySQL】再インストールしても、諸々エラーが発生する時に確認して欲しいこと。

はじめに

mysql8→5.7に切り替える際に、

.. ERROR! The server quit without updating PID file (/usr/local/var/mysql/MacBookPro.local.pid).

やたらとこのエラーに時間を使ったので、書き残しておきます。

結論

プロセスを確認して、それを殺す。

$ ps aux | grep mysql

実行後、僕の場合だと、mysql8が残ってました。
なのでそれを

$ kill -9 (プロセス番号)

これで削除。

細かいことは、よくわかりませんが、裏で前のバージョンが動いていたから、それを削除したら使えるようになるってことですかね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PDOで編集機能を実装する。

概要

PHPでバンドの管理アプリをつくる際、編集機能の実装でしばらく躓いてしまってました。
データの受け渡しの理解を深める意味で、個人用に記録として残しておきます。

ソース

Edit.php
<?php
    //CREATE_INFO(テーブル)の中身を初期値に入れ込む
    $id = $_GET['id'];
    $db = new PDO('mysql:host=localhost;dbname=SCHEDULE','root','root');
    $sql = 'SELECT * FROM CREATE_INFO WHERE id = :id';
    $stmt = $db->prepare($sql);
    $stmt -> execute([':id' => $id]);
    $result = $stmt->fetch(PDO::FETCH_OBJ);

    //更新処理
    if(isset($_POST['Band']) && ($_POST['StarTime']) && ($_POST['Song1']) && ($_POST['Song2']) && ($_POST['EndTime'])){
        $Band = $_POST['Band'];
        $StarTime = $_POST['StarTime'];
        $Song1 = $_POST['Song1'];
        $Song2 = $_POST['Song2'];
        $EndTime = $_POST['EndTime'];
        try{
            $db = new PDO('mysql:host=localhost;dbname=SCHEDULE','root','root');
            $sql = 'UPDATE CREATE_INFO SET Band = :Band, StarTime = :StarTime, Song1 = :Song1, Song2 = :Song2, EndTime = :EndTime WHERE id=:id';
            $stmt = $db->prepare($sql);
            $stmt -> execute([':Band'=> $Band,':StarTime'=> $StarTime,':Song1'=> $Song1,':Song2'=> $Song2,':EndTime'=> $EndTime, ':id'=> $id ]);
            $result = $stmt->fetchAll(PDO::FETCH_OBJ);
            header('Location: http://192.168.33.10/AdjusTime/Schedule.php');
            exit;    
        }catch(PDOException $e){
            echo $e->getMessage();
            exit;
        }
    }
?>

実行結果をfetchで受け取るのか、fetchAllで受け取るのかで「?」でした。

・fetchで受け取る=データを一行ずつ取得。
・fetchAllで受け取る=全データを配列に変換。全ての結果行を含む配列を返す。

そりゃデータが複数あったら配列にしないと取得できませんわな()
以下、html部分。

Edit.php
<html>

<head>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
</head>

<div class="container">
    <div class="card-header">
       <h2 class="head-edit">バンド編集</h2>
    </div>
    <div class="card-body">
        <form action="" method="POST">
            <!-- <div class="form-group">
                No
                <input type="text" name="id" class="form-control">
            </div> -->
            <div class="form-group">
                バンド名
                <input value="<?= $result->Band; ?>" type="text" name="Band" class="form-control">
            </div>
            <div class="form-group">
                開始時刻
                <input value="<?= $result->StarTime; ?>" type="text" name="StarTime" class="form-control">
            </div>
            <div class="form-group">
                曲1
                <input value="<?= $result->Song1; ?>" type="text" name="Song1" class="form-control">
            </div>
            <div class="form-group">
                曲2
                <input value="<?= $result->Song2; ?>" type="text" name="Song2" class="form-control">
            </div>
            <div class="form-group">
                終了時刻
                <input value="<?= $result->EndTime; ?>" type="text" name="EndTime" class="form-control">
            </div>

            <div class="col-12 clearfix">
                <div class="float-right test-box">
                    <div class="btn-toolbar mb-3" role="toolbar">
                        <div class="btn-group mr-2" role="group">
                            <button type="button" class="btn btn-primary" onclick="history.back()">戻る</button>
                        </div>
                        <div class="input-group">
                            <button type="submit" href="Schedule.php<? $result['id'] ?>" name="btnSend" class="btn btn-danger">決定</button>
                        </div>
                    </div>
                </div>
            </div>
        </form>
    </div>
</div>

</html>

PDO::FETCH_OBJのおかげで楽に実装できています。
コード自体相当汚いと思いますが、かなり直感的に実装できました。

しかし、詰まったのは、

<div class="input-group">
   <button type="submit" href="Schedule.php<? $result['id'] ?>" name="btnSend" class="btn btn-danger">決定</button>
</div>

この部分です。DBの$resultの部分、こんな書き方できるんですね。(超初歩)
ここの書き方が分からず仕舞いで数日調べまくってました、、、笑

まとめ

・データを複数件fetchするときはfetchAll。
・テーブルのキーを受け取って全体を表示する。

勉強になりました。プログラムおもしろい!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

vagrant(CentOS7)環境でrails6 + MySQLの環境構築(半分は自分メモ)

はじめに

今回の投稿が初投稿になります。至らない点が多々あるかと思いますが参考にしていただけると幸いです。
最後の方がグダグダしてたりするのでご了承ください。
また、VirtualBox + Vagrantは始めから入っている状態から入っている前提でお話しさせていただきます。

こちらの記事を参考にさせていただきました。
Windows 10 + VirtualBox + Vagrant + CentOS + Rails で、”Yay! You’re on Rails!”まで

環境

ホストos
・windous10 pro
・Vagrant 2.2.6

ゲストos
・centos7
・ruby 2.7.0
・rails 6.0.2.2

ホストOSでの準備

はじめに、vagrantがはいっているか確認します。

C:\Users\hogetarou\vagrant>vagrant --version
Vagrant 2.2.6

続いて作業用のディレクトリを作っていきます。

C:\Users\hogetarou\vagrant>mkdir rails
C:\Users\hogetarou\vagrant>cd rails
C:\Users\hogetarou\vagrant\rails>vagrant box add centos/7
==> box: Loading metadata for box 'centos/7'
    box: URL: https://vagrantcloud.com/centos/7
This box can work with multiple providers! The providers that it
can work with are listed below. Please review the list and choose
the provider you will be working with.

1) hyperv
2) libvirt
3) virtualbox
4) vmware_desktop

Enter your choice: 3
==> box: Adding box 'centos/7' (v1905.1) for provider: virtualbox
The box you're attempting to add already exists. Remove it before
adding it again or add it with the `--force` flag.

Name: centos/7
Provider: virtualbox
Version: 1905.1

C:\Users\hogetarou\vagrant\rails>vagrant box list
centos/7 (virtualbox, 1905.1)

box listにcentos/7が追加されていたら問題ないです。

C:\Users\hogetarou\vagrant\rails>vagrant init centos/7

このコマンドでディレクトリの中にVagrantfileが作成されていますので設定します。
33行目あたりに
config.vm.network "private_network", ip: "192.168.33.10"
があるのでコメントアウトを外してください。

終わったら仮想環境を立ち上げてsshで仮想環境に入ります。

C:\Users\hogetarou\vagrant\rails>vagrant up
...
...結構長いです
...
C:\Users\hogetarou\vagrant\rails>vagrant ssh
[vagrant@localhost ~]$

ゲストOSでの作業

rbenvのインストール

gitをインストールしてからいろいろ持ってきます。

$ sudo yum install -y git

$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ source ~/.bash_profile

ruby-buildのインストール

$ git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
$ cd ~/.rbenv/plugins/ruby-build
$ sudo ./install.sh

rbenvの確認

$ rbenv -v
rbenv 1.1.2-28-gc2cfbd1

必要なパッケージをインストール

$ sudo yum install -y openssl-devel readline-devel zlib-devel mysql-devel gcc gcc-c++
$ sudo yum install -y epel-release
$ sudo yum install -y nodejs --enablerepo=epel

rbenvを使ってrubyをインストール

初めどのバージョンがインストールできるか確認します。

$ rbenv install -l
...
2.7.0-dev
2.7.0-preview1
2.7.0-preview2
2.7.0-preview3
2.7.0-rc1
2.7.0-rc2
2.7.0
2.8.0-dev
jruby-1.5.6
jruby-1.6.3
...

今回はruby2.7.0をインストールします。
注釈 このインストールは長いです!!何も反応がありませんが、ちゃんと動いてます!待ってあげて!

$ rbenv install 2.7.0

rubyを設定します。

$ rbenv rehash
$ rbenv global 2.7.0

バージョンの確認

$ ruby -v
ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-linux]

railsをインストール

バージョンを指定するときは
$ gem install -v 6.0.0 rails
みたいな感じで指定可能です。

$ gem install rails

バージョンの確認

$ rails -v
Rails 6.0.2.2

DB(MySQL)をインストール

npmとnode.jsがしっかりとインストールされているか確認

$ npm -v
3.10.10
$ node -v
v6.17.1

mariaDBが入っている可能性があるので念のため削除

$ sudo yum remove mariadb-libs
$ sudo rm -rf /var/lib/mysql/

MySQLの公式のyumリポジトリを追加。
そしてインストール。確認もしましょう。

$ sudo yum localinstall http://dev.mysql.com/get/mysql57-community-release-el7-7.noarch.rpm
...
...もろもろ

$ sudo yum -y install mysql-community-server
...
...もろもろ

$ sudo mysqld --version
mysqld  Ver 5.7.29 for Linux on x86_64 (MySQL Community Server (GPL))

一行目のコマンドでCentOS起動の際自動で起動してくれるようになります。
MySQLserver起動

$ sudo systemctl enable mysqld.service
$ sudo systemctl start mysqld.service

止めるときはこれ
今回は使わない予定。

$ sudo systemctl stop mysqld.service

続いてuserとデータベースを作っていきます。

$ mysql -u root
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)

ぬは。パスワードが無いって怒ってますね。
ってことでパスワードを探してログインします。

$ sudo  cat /var/log/mysqld.log | grep root
2020-03-26T14:23:10.121821Z 1 [Note] A temporary password is generated for root@localhost: あなたのパスワード

ps.私のパスワードの最後の文字が > でそれがパスワードの一部だと気づかないで結構な時間取られました。

そしてログイン

$ mysql -u root -p
Enter password: あなたのパスワード

初めにrootのパスワードを変えていきます。
パスワードですが8文字以上、英数大文字小文字と記号を使わないと、パスワードポリシーエラーになります。
例)Hogetarou<<0327

mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'パスワード';

そして、userを作っていきます。
ここで作ったユーザー名とパスワードは後で使います!!!!!

mysql> create user 'ユーザー名'@'localhost' identified by 'パスワード(rootと別)';

最後に確認します。waninokoが私です。

mysql> select User,Host from mysql.user;
+---------------+-----------+
| User          | Host      |
+---------------+-----------+
| mysql.session | localhost |
| mysql.sys     | localhost |
| root          | localhost |
| waninoko      | localhost |
+---------------+-----------+
4 rows in set (0.00 sec)

railsアプリ作成

$ rails new sample -d mysql

赤字でなんか文句言われました。
要するに、必要なgemが足りないって言ってきてます。

An error occurred while installing mysql2 (0.5.3), and Bundler cannot continue.
Make sure that `gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'` succeeds before bundling.

In Gemfile:
  mysql2
         run  bundle binstubs bundler
Could not find gem 'mysql2 (>= 0.4.4)' in any of the gem sources listed in your Gemfile.
         run  bundle exec spring binstub --all
bundler: command not found: spring
Install missing gem executables with `bundle install`
       rails  webpacker:install
Could not find gem 'mysql2 (>= 0.4.4)' in any of the gem sources listed in your Gemfile.
Run `bundle install` to install missing gems.

さっき作成アプリケーションのディレクトリに移動してインストールします。

$ sudo yum install mysql-devel

終わったらgemfileのインストール

$ bundle

yarnをインストール

こちらを参考にさせていただきました。
ruby on rails 環境をセットアップするときの自分メモ

$ sudo yum remove nodejs npm #古いのが入っていれば削除
$ curl --silent --location https://rpm.nodesource.com/setup_10.x | sudo bash -
$ sudo yum install -y nodejs
$ sudo npm install yarn -g

webpackerをインストール

bundle exec rails webpacker:install

nodeのバージョンエラーになる場合はこちらを実行してまたwebpakerをインストール

$ sudo npm install -g n
$ sudo n 9.11.2

これでとりあえずrails serverは問題なく起動するようになりました。
ここからデータベースの設定をしていきます。あと少しですw

database.ymlの設定とDBの作成

先ほど控えたDBのユーザー名とパスワードを書きます。
僕はatomのremote-ftpを使いましたが、viが書ける人はそちらを使ってもらって大丈夫です。

/config/database.yml
...
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: ユーザー名
  password: パスワード
  host: localhost
  socket: /var/lib/mysql/mysql.sock
...

続いてデータベースを作っていきます。

$ rails db:create
...
...
...
Created database 'sample_development'
Created database 'sample_test'

これでデータベースは完成!!!!
rails serverを起動

$ rails s -b 192.168.33.10
...
...
* Listening on tcp://192.168.33.10:3000
Use Ctrl-C to stop

最後にホストOS側のブラウザからアクセスして終わりです。お疲れさまでした。
http://192.168.33.10:3000/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MySQL テーブルのカラムを出力しようとした時にエラーが出た話

目的

  • laravelのマイグレーションファイルを使用してとあるテーブルにカラム追加したものを確認しようとしたらエラーが発生し解決した話をまとめる

実施環境

  • ハードウェア環境
項目 情報 備考
OS macOS Catalina(10.15.3)
ハードウェア MacBook Air (11-inch ,2012)
プロセッサ 1.7 GHz デュアルコアIntel Core i5
メモリ 8 GB 1600 MHz DDR3
グラフィックス Intel HD Graphics 4000 1536 MB
  • ソフトウェア環境
項目 情報 備考
PHP バージョン 7.4.3 Homwbrewを用いて導入
Laravel バージョン 7.0.8 commposerを用いて導入
MySQLバージョン 8.0.19 for osx10.13 on x86_64 Homwbrewを用いて導入

エラー内容

  • MySQLのコマンドラインにて下記のコマンドを実行したとこ「ERROR 1046 (3D000): No database selected」が出力された。

    mysql> show columns from テーブル名;
    

原因

  • エラーメッセージにもある様にデータベース名を指定せずにテーブル名のみを指定したためエラーが発生している。

解決方法

  1. コマンドhow columnsの実行時にデータベース名も指定して実行する。
  2. MySQLのコマンドラインでhow columnsを実行する際の例を下記に記載する。

    mysql> how columns from データベース名.テーブル名
    
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MySQL の CASE 文中で書式の違う時刻を比較してはならぬ

現象

実行環境
OS: Ubuntu 18.04.1 LTS
MySQL: 5.7.29

mysql> SELECT CASE WHEN '2020-03-27 00:00:00' < '2020-1-1 0:0:0' THEN 'そうです(大嘘)' ELSE 'んなわけないでしょ……' END AS '2020年1月1日は 2020年3月27日より未来?';
--------------
SELECT CASE WHEN '2020-03-27 00:00:00' < '2020-1-1 0:0:0' THEN 'そうです(大嘘)' ELSE 'んなわけないでしょ……' END AS '2020年1月1日は 2020年3月27日より未来?'
--------------

+----------------------------------------------------+
| 202011日は 2020327日より未来?             |
+----------------------------------------------------+
| そうです(大嘘)                                   |
+----------------------------------------------------+
1 row in set (0.00 sec)

ファッッッッッッ?????!!!??!!!??!!!?!!?!!?!??!?!?!!!??

書式を合わせて再実行

上記の SQL をよく見てみると、比較している日付の書式が 2020-03-27 00:00:002020-1-1 0:0:0 で書式が違っています。
試しに 2020-1-1 0:0:0 の方を MySQL の推奨形式である YYYY-mm-dd HH:ii:ss 形式(自称 山田ヒステリック形式)に変えて実行してしましょう。

mysql> SELECT CASE WHEN '2020-03-27 00:00:00' < '2020-01-01 00:00:00' THEN 'そうです(大嘘)' ELSE 'んなわけないでしょ……' END AS '2020年1月1日は 2020年3月27日より未来?';
--------------
SELECT CASE WHEN '2020-03-27 00:00:00' < '2020-01-01 00:00:00' THEN 'そうです(大嘘)' ELSE 'んなわけないでしょ……' END AS '2020年1月1日は 2020年3月27日より未来?'
--------------

+----------------------------------------------------+
| 202011日は 2020327日より未来?             |
+----------------------------------------------------+
| んなわけないでしょ……                               |
+----------------------------------------------------+
1 row in set (0.00 sec)

期待通りの動作になりました。

書式を合わせずに UNIX_TIMESTAMP() を挟んで再実行

MySQL には時刻の文字列をタイムスタンプに変換できる UNIX_TIMESTAMP 関数が存在するので、書式の違う両者日時文字列を変換した上で再実行してみましょう。

mysql> SELECT CASE WHEN UNIX_TIMESTAMP('2020-03-27 00:00:00') < UNIX_TIMESTAMP('2020-01-01 00:00:00') THEN 'そうです(大嘘)' ELSE 'んなわけないでしょ……' END AS '2020年1月1日は 2020年3月27日より未来?';
--------------
SELECT CASE WHEN UNIX_TIMESTAMP('2020-03-27 00:00:00') < UNIX_TIMESTAMP('2020-01-01 00:00:00') THEN 'そうです(大嘘)' ELSE 'んなわけないでしょ……' END AS '2020年1月1日は 2020年3月27日より未来?'
--------------

+----------------------------------------------------+
| 202011日は 2020327日より未来?             |
+----------------------------------------------------+
| んなわけないでしょ……                               |
+----------------------------------------------------+
1 row in set (0.00 sec)

これも期待通りですね。アプリケーション側での対処が難しい場合はこちらで解決してもいいかもしれません。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む