20200329のMySQLに関する記事は15件です。

組み込み系からWeb系へのスキルチェンジ【随時更新】

はじめに

組み込みの開発しかほぼしたことしかない中で、Web系のスキルを身に着けるためにやったことをメモっておきます。

現状のWeb系のスキル。

  • Perl/PHP/javascript/HTML5:ちょっと使えるレベル
  • セキュアド:取得済
  • ネスペ:一通り勉強はした(受かってはいない)
  • github/Slack:プライベートで少し使ってるレベル(業務?シャガイノサービスナンテシヨウキンシデスヨ)

書籍

  1. TECHNICAL MASTER はじめてのPHPプロフェッショナル開発 PHP7対応 :チーム開発に即した形(もちろん会社やプロジェクトにもよるだろうけど)で書かれてたので、PLをやるのに役立ちそうだったので購入。推奨動作環境はMacOSで書かれています。

環境構築

手持ちがWindows10 homeしかなくDockerを入れれないので、VirtualBox+Ubuntuベースで環境構築しました。

Windows10にVirtualBoxとUbuntuをインストール

Windows10にVirtualBoxとUbuntuをインストールを参考にしました。
Ubuntuのバージョンは2020/3/22時点で最新のLSTの「Ubuntu 18.04.4 LTS」を使用しましたが、手順はほぼ一緒です。

設定変更

Docker

VirtualBox に Ubuntu 18.04 と Docker をインストールしたメモを参考にインストール。バージョンは19.03.8。

追加でdocker-composeをインストール

$ sudo apt install docker-compose

PHP

一旦、書籍1.に合わせてPHP7.2を入れる。
Ubuntu 16.04 で PHP 7.2 を使う手順

MySQL

UbuntuにMySQLをインストールを参考にインストール。
バージョンは14.14。

$ sudo apt install mysql-server mysql-client
//rootユーザ設定
$ sudo mysql_secure_installation

Visual Studio Code

簡単にUbuntuにVSCode (Visual Studio Code) をインストールする方法を参考にインストール。
バージョンは1.43.2。

日本語化

Visual Studio Code のユーザーインタフェイス(UI) 表示を日本語にする

PHP IntelliSense

以下を参考に導入。

setting.jsonの設定は、LinuxのPHPのインストール先に合わせて以下になります。

~/.config/Code/User/setting.json
{
  "php.validate.enable": false,
  "php.suggest.basic": false,
  "php.executablePath": "/usr/bin/php"
}

うまくいかなかったとこ

Dcokerでdocker-entrypoint-initdb.dをマウントするときにPermission deniedエラーがでる。

docker-compose.ymlに以下を追加したら、エラーがでるようになった。(全文は書籍の内容なので割愛します。)

docker-compose.yml
    volumes:
      - ./Docker/mysql/sqls:/docker-entrypoint-initdb.d
$ docker-compose up
Creating network "phpbookapp_default" with the default driver
Creating php-book-app-db ... 
Creating php-book-app-db ... done
Attaching to php-book-app-db
php-book-app-db | 2020-03-29 01:19:13+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.29-1debian10 started.
php-book-app-db | 2020-03-29 01:19:13+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
php-book-app-db | 2020-03-29 01:19:13+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.29-1debian10 started.
php-book-app-db | ls: cannot open directory '/docker-entrypoint-initdb.d/': Permission denied
php-book-app-db exited with code 2

解決策

ホスト側のディレクトリにgroupとotherの読み取り・実行権限がなかったのが原因でした。。。

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

MySQLからcsvを出力する

環境

mysql : Ver 8.0.19 for Linux on x86_64 (MySQL Community Server - GPL)

SELECT文でcsvファイルを出力する

SELECT * FROM hoge INTO OUTFILE '/output/hoge.csv'
 FIELDS TERMINATED BY ','
 OPTIONALLY ENCLOSED BY '"'

dockerでMYSQLコンテナ立ち上げている場合、OUTFILEをマウント位置にすると良い

csvファイルを出力する際にエラーを吐いた場合

ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement

データの入出力エラー

MySQLの設定を確認

mysql> SELECT @@global.secure_file_priv;

+---------------------------+
| @@global.secure_file_priv |
+---------------------------+
| NULL                      |
+---------------------------+

このNULLがダメらしい

設定を変更して解決する

DockerでMySQLコンテナを立ち上げて.sqlファイルからDBを作る
立ち上げているコンテナは上の通りなので、my.cnfに以下を追記

[mysqld]
secure-file-priv = ""

コンテナ再起動で設定を反映させてると設定欄のNULLが消える

mysql> SELECT @@global.secure_file_priv;

+---------------------------+
| @@global.secure_file_priv |
+---------------------------+
|                           |
+---------------------------+

これでSELECT文でcsvファイルが吐き出せるようになっているはず

参考資料

MySQLのバージョン確認方法
MySQLのSELECT文でcsvを出力する
MySQLでCSV出力しようとしたら --secure-file-priv option のエラーになった
MySQLでCSVファイルを使って結果出力やデータ入力を行う方法

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

Rails 自作アプリへの道 Part2

Rails 自作アプリを作った時の経過をまとめていきます。

環境

OS Ruby Rails
Mac Mojave 10.14.16 2.6.3p62 6.0.2.2

参考
https://qiita.com/aplifyjp/items/ea0d9236d89fa24a7a1c

前提
環境構築済

項番1 『devise』の導入

code1.rb
# Gemfileに『devise』を追加する

$ cat Gemfile
(省略)
# gem 'bcrypt', '~> 3.1.7'

# Use Active Storage variant
# gem 'image_processing', '~> 1.2'
(省略)

$ vi Gemfile
(省略)
# gem 'bcrypt', '~> 3.1.7'
gem 'devise'
# Use Active Storage variant
# gem 'image_processing', '~> 1.2'
(省略)

$ cat Gemfile
(省略)
# gem 'bcrypt', '~> 3.1.7'
gem 'devise'
# Use Active Storage variant
# gem 'image_processing', '~> 1.2'
(省略)

$ bundle install # Gemfileに記述した『devise』をインストールする
(省略)
Using devise 4.7.1
(省略)

項番2 アプリへの『devise』の機能の導入

code2.rb
# アプリに『devise』の機能を導入する
$ rails g  devise:install
      create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================

Some setup you must do manually if you haven't yet:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

===============================================================================

項番3 モデル絡みの操作

code3.rb
#『devise』の機能を取り込んだ『Sellerモデル』の作成
$ rails g devise Seller 
      invoke  active_record
   identical    db/migrate/20200330100615_devise_create_sellers.rb
      create    app/models/seller.rb
      invoke    test_unit
      create      test/models/seller_test.rb
      create      test/fixtures/sellers.yml
      insert    app/models/seller.rb
       route  devise_for :sellers

# db/migrate/20200330100615_devise_create_sellers.rbのt.confirmableのコメントを外す
# インデックスも有効にする
$ vi db/migrate/20200330100615_devise_create_sellers.rb
$ rails db:migrate

#『Sellerモデル』に必要なカラムを追加する
$ rails g migration add_columns_to_sellers name:string admin_flag:boolean
      invoke  active_record
      create    db/migrate/20200330101922_add_columns_to_sellers.rb
$ rails db:migrate

# 初期データを作成する
$ vi db/seeds.rb
sellers = ["橋本"]
sellers.each_with_index do |user, i|
  Seller.create(
    name: "#{user}",
    email: "#{i + 1}@gamil.com",
    password: "password",
    admin_flag: true
  )
end

# 初期データを投入する
$ rails db:seed

項番4『devise』とは関係ない『controller』と『routes.rb』の操作

code4.rb
$ rails g controller Home index show
$ vi config/routes.rb
Rails.application.routes.draw do
    get 'home/index'
    get 'home/show'
end

root to: "home#index"

項番5『view』の操作

code5.rb
# 基本となる『view』の作成
$ vi app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>Ticket2App</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <header>
    <nav>
      <!-- seller_signed_in? はセラーがログインしているか調べるdeviseHelperメソッド -->
      <% if seller_signed_in? %>
        <!-- current_seller は現在ログインしているSellerオブジェクトを返すdeviseのHelperメソッド -->
        <!-- *_path Sellerモデルを作成したときに、
        deviseにより自動で作成されてますので、rails routesで確認できます -->
        Logged in as <strong><%= current_seller.email %></strong>.
        <%= link_to 'プロフィール変更', edit_seller_registration_path %> |
        <%= link_to "ログアウト", sign_out_path %>
      <% else %>
        <%= link_to "サインイン", new_seller_registration_path %> |
        <%= link_to "ログイン", new_seller_session_path %>
      <% end %>
    </nav>
  </header>

  <p class="notice"><%= notice %></p>
  <p class="alert"><%= alert %></p>
  </body>
</html>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails 自作アプリへの道 Part1

Rails 自作アプリを作った時の経過をまとめていきます。

参考:https://kitsune.blog/rails-install

環境
| 1 | 2 |
|:-:|:-:|
| | |
| | |
| | |
| OS | Mac Mojave 10.14.16 |
| Ruby | 2.6.3p62 |
| Rails | 6.0.2.2 |

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

XAMPPのphpmyadminにアクセスした時、HY000/2002が出てアクセス拒否された場合の対処

起こったこと

xmappでApacheとMySQLを起動してさてphpmyadmin/index.htmlにアクセスすると
以下みたいなエラーが出てログイン画面すら出ない状態になっていました。
今回行った対応を順に書いていきます。
※この記事ではrootユーザでのログインを行っているが実際の運用ではrootユーザではなく別のユーザを別途定義した方が無難。

えらー.png

ログイン画面を出す

デフォルトでxmappをインストールした場合、C:\xampp\phpMyAdmin\配下にconfig.inc.phpが置いてあります。
今回はその中の一部を編集する。config.inc.phpを開き、以下の項目があることを確認してください。
何も編集していない状態であればおそらく下記のような状態になっているかと思われます。(これとは違う場合もあるかもしれない)

config.inc.php
/* Authentication type and info */
$cfg['Servers'][$i]['auth_type'] = 'config';
$cfg['Servers'][$i]['user'] = 'root';
$cfg['Servers'][$i]['password'] = '';
$cfg['Servers'][$i]['extension'] = 'mysqli';
$cfg['Servers'][$i]['AllowNoPassword'] = true;
$cfg['Lang'] = '';

/* Bind to the localhost ipv4 address and tcp */
$cfg['Servers'][$i]['host'] = '127.0.0.1';
$cfg['Servers'][$i]['connect_type'] = 'tcp';

/* User for advanced features */
$cfg['Servers'][$i]['controluser'] = 'pma';
$cfg['Servers'][$i]['controlpass'] = '';

$cfg['Servers'][$i]['auth_type']は認証モードの設定でデフォルトではconfigとなっています。これをcookieと変更してください。これによって有効なMySQLユーザーをログイン画面で入力すればログインできるはずです。ついでに$cfg['Servers'][$i]['user'] = 'root';はcookieでは不要なので空文字にしてください。

config.inc.php(一部)
$cfg['Servers'][$i]['auth_type'] = 'cookie';
$cfg['Servers'][$i]['user'] = '';
$cfg['Servers'][$i]['password'] = '';

(HY000/2002): 対象のコンピューターによって拒否されたため、接続できませんでした。の対処

前述の設定をしたconfig.inc.phpを保存し、phpmyadminのページをリロードするとログイン画面が表示されるかと思います。
あらかじめ設定したrootユーザでログイン……、がっダメ!

えらー2.png

ここで小一時間詰まってしまいました。原因はおそらくhostの項目でローカルのipアドレス127.0.0.1になっているからかなと思いlocalhostに変更したりしましたが一向に解決せず。
そんな時下記の質問記事を発見しました。
xampp phpmyadmin access denied error(#2002)
どうやら、localhost:MySQLのポート番号(デフォルトでは3306?)
と記載しないといけなかったみたいです。つまり下記のように直すということですね。
※筆者のMySqlのポート番号は3306です。自分の環境に合わせたポート番号に変更してください。

config.inc.php(一部)
/* Bind to the localhost ipv4 address and tcp */
$cfg['Servers'][$i]['host'] = 'localhost:3306';

config.inc.phpを保存し、IDとパスを入力してログイン…。成功!
ログイン.png

所感

ポート番号込みで定義しないといけないというのは盲点でしたが当たり前ですね…。
とりあえずphpmyadmiにはアクセスできたので、この後は別途ユーザを作成し、
rootユーザのアクセスを制限しておく必要があるかと思います。
振り返れば簡単なことなのですがこれ調べるだけで半日終わっちゃって本来の勉強が進まない…。

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

MySQLのエラーでDjangoアプリがローカルで実行できなくなったときの話

久しぶりにDjangoのアプリケーションを立ち上げようと以下のコマンドを打ったところ
python.manage.py runserver
こんなエラーが。前は動いてたはずなのに何故
django.db.utils.OperationalError: (2003, "Can't connect to MySQL server on '127.0.0.1' ([Errno 111] Connection refused)")

MySQLの起動確認

$ mysql.server start
Starting MySQL
.... * The server quit without updating PID file (/home/linuxbrew/.linuxbrew/var/mysql/***.pid).

PIDファイルとは,Linux上であるサービスが起動したときに作成されるファイルで,プロセス番号が割り振られているらしい.サービスが動いているかどうかの判断基準になる.
***は端末名

空のPIDファイルを作ってみる

$ touch /home/linuxbrew/.linuxbrew/var/mysql/***.pid

$ mysql.server restart
 * MySQL server PID file could not be found!
Starting MySQL
.rm: cannot remove '/tmp/mysql.sock': Operation not permitted
2020-03-20T18:09:18.611443Z mysqld_safe Fatal error: Can't remove the socket file:
/tmp/mysql.sock.
Please remove the file manually and start /home/linuxbrew/.linuxbrew/Cellar/mysql/8.0.18_1/bin/mysqld_safe again;
mysqld daemon not started
 * The server quit without updating PID file (/home/linuxbrew/.linuxbrew/var/mysql/***.pid).

/tmp/mysql.sock削除&再チャレンジ

$ sudo rm /tmp/mysql.sock
$ touch /home/linuxbrew/.linuxbrew/var/mysql/***.pid
$ mysql.server restart
 * MySQL server PID file could not be found!
Starting MySQL
... *
$ mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.18 Homebrew

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

通った!

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

PHP 郵便番号と住所を検索 正規表現

郵便番号か住所で検索

コメント 2020-03-28 222803.png

内容

郵便番号または都道府県を選択し市町村を入力すると
郵便のデータが検索できます。

10件を超えた場合に”前へ”、”次へ”を押すと各々のページに飛ぶようになっています。

SQL脆弱性があると思いますが、今のところこのまま学習を進めていきます。

// 変数を設定
$post_num ='';//郵便番号
$area ='';//都道府県選択
$city ='';//市町村
$town ='';//県域
$error1 = [];//エラー文
$error2 = [];//エラー文
$user_data = [];
$abc_data = [];
$query = '';
$host = 'localhost';
$username = '';
$passwd = '';
$dbname = '';
$link= mysqli_connect($host, $username, $passwd, $dbname);
$page = 1;
$count = '';//トータル件数
$totalpage = ceil($count/ 10);//切り上げ

変数が存在するかを確認

//どちらかに値が入っていた場合
if(isset($_GET['post_num']) === true || isset($_GET['area']) === true) {
//変数を代入する
    if(isset($_GET['post_num']) === true) {
        $post_num = $_GET['post_num'];
    }
        if(isset($_GET['area']) === true) {
        $area = $_GET['area'];
    }
        if(isset($_GET['city']) === true) {
        $city = $_GET['city'];
    }
        if(isset($_GET['town']) === true) {
        $town = $_GET['town'];
    }
        if(isset($_GET['page']) === true) {
        $page = $_GET['page'];
    }
if(isset($_GET['post_num']) === true || isset($_GET['area']) === true)

このif文を書かないと空欄の状態でも変数の確認をしてしまうため、
後述のエラー文が出てしまいます

空白の削除をします

    $post_num = str_replace(array(" "," "),"", $post_num);
    $area = str_replace(array(" "," "),"", $area);
    $town = str_replace(array(" "," "),"", $town);

str_replace(array(半角、全角空白)、空、変数)となっており
変数の中の半角、全角空白を空要素と入れ替えます。つまり、空白があった場合に削除します。

エラーメッセージ

    if(empty($post_num) === true && 
    ($area === '都道府県を選択' || empty($city) === true)) {
        $error1[] = '郵便番号を入力してください';
    }else if ((preg_match('/^[0-9]{7}$/', $post_num) !== 1) && 
    ($area === '都道府県を選択' || empty($city) === true)) {
        $error1[] = '7桁の数字で入力してください';
    }else {
        print "";
    }

areaとcityの入力がしていない場合でないと条件を付けないと
2つの値が入っているときにもエラー文が出てしまう。

}else if ((preg_match('/^[0-9]{7}$/', $post_num) !== 1) && 
    ($area === '都道府県を選択' || empty($city) === true)) {
        $error1[] = '7桁の数字で入力してください';

preg_match(正規表現、文字列)で文字列が正規表現と一致しているかを
確認する
一致していれば1、していなければ0で、失敗するとfalseを返します。
正規表現は0から9までの値を7桁でとなっている。
なので、post_numが7桁の数字出なかった場合、かつareaまたはcityの
値が空だった場合にエラー文が出るようになる。
  

    if ($area === '都道府県を選択' && 
    (empty($post_num) === true ||(preg_match('/^[0-9]{7}$/', $post_num) !== 1))) {
        $error2[] = '都道府県を選択してください';
    }
    if(empty($city) === true && 
    (empty($post_num) === true ||(preg_match('/^[0-9]{7}$/', $post_num) !== 1))){
        $error2[] = '市区町村名をを入力してください';
    }

前述とほぼ同じで、post_numに値が入っている場合にはエラー分が出ないようになっています。

データベースに接続

        if(count($error1) === 0 || count($error2) === 0) {
        if($link) {
            mysqli_set_charset($link, 'utf8');
            if($post_num !== '') {
                $query = "SELECT post_num, area , city, town FROM pt_table 
                WHERE post_num = '$post_num'";

エラー文がないときに接続します。文字化けを防止でutf8で表記します。
post_numが空ではない場合にsql文を代入します。

WHERE post_num = '$post_num'";

データベースにある郵便番号の値とpost_numが同じ場合になるのが条件。

            } else {
                $limit = 10*$page-10;
                $query = "SELECT post_num, area , city, town FROM pt_table 
                WHERE (area = '$area') AND (city = '$city') LIMIT ".$limit.",10";

pageは1番最初のページ数を表しています。 LIMITは開始位置、終わりの位置までを指定。
つまり、10件ごとにページに表示します。

変数limitは0、10、20、30と増えていきます。

                $query = "SELECT post_num, area , city, town FROM pt_table 
                WHERE (area = '$area') AND (city = '$city') LIMIT ".$limit.",10";

データベースのarea,cityの値がそれぞれ一致している場合という条件。
変数limitを”$limit”と書いた場合には文字列となってしまいます。カンマで囲うと数字として扱えます。

総件数を出すために文字列を取得

                $abc = "SELECT post_num, area , city, town FROM pt_table 
                WHERE (area = '$area') AND (city = '$city')";
                $result = mysqli_query($link, $abc);
                while($row = mysqli_fetch_array($result)) {
                    $abc_data[] = $row;
                }
            } 

まず、変数queryでデータを取得しようとすると最大10件しか取得できません。理由はLIMITを使って10件ずつ取得するプログラムになっているからです。なので、別の実行データを
1行ずつ取得し、文字列にしていきます。

実行したデータを取得

$result = mysqli_query($link, $query);
          while($row = mysqli_fetch_array($result)) {
          $user_data[] = $row;
          }      

10件ずつ取得するデータを1行ずつ取得し文字列にします。

メモリを開放しデータベースから閉じる

            mysqli_free_result($result);
            mysqli_close($link);

        }else {
            echo 'DB接続失敗';
        }

    }

}

総件数

$count = count($abc_data);

ページング

    <?php if ($page > 1) { ?>   
      <a href="?page=<?php echo ($page - 1); ?>&area=<?php print $area; ?>
      &city=<?php print $city; ?>">前のページへ</a>
    <?php } ?>
    <?php if ($page < $totalpage) { ?>
      <a href="?page=<?php echo ($page + 1); ?>&area=<?php print $area; ?>
      &city=<?php print $city; ?>">次のページへ</a>
    <?php } ?>

ファイル名?post_num=&area=県名&city=市名とURLに表示させる事を目的にする。
GETで値を取得したときにはURLが表示され、その先頭は?が付きます。
現在のページが1よりも大きいは(page-1)つまり前のページにいきます。

トータルページが今のページよりも多い場合には次のページに行きます

全コード

<?php
// 変数を設定
$post_num ='';
$area ='';
$city ='';
$town ='';
$error1 = [];
$error2 = [];
$user_data = [];
$abc_data = [];
$query = '';
$host = 'localhost';
$username = 'codecamp31549';
$passwd = 'RXFXXBTL';
$dbname = 'codecamp31549';
$link= mysqli_connect($host, $username, $passwd, $dbname);
$page = 1;
$count = '';//トータル件数
$totalpage = ceil($count/ 10);//切り上げ
/*変数が存在する確認*/ 
if(isset($_GET['post_num']) === true || isset($_GET['area']) === true) {
    if(isset($_GET['post_num']) === true) {
        $post_num = $_GET['post_num'];
    }
        if(isset($_GET['area']) === true) {
        $area = $_GET['area'];
    }
        if(isset($_GET['city']) === true) {
        $city = $_GET['city'];
    }
        if(isset($_GET['town']) === true) {
        $town = $_GET['town'];
    }
        if(isset($_GET['page']) === true) {
        $page = $_GET['page'];
    }

/*空白削除*/
    $post_num = str_replace(array(" "," "),"", $post_num);
    $area = str_replace(array(" "," "),"", $area);
    $town = str_replace(array(" "," "),"", $town);

/*エラーメッセージ*/
    if(empty($post_num) === true && 
    ($area === '都道府県を選択' || empty($city) === true)) {
        $error1[] = '郵便番号を入力してください';
    }else if ((preg_match('/^[0-9]{7}$/', $post_num) !== 1) && 
    ($area === '都道府県を選択' || empty($city) === true)) {
        $error1[] = '7桁の数字で入力してください';
    }else {
        print "";
    }
    if ($area === '都道府県を選択' && 
    (empty($post_num) === true ||(preg_match('/^[0-9]{7}$/', $post_num) !== 1))) {
        $error2[] = '都道府県を選択してください';
    }
    if(empty($city) === true && 
    (empty($post_num) === true ||(preg_match('/^[0-9]{7}$/', $post_num) !== 1))){
        $error2[] = '市区町村名をを入力してください';
    }
/*データベースに接続*/ 

        if(count($error1) === 0 || count($error2) === 0) {
        if($link) {
            mysqli_set_charset($link, 'utf8');
            if($post_num !== '') {
                $query = "SELECT post_num, area , city, town FROM pt_table 
                WHERE post_num = '$post_num'";
                // var_dump($query);
            } else {
                $limit = 10*$page-10;
                $query = "SELECT post_num, area , city, town FROM pt_table 
                WHERE (area = '$area') AND (city = '$city') LIMIT ".$limit.",10";
                $abc = "SELECT post_num, area , city, town FROM pt_table 
                WHERE (area = '$area') AND (city = '$city')";
                $result = mysqli_query($link, $abc);
                while($row = mysqli_fetch_array($result)) {
                    $abc_data[] = $row;
                }
            } 
            // var_dump($query);
                $result = mysqli_query($link, $query);
                while($row = mysqli_fetch_array($result)) {
                    $user_data[] = $row;

                }
            mysqli_free_result($result);
            mysqli_close($link);

        }else {
            echo 'DB接続失敗';
        }

    }

}

$count = count($abc_data);





?>

<!DOCTYPE html>
<html lang="ja">
<head>
   <meta charset="UTF-8">
   <title>郵便</title>
</head>
<body>
    <form action="./17-6.php" method="get">
        <h1>郵便番号検索</h1>
        <h2>郵便番号から検索</h2>
        <?php print "総件数" . htmlspecialchars($count,ENT_QUOTES,'UTF-8') . "件";?>
        <input type="search" name="post_num" value="">
        <input type="submit" value="検索">
        <h2>地名から検索</h2>
        <label>都道府県を選択
            <select name="area">
                <option>都道府県を選択</option>
                <option>北海道</option>
                <option>兵庫県</option>
                <option>新潟県</option>
            </select>
        </label>
        <label>市区町村
            <input type="seach" name="city">
            <input type="submit" value="検索">
        </label>
    </form>
    <p><?php foreach($error1 as $key1 => $string1) {
                print htmlspecialchars($string1,ENT_QUOTES,'UTF-8');
            }
    ?></p>
        <p><?php foreach($error2 as $key2 => $string2) {
                print htmlspecialchars($string2,ENT_QUOTES,'UTF-8');;
            }
    ?></p>
        <?php 
    foreach($user_data as $read) {?>
        <table>
           <style type="text/css">
       table, td, th {
           border: solid black 1px;
       }
       table {
           width: 600px;
       }
       tr td {
           width: 150px;
       }
   </style>

            <tr>
                <th>郵便番号</th>
                <th>都道府県</th>
                <th>市町村</th>
                <th>町域</th>
            </tr>
            <tr>
                <td><?php print htmlspecialchars($read['post_num'],ENT_QUOTES,'UTF-8'); ?></td>
                <td><?php print htmlspecialchars($read['area'],ENT_QUOTES,'UTF-8'); ?></td>                
                <td><?php print htmlspecialchars($read['city'],ENT_QUOTES,'UTF-8'); ?></td>            
                <td><?php print htmlspecialchars($read['town'],ENT_QUOTES,'UTF-8'); ?></td>            
            </tr>
        </table>
    <?php } ?>  
<p>
    <!--GETを使用するときは?からスタートする-->
    <?php if ($page > 1) : ?>   
      <a href="?page=<?php echo ($page - 1); ?>&area=<?php print $area; ?>
      &city=<?php print $city; ?>">前のページへ</a>
    <?php endif; ?>
    <?php if ($page < $totalpage) : ?>
      <a href="?page=<?php echo ($page + 1); ?>&area=<?php print $area; ?>
      &city=<?php print $city; ?>">次のページへ</a>
    <?php endif; ?>

  </p>    

</body>

</html>   

```php


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

README データベース設計

マークダウンで記述します。
自分の勉強用でメモします。
初学者の方は参考にしてください。

以下のようなテーブルを作成したとします。

usersテーブル   

Column Type Options
name string null: false, add_index: true
email string null: false, unique: true
password string null: false
password confirmation string null: false

意味を下記に記述した。

↓↓したのusersテーブルはテーブル名を記述する。
usersテーブル これはコメントアウトする。

↓↓ここはテンプレートで大丈夫です。  
|Column|Type|Options|
|------|----|-------|

|❶name|❷string|❸null: false, ❹add_index: true|

❶name

❶nameはカラム名。
そのカラムの名前。

❷string

❷stringはデータ型です。
種類は以下のようにあります。

string 文字列型
text テキスト(不定長文字列)型
integer 整数型
float 浮動小数点数型
decimal 固定長整数型
datetime 日時型
timestamp タイムスタンプ型
time 時刻型
date 日付型
binary バイナリ文字列型
boolean 真偽値型
references 他のテーブルへの外部キーの定義、_id が付いた整数などがあります。

❸null: false

❸null: false カラムにnullを許可しない
カラムのオプションです!!
NULLとは(空の値)のこと。
(null false制約など)
以下があります。

❹Usersテーブルのnameカラムにindexを張ることで、アルファベット順にnameを並べ替え検索しやすいようにしてくれます。

null: false カラムにnullを許可しない
unique: true カラムに同じ値を許可しない
foreign_key: true 他のテーブルへの外部キー制約をつける indexも自動付与
default: "oooooo" カラムに値が設定されなかった場合にデフォルトで格納される値を設定。
limit: 50 データ型の最大幅を指定。
対象となるデータ型は文字列タイプはstring型とtext型の2つ、数値タイプはinteger型とbinary型の2つ。
precision: 10, scale: 5 指定することで精度(最大桁数)とスケール(小数点以下の桁数)を指定。
対象となるデータ型は文字列タイプはdecimal型。

以下同様です。

|❶email|❷string|❸null: false, ❹unique: true|
❶email=カラム名
❷string=文字列型
❸null: false=カラムにnullを許可しない
NULLとは(空の値)空欄のこと!!!
❹unique: true=同じアドレスはダメということ。

アソシエーション

対象を1つ持っているなら、has_one

has_oneは自分のテーブルが対象テーブルを1つ持っている(複数持たない)場合に使います。対象テーブル側に自分のidのカラムがある場合に使います。
対象を複数持っているなら、has_many

has_manyは自分のテーブルが対象テーブルを複数もつ場合に使います。対象テーブル側に自分のidのカラムがある場合に使います。
自分が対象に所属しているなら、belongs_to

belongs_toは、自分のテーブルが対象テーブルのレコードに所属する(対象テーブルのidカラムがある)場合に使います。

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

【SQL初心者向け】インデックスのしくみを理解する

記事概要

作成までの経緯、状況
「インデックスは、辞書の目次みたいなものだから。使えば検索が早くなる」
SQLを使い始めてまだ間もないころ、先輩に言われた言葉です。
「お!なるほど!とりあえず貼ればいいのかあ」
と馬鹿の一つ覚えのようにテーブルにインデックスを貼りまくった結果、
その後のパフォーマンスチュー二ングにとても苦しみました。
インデックスの作成はできる。けれどしくみが説明できない。。
当時の自分への備忘録として、本記事の作成に至りました。
使用する用語はMySQLに準じます。

発生した問題
インデックスの作成方法はわかるが、なぜ効果があるのかがわからない。

期待する効果
インデックスのしくみを説明できるようにする。

問題を解決するための用法
Qiitaで記事を書く。

しくみ、動作原理
以下の流れでしくみを説明します。
1. テーブルを用意する。
2. データ検索の流れを理解する。
3. インデックスのしくみを理解する。
4. インデックスが使えない場合を理解する。

しくみ1 「テーブルを用意する」

インデックスを作成するには、テーブルが必要です。
今回は、あるアニメの「登場人物」テーブルを用意します。

登場人物
イカリ シンジ
アヤナミ レイ
スズハラトウジ
カツラギ ミサト
アカギ リツコ
カジ リョウジ
イカリ ゲンドウ
・・・
ヒュウガ マコト
ナギサ カヲル

2020/06/27 楽しみだなー( ´∀` )

しくみ2 「データ検索を理解する」

テーブルを検索する流れは以下の通りです。
① HDD上のデータがページ単位でキャッシュメモリに載る。
② キャッシュメモリに載ったテーブルをCPUが処理する。
③ メモリがパンパンになったら削除され、①に戻る。

Qiita_Index2.jpg

①の「ページ」とは、データをかたまりで扱う際の単位を意味します。
Oracleでは「ブロック」と言います。

この図を見たときの疑問点として以下のものが挙げられます。
「②の時に検索したいデータがあれば、その時点で検索が終わるんじゃない?」

これに対する答えは「検索は続くよどこまでも」です。
インデックスを作成していないと、データがソートされません。
そのため、「ほかにも同様のデータがあるんじゃ。。」
となり、結局テーブル全体が検索されます。これがフルスキャンです。
(メモリにキャッシュされている部分は除く)
だからパフォーマンスが落ちるのですね!!:eyes:

しくみ3 「インデックス作成を理解する」

数あるインデックスの中で、MySQLで使用されているのはB+treeです。
B-treeとも呼ばれますが、厳密には、B-treeを実用的扱いやすく改良したものがB+treeです。

B-treeインデックスについての説明は以下の記事がとても分かりやすいです。
「B-treeインデックス入門」

以下はメモリやHDDページを省略した簡単な図解です。

Qiita_Btree2.jpg

ここでは検索対象として「アヤナミ レイ」を2件用意しました。
HDD全体を検索するフルスキャンでは、検索終了までに何回もHDDを読み込む必要があります。
しかし、B-treeインデックスを使用した場合、図からもわかるように2か所のHDDページだけを直接読み込むことで検索が終了します。
インデックスのデータ構造はただテーブルがソートされていただけでなく、
このようなしくみで検索されていたから早くなるのです。:thinking:

しくみ4 「インデックスが使えない時を知る」

インデックスが役に立たない場合は以下の通りです。
・データ数が少ないとき
・後方一致検索
・前方一致検索(検索結果が多いときのみ)

後方検査でインデックスが使用できない理由は、上記の図からもわかりますね。
要は「データは頭文字から照合されていくため、中間地や後方一致検索にインデックスを使用できないから」です。

前方一致検索でインデックスが使用できない理由は、「頭文字が同じものが多数ある場合、結局検索する対象が多くなるから」です。

おわりに

最後までお読みいただき、ありがとうございました!
本記事の作成を通して、インデックスのしくみが理解できました。
内容に誤りがありましたら、ご指摘ください。

参考書籍

オススメの技術書籍を楽天Roomで紹介しています。

「SQLの苦手を克服する本 データの操作がイメージできれば誰でもできる」
https://room.rakuten.co.jp/room_39a28b3432/items#!

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

拝啓「インデックスは作れるけど説明できない僕へ」

記事概要

作成までの経緯、状況
「インデックスは、辞書の目次みたいなものだから。使えば検索が早くなる」
SQLを使い始めてまだ間もないころ、先輩に言われた言葉です。
「お!なるほど!とりあえず貼ればいいのかあ」
と馬鹿の一つ覚えのようにテーブルにインデックスを貼りまくった結果、
その後のパフォーマンスチュー二ングにとても苦しみました。
インデックスの作成はできる。けれどしくみが説明できない。。
当時の自分への備忘録として、本記事の作成に至りました。
使用する用語はMySQLに準じます。

発生した問題
インデックスの作成方法はわかるが、なぜ効果があるのかがわからない。

期待する効果
インデックスのしくみを説明できるようにする。

問題を解決するための用法
Qiitaで記事を書く。

しくみ、動作原理
以下のポイントでインデックスのしくみを説明します。
1. テーブルを用意する。
2. データ検索の流れを理解する。
3. インデックスのしくみを理解する。
4. インデックスが使えない場合を理解する。

ポイント1 「テーブルを用意する」

インデックスを作成するには、テーブルが必要です。
今回は、あるアニメの「登場人物」テーブルを用意します。

登場人物
イカリ シンジ
アヤナミ レイ
スズハラトウジ
カツラギ ミサト
アカギ リツコ
カジ リョウジ
イカリ ゲンドウ
・・・
ヒュウガ マコト
ナギサ カヲル

2020/06/27 楽しみだなー( ´∀` )

ポイント2 「データ検索を理解する」

テーブルを検索する流れは以下の通りです。
① HDD上のデータがページ単位でキャッシュメモリに載る。
② キャッシュメモリに載ったテーブルをCPUが処理する。
③ メモリがパンパンになったら削除され、①に戻る。

Qiita_Index2.jpg

①の「ページ」とは、データをかたまりで見た時の単位を意味します。
上記では、P2のデータをメモリに載せています。
Oracleでは「ブロック」と言います。

この図を見たときの疑問点として以下のものが挙げられます。
「②の時に検索したいデータがあれば、その時点で検索が終わるんじゃない?」

これに対する答えは「検索は続くよどこまでも」です。

インデックスを作成していないと、データがソートされません。
そのため、「ほかにも同様のデータがあるんじゃ。。」
となり、結局テーブル全体が検索されます。これがフルスキャンです。
(メモリにキャッシュされている部分は除く)
だからパフォーマンスが落ちるのですね!!:eyes:

ポイント3 「インデックス作成ロジックを理解する」

数あるインデックスの中で、MySQLで使用されているのはB+treeです。
B-treeとも呼ばれますが、厳密には、B-treeを実用的扱いやすく改良したものがB+treeです。

B-treeインデックスについての説明は以下の記事がとても分かりやすいです。
「B-treeインデックス入門」

以下はメモリやHDDページを省略した簡単な図解です。

Qiita_Btree2.jpg

ここでは検索対象として「アヤナミ レイ」を2件用意しました。
HDD全体を検索するフルスキャンでは、検索終了までに何回もHDDを読み込む必要があります。
しかし、B-treeインデックスを使用した場合、図からもわかるように2か所のHDDページだけを直接読み込むことで検索が終了します。
インデックスのデータ構造はただテーブルがソートされていただけでなく、
このようなしくみで検索されていたから早くなるのです。:thinking:

ポイント4 「インデックスが使えない時を知る」

インデックスが役に立たない場合は以下の通りです。
・データ数が少ないとき
・後方一致検索
・前方一致検索(検索結果が多いときのみ)

後方検査でインデックスが使用できない理由は、上記の図からもわかりますね。
要は「データは頭文字から照合されていくため、中間地や後方一致検索にインデックスを使用できないから」です。

前方一致検索でインデックスが使用できない理由は、「頭文字が同じものが多数ある場合、結局検索する対象が多くなるから」です。

おわりに

最後までお読みいただき、ありがとうございました!
本記事の作成を通して、インデックスのしくみが理解できました。
内容に誤りがありましたら、ご指摘ください。

参考書籍

オススメの技術書籍を楽天Roomで紹介しています。

「SQLの苦手を克服する本 データの操作がイメージできれば誰でもできる」
https://room.rakuten.co.jp/room_39a28b3432/items#!

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

MysqlでThe server quit without updating PID file エラーについて

The server quit without updating PID fileエラー

mysql server startをすると以下のようなエラーが発生
これはmysqlのバージョンを変えたりする時に発生するエラー。つまり別のバージョンのmysqlが動いているので、そちらの実行を止める必要があるということ。

ERROR! The server quit without updating PID file (/usr/local/var/mysql/user-no-MacBook-Air.local.pid).

現在実行中のプロセスを止める必要がある

ps aux | grep mysql  #MySQL関連のプロセス確認

以下のように表示されるので、実行されているプロセスを止める。

user           #これが(31827)PID→#  31827   0.3  0.2  4901664  12920   ??  S    日09PM  22:37.06 /usr/local/Cellar/mysql/8.0.19/bin/mysqld --basedir=/usr/local/Cellar/mysql/8.0.19 --datadir=/usr/local/var/mysql --plugin-dir=/usr/local/Cellar/mysql/8.0.19/lib/plugin --log-error=user --pid-file=/usr/local/var/mysql/user.pid
user              31691   0.0  0.0  4271692    672   ??  S    日09PM   0:00.03 /bin/sh /usr/local/Cellar/mysql/8.0.19/bin/mysqld_safe --datadir=/usr/local/var/mysql --pid-file=/usr/local/var/mysql/user.pid
user               3205   0.0  0.0  4277256    812 s001  S+    2:49PM   0:00.00 grep mysql

プロセスの所有権がユーザ名ではない場合は以下を実行して強制的に止める

kill -9 <PID>

これで所有権をとめてから実行する

 mysql.server start

こちらが大変参考になりました。
MySQLエラー解決法(Mac編)
こちらも参考
pidのエラー解決

ちなみにPIDはProsess ID の略

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

docker-composeで起動してるMySQLがうまく終了しなくなってたのを直した

概要

私が頻繁に使っているローカル開発環境用の docker-compose.yml に含まれるMySQLが気づいたらちゃんと終了しなくなっていて、たまにデータをぶっ壊していたから直しました。

原因

mysqlコンテナを command: bash-c 'ほげほげ' で起動していたら、PID1で起動するもんで、終了時のkillをうまくハンドリングできずに、mysqlのプロセスまでkillが届かず落ちなくて、タイムアウトでホストから落とされていた(データ壊す危険)。

docker-compose.ymlにやったこと

initオプションを指定して /dev/ihit 越しに起動してあげればこいつがちゃんとハンドリングしてくれます。
3.5だったので、3.7へバージョン上げて、下記のように init: true を指定しました。

version: '3.7'
services:
  mysql:
    image: mysql:5.7
    init: true
    command: bash -c '
      touch /var/log/mysql/general.log &&
      chown mysql:mysql /var/log/mysql/general.log &&
      tail -f /var/log/mysql/general.log &
      /entrypoint.sh mysqld
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_unicode_ci
      --general-log=true
      --general-log-file=/var/log/mysql/general.log
      --sql-mode=ONLY_FULL_GROUP_BY,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
      --innodb-use-native-aio=0'

before

指定していなかった時代

root@4b13f5625011:/# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 05:53 ?        00:00:00 bash -c  touch /var/log/mysql/general.log && chown mysql:mysql /var/log/mysql/general.log && tail -f /var/log/mysql/general.log & /entrypoint.sh mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --general-log=true --general-log-file=/var/log/mysql
root         7     1  0 05:53 ?        00:00:00 bash -c  touch /var/log/mysql/general.log && chown mysql:mysql /var/log/mysql/general.log && tail -f /var/log/mysql/general.log & /entrypoint.sh mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --general-log=true --general-log-file=/var/log/mysql
mysql        8     1  5 05:53 ?        00:00:00 mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --general-log=true --general-log-file=/var/log/mysql/general.log --sql-mode=ONLY_FULL_GROUP_BY,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION --innodb-use-native-aio=0
root        14     7  0 05:53 ?        00:00:00 tail -f /var/log/mysql/general.log
root        65     0  0 05:53 pts/0    00:00:00 bash
root        71    65  0 05:53 pts/0    00:00:00 ps -ef

after

指定した時代

root@8771d0333475:/# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 06:00 ?        00:00:00 /sbin/docker-init -- docker-entrypoint.sh bash -c  touch /var/log/mysql/general.log && chown mysql:mysql /var/log/mysql/general.log && tail -f /var/log/mysql/general.log & /entrypoint.sh mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --general-
root         7     1  0 06:00 ?        00:00:00 bash -c  touch /var/log/mysql/general.log && chown mysql:mysql /var/log/mysql/general.log && tail -f /var/log/mysql/general.log & /entrypoint.sh mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --general-log=true --general-log-file=/var/log/mysql
root         9     7  0 06:00 ?        00:00:00 bash -c  touch /var/log/mysql/general.log && chown mysql:mysql /var/log/mysql/general.log && tail -f /var/log/mysql/general.log & /entrypoint.sh mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --general-log=true --general-log-file=/var/log/mysql
mysql       10     7  2 06:00 ?        00:00:00 mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --general-log=true --general-log-file=/var/log/mysql/general.log --sql-mode=ONLY_FULL_GROUP_BY,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION --innodb-use-native-aio=0
root        13     9  0 06:00 ?        00:00:00 tail -f /var/log/mysql/general.log
root        67     0  1 06:00 pts/0    00:00:00 bash
root        73    67  0 06:00 pts/0    00:00:00 ps -ef

結果

こうするとホストから Ctrl + Cを叩き込んでもタイム・アウトすることなく、素直に落ちてくれるようになりました。

参考

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

MySQLが起動できない エラー備忘ログ その2

エラー

スタート(起動できない)

Starting MySQL
./usr/local/Cellar/mysql/8.0.19/bin/mysqld_safe: line 144: /usr/local/var/mysql/ユーザーMBP.err: Permission denied
rm: /usr/local/var/mysql/ユーザーMBP.pid: Permission denied
2020-03-29T03:04:45.6NZ mysqld_safe Fatal error: Can't remove the pid file:
/usr/local/var/mysql/ユーザーMBP.pid.
Please remove the file manually and start /usr/local/Cellar/mysql/8.0.19/bin/mysqld_safe again;
mysqld daemon not started
/usr/local/Cellar/mysql/8.0.19/bin/mysqld_safe: line 144: /usr/local/var/mysql/ユーザーMBP.err: Permission denied
 ERROR! The server quit without updating PID file (/usr/local/var/mysql/ユーザーMBP.pid).

Permission denied ってどゆう意味

簡単に言いますと、「ファイルへのアクセス権限がない」とのこと。

参考
https://qiita.com/takuyanin/items/18590600d077df707923

権限を確認する

*mysqlの該当ファイルまで移動
 % cd /usr/local/var/mysql
*ファイルのアクセス権限をみてみる
 % ls -l      
-rw-r-----    1 mysql  wheel      2948  3 29 14:14 ユーザーMBP.err
-rw-r-----    1 mysql  wheel         5  3 29 14:14 ユーザーMBP.pid

こんな感じで確認できました。
権限のところが、mysqlとなってます。これがいいのかよくわかりませんが、、、
この辺りの権限を変えてみました。

権限を変えてみる

ユーザー権限に変更

 % sudo chown -R $USER /usr/local/

確認

 % ls -l       

-rw-r-----    1 ユーザー wheel      2948  3 29 14:14 ユーザーMBP.err
-rw-r-----    1 ユーザー wheel         5  3 29 14:14 ユーザーMBP.pid

起動確認 (mysql.server start)

 % mysql.server start  
Starting MySQL
.... SUCCESS! 

うまく行きました...

MySQLのステータスを確認する。(mysql.server status)

mysql.server status
 ERROR! Multiple MySQL running but PID file could not be found (754 857 )

複数起動していますが、PIDファイル(754 857)というのがないですよーーって事で
現在実行されているmysqlのアクティブなプロセスのIDを確認!

 %  ps ax | grep mysql
 754 s004  S      0:00.03 /bin/sh /usr/local/Cellar/mysql/8.0.19/bin/mysqld_safe --datadir=/usr/local/var/mysql --pid-file=/usr/local/var/mysql/MacBook-Pro.pid
  857 s004  S      0:03.55 /usr/local/Cellar/mysql/8.0.19/bin/mysqld --basedir=/usr/local/Cellar/mysql/8.0.19 --datadir=/usr/local/var/mysql --plugin-dir=/usr/local/Cellar/mysql/8.0.19/lib/plugin --log-error=MacBook-Pro.err --pid-file=/usr/local/var/mysql/MacBook-Pro.pid
 1088 s004  S+     0:00.01 grep mysql

実行されているプロセスを遮断する。kill ××

kill 754
kill 857

再びMySQLを起動させる。(mysql.server start)

Starting MySQL
.... SUCCESS! 

% mysql.server status
 SUCCESS! MySQL running (1242)

これで全てうまくいくことができました。

番外編(Operation not permitted)

% sudo chown -R $USER /usr/local

を実行したときに、

chown: /usr/local: Operation not permitted

このように表示される場合があります。

Operation not permittedとは...

OS X 10.11 El Capitanより追加されたセキュリティ機能、SIP(System Integrity Protection)によって以下の領域がガードされているそうです。
- /bin
- /sbin
- /System

この配下では,rootユーザでも書き込みできません。

解決策

参考
https://qiita.com/iwaseasahi/items/9d2e29b02df5cce7285d

最後に

皆様の参考になれば幸いです。

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

フリマアプリのDB設計

フリマアプリのDB設計

プログラミングスクールの最終課題でフリマアプリを制作したので、そのDBを公開します。
全部で7テーブルです。(かなり少なくまとめました、追加実装のコメントテーブル等は無し)
途中でDB設計を何度も変更して手間がかかってしまったので、最初にしっかり考えてから制作に取り掛かることをお勧めします!

usersテーブル

Column Type Options
nickname string null: false
email string null: false
encrypted_password string null: false
user_image string
introduction text
family_name string null: false
first_name string null: false
family_name_kana string null: false
first_name_kana string null: false
birth_day date null: false

Association

  • has_many :products dependent: :destroy
  • belongs_to :destination dependent: :destroy
  • belongs_to :card dependent: :destroy

destinationテーブル

Column Type Options
user_id integer null: false, foreign_key: true
family_name string null: false
first_name string null: false
family_name_kana string null: false
first_name_kane string null: false
post_code string null: false
prefecture string null: false
city string null: false
address string null: false
building_name string
phone_number string

Association

  • belongs_to :user

cardテーブル

Column Type Options
user_id integer null: false, foreign_key: true
customer_id string null: false
card_id string null: false

Association

  • belongs_to :user

categoryテーブル

Column Type Options
name string null: false
ancestry string

Association

  • has_many :products
    ※ancestryは、gem ancestryを使用するため。

productテーブル

Column Type Options
name string null: false
price string null: false
description string null: false
status string null: false
size string null: false
shipping_cost string null: false
shipping_days string null: false
prefecture_id string null: false
judgment string
category_id integer null: false, foreign_key: true
brand_id integer null: false, foreign_key: true
shipping_id integer null: false, foreign_key: true
user_id integer null: false, foreign_key: true

Association

  • belongs_to :user dependent: :destroy
  • belongs_to :category dependent: :destroy
  • belongs_to :brand dependent: :destroy
  • has_many :images dependent: :destroy

  • belongs_to_active_hash :prefecture

imageテーブル

Column Type Options
image string null: false
product_id integer null: false, foreign_key: true

Association

  • belongs_to :product

brandテーブル

Column Type Options
name string index: true

Association

  • has_many :products

ER図

スクリーンショット 2020-03-29 13.27.15.png

これよりもコンパクトに作成できるよ!って方はぜひ教えてください:sunglasses:
以上、最後まで読んでいただきありがとうございました。

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

MySQLのCRUD

MySQLによるデータベースのCRUDを学習したのでメモします。(Windows環境)

まずxamppコントールパネルからshellを開き、mysql -u rootでMySQLにログインします。

データベースの作成からやっていきます。

データベース作成

 create database node_todo;

データベース確認

 show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| node_todo          |
| performance_schema |
| phpmyadmin         |
| test               |
+--------------------+

node_todoデータベースにtodosテーブルを作成します。

データベースディレクトリに移動

 use node_todo;
Database changed 

テーブル作成
※必ず1つはカラムを設定しないといけない

 create table todos(
    ->     id int not null auto_increment,
    ->     content varchar(20) not null,
    ->     primary key (id));

+---------------------+
| Tables_in_node_todo |
+---------------------+
| todos               |
+---------------------+

カラムは カラム名 データ型 条件式の形で記述。

idを識別子とします。

テーブル内容確認

describe todos;

+---------+-------------+------+-----+---------+----------------+
| Field   | Type        | Null | Key | Default | Extra          |
+---------+-------------+------+-----+---------+----------------+
| id      | int(11)     | NO   | PRI | NULL    | auto_increment |
| content | varchar(20) | NO   |     | NULL    |                |
+---------+-------------+------+-----+---------+----------------+

作成したカラムにレコードを追加してみます

insert into todos (content) values ('勉強する');

確認します。

 select * from todos;
+----+----------+
| id | content  |
+----+----------+
|  1 | ????     |
+----+----------+

文字コードをutf8にセットしていなかったので日本語が認識されませんでした。
とりあえず英語でやります。

+----+----------+
| id | content  |
+----+----------+
|  1 | ????     |
|  2 | learning |
+----+----------+

レコードの変更

update todos set content =  'learn programing' where id = 2;

+----+------------------+
| id | content          |
+----+------------------+
|  1 | ????             |
|  2 | learn programing |
+----+------------------+

レコード削除

 delete from todos where id = 1;
+----+------------------+
| id | content          |
+----+------------------+
|  2 | learn programing |
+----+------------------+

これでとりあえずデータベースのCRUDが一通りできました。

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