情弱エンジニアのなかのblog

一人前のエンジニアになる為のブログです

内部結合と外部結合の違いについて

INNER JOIN と LEFT OUTER JOIN

この間MySQLのJOINについての記事を書きましたが、内部結合と外部結合についてよく分かっていなかったので今回まとめてみようと思います

1.前提条件

2.内部結合とは

3.外部結合とは

1.前提条件

まず説明を始める前に二つのテーブル、顧客テーブル「customers」と商品テーブル「items」があると仮定します。

「customers」にはidと顧客名と商品テーブルの外部キーが入っています。

id,name,item_id

「item」にはidと商品の種類と商品名が入っているとします。

id,category,name

それぞれの中身はこうなっています。

mysql> SELECT * FROM customers;
+----+--------+---------+
| id | name   | item_id |
+----+--------+---------+
|  1 | tanaka | 1       |
|  2 | yamada | 2       |
|  3 | satou  | 1       |
|  4 | itou   | 5       |
+----+--------+---------+

mysql> SELECT * FROM items;
+----+-----------+-------+
| id | category  | name  |
+----+-----------+-------+
|  1 | food      | salad |
|  2 | book      | novel |
|  3 | clothes   | coat  |
|  4 | furniture | chair |
+----+-----------+-------+

2.内部結合とは

そもそも結合とは二つのテーブルをくっつけることです、今回の場合「customers」と「items」ですね。

そして内部結合(INNER JOIN)とは二つのフィールドを検索して一致するものだけを抽出して、二つのテーブルを結合するというものになります。

実際に試すとこうなります。

mysql> SELECT * FROM customers INNER JOIN items ON  customers.item_id = items.id;

+----+--------+---------+-----+----------+-------+
| id | name   | item_id | id  | category | name  |
+----+--------+---------+-----+----------+-------+
|  1 | tanaka | 1       | 1   | food     | salad |
|  3 | satou  | 1       | 1   | food     | sarad |
|  2 | yamada | 2       | 2   | book     | novel |
+----+--------+---------+-----+----------+-------+

重要なのは 「customers.item_id」 と 「items.id」が一致するものを検索条件にしているので、 一致するデータを持っていないものは除外されてしまうという点です。

customersテーブルの

|  4 | itou   | 5       |

itemsテーブルの

|  4 | furniture | chair |

この二つのが消えてしまっています。

3.外部結合とは

続いて外部結合(LEFT OUTER JOIN)とは二つのフィールドを検索して一致するものプラス、左側のテーブルに関しては全て出力し、二つのテーブルを結合するというものになります。

ここで重要なのは検索されても存在しない右のテーブルのデータはNULLになるというところです。 NULLとは何もない何も表示されないという意味になります。

実際に試すとこうなります。

mysql> SELECT * FROM customers LEFT JOIN items ON  customers.item_id = items.id;

+----+--------+---------+------+----------+-------+
| id | name   | item_id | id   | category | name  |
+----+--------+---------+------+----------+-------+
|  1 | tanaka | 1       | 1    | food     | salad |
|  3 | satou  | 1       | 1    | food     | sarad |
|  2 | yamada | 2       | 2    | book     | novel |
|  4 | itou   | 5       | NULL | NULL     | NULL  |
+----+--------+---------+------+----------+-------+

お分かりいただけたでしょうか、さっきと違い基準となる「左側」のcustomersの

|  4 | itou   | 5       | NULL | NULL     | NULL  |

が消えていません、そして「items」には「5」というidが存在していないのでNULLが続いています。

そして「customers」を基準にしているのでさっきと同じく

|  4 | furniture | chair |

は消えています。

補足として結合後のテーブルは検索先である「item_id」の昇順に並び替えられます。

以上が内部結合と外部結合の違いにつての説明になります。 今回参考にさせて頂いたサイトを記載致します。

INNER JOINとOUTER JOIN - 紳士なブログ

inner join と outer join の違いと覚え方の自分用まとめ(外部表、駆動表もメモ) | ぱーくん plus idea

SQL:内部結合と外部結合の違い | 覚え書き.com

それでは

CSRF対策について

サイト制作において大切なCSRF対策!

今回はCSRF対策について学んだので使い方などを書いていきます。

現在私自身webアプリを制作していて最近CSRFという言葉に出会ってかなり重要だと感じたので、これからwebアプリを作りたいと思っている人に参考にしていただければ幸いです。

1.クロスサイト・リクエストフォージェリ(CSRF)とはなにか?

2.CSRF対策はどうすればいいのか

1.クロスサイト・リクエストフォージェリ(CSRF)とはなにか?

もしこれを見ている方がwebアプリケーションを制作しようとしていて、ログイン機能をつけたい、掲示板のように投稿できるようにしたい。という場合は特に注目してください。

例えば自分が作ったwebアプリがあり、Cookieでセッション管理を行っているとします。 ユーザーがwebアプリにログインするとCookieにセッションIDが保存されます。その後ユーザーがアプリを離れてほかのサイトにいってもセッションは残ってしまいます。

その状態でユーザーが悪意のあるサイトに訪れリンクをクリックしたり、スクリプトを実行するとブラウザはCookieのセッションIDとパラメータを自分が作ったwebアプリに送ってしまいます。

こうなったらもうお手上げです、重要なのはwebアプリから見るとCookieにセッションIDが入っているので正規のユーザーかどうか判断できないというところです。

2.CSRF対策はどうすればいいのか

ではどうすればいいのか、結論から言いますとログインのリクエストが送られてきたタイミングでトークン(一度のみ有効なパスワード)を利用すればいいらしいです。

どういうことかといいますと重要な処理を行うページに、hidden(見えない項目)でトークンをセットして表示、保存します。そしてログインリクエストが送られてきたらトークンも一緒に送り、この送られてきたトークンと保存しておいたトークンが等しければ正しいリクエストだと判断できます。

このほかに単純ですが重要な処理のタイミングでパスワード入力をしてもらうなどがあります。

まだ覚えたてなので説明がおぼつかない部分があり申し訳ありません。 今回参考にさせて頂いたサイトを記載致します。

クロスサイト・リクエストフォージェリ(CSRF)と対策 | Webセキュリティの小部屋

もっと理解して使いこなせるようになったらコードなどもまぜて再度アップします!

MySQLの結合について

テーブルとテーブルを結合するにはJOINが必要!

今回はMySQLのJOINを覚えたので使い方を書いていきます。

1.なぜ結合するのか

2.前提条件

3.実際の使い方

1.なぜ結合するのか

まずなぜ結合が必要かといいますと、DBには複数のテーブルが存在していまして、そのテーブルをまたいだ検索を行いたい時などに使えます。

例えば顧客テーブルと商品テーブルがあり、ある商品を買ったお客様だけを抽出したい、などの状況で結合が必要になります。

2.前提条件

では実際に使い方を見ていきましょう。

二つのテーブル、顧客テーブル「customer」と商品テーブル「item」があると仮定します。

「customer」にはidと顧客名と商品テーブルの外部キーが入っています。

id,name,item_id

「item」にはidと商品の種類と商品名が入っているとします。

id,category,name

categoryの内容は[food,book,clothes]だとします、ここでbookを買った顧客を一覧表示したい、となったとします、そこで結合が必要になります。

3.実際の使い方

実際にSQL文を書くときに必要になるのが「JOIN」です。正確には「INNER JOIN」を使うことでテーブルの結合が出来ます。つかい方は

INNER JOIN [結合先テーブル] ON [結合元フィールド] = [結合先フィールド]

と書きます、実際のコードはこうなります。

INNER JOIN item ON customer.item_id = item.id;

そして今回求める処理をするにはこう書きます。

SELECT
    customer.name
FROM
    customer
INNER JOIN 
    item
ON 
    customer.item_id = item.id
WHERE
    item.category = 'book';

これで本を買ったお客様を求めることができます。

ちなみに今回JOINについて参考にさせて頂いたサイトこちらになります。

内部結合(INNER JOIN句) - データの取得 - MySQLの使い方

MySQLはまだまだ分からないことも多いのでもっと勉強します。それでは

DBについて理解しよう!!

難しいことはドットインストールで覚えよう

今回はPHPMySQLを組み合わせた使い方を学習したのでつまずいた点などアップします! ちなみにドットインストールの「PHPデータベース入門」を学びました

1.データの追加をしたいときとは?

2.検索の仕方とは?

3.bindValueの使い方は?

1.データの追加をしたいときとは?

結論から言えばいろいろあるのですが、とりあえずexec()を説明します、最初は何してるのか分かりませんでした。

// connect
  $db = new PDO(PDO_DSN, DB_USERNAME, DB_PASSWORD);
  $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

  // insert
  $db->exec("insert into users (name, score) values ('nonaka', 55)");

まあそのまんまなんですが、これでレコードに追加しているわけです 他にもデータを追加するにはprepare()なども使えるのですがまずはどれか一つ試してみて 結果を確認するとスムーズに進めます

2.検索の仕方とは?

当然ながら検索も使えます、こんな感じです

   $stmt = $db->query("select * from users");
   $stmt = $db->prepare("select score from users where score > ?");
   $stmt->execute([60]);
   $stmt = $db->prepare("select name from users where name like ?");
   $stmt->execute(['%t%']);

どちらもデータベースの基本的な検索方法をPHPで行っているだけなのですが 最初に見たときは( ゚д゚)ポカーン でした、、、

3.bindValueの使い方は?

同じ名前の人のスコアをたくさん追加したいというときにbindValueは使えます(果たしてそんな時は来るのか)

$stmt = $db->prepare("insert into users (name, score) values (?, ?)");

  $name = 'nonaka';
  $stmt->bindValue(1, $name, PDO::PARAM_STR);
  // $stmt->bindValue(':name', $name, PDO::PARAM_STR);
  $score = 23;
  $stmt->bindValue(2, $score, PDO::PARAM_INT);
  $stmt->execute();
  $score = 44;
  $stmt->bindValue(2, $score, PDO::PARAM_INT);
  $stmt->execute();

こういった感じで使えます、これも使って慣れるのが一番です!

大分説明不足感が否めないのですが何分ドットインストールを見ただけなので悪しからず、、 これじゃあ分からんわという人はこちらへ

http://dotinstall.com/lessons/basic_php_db

またつまずくことあったらアップしてく予定です。。

ランダム指名アプリケーション制作3

とりあえずの機能実装とエラー処理

まずまず、必要な処理の実装と例外時のエラー処理が出来たのでアップします!

1.必要なデータの取得

2.指定した人数分出力

3.エラー処理の実装

1.チェックボックスで必要なデータの取得

チェックボックスのデータを取得して、不在メンバーを配列から除外する処理を作りました 意外と時間がかかりました、、

result.php

$member = array('Aさん','Bさん','Cさん','Dさん','Eさん');

for($i = 0; $i < $employee_number;$i++){
        //出欠席チェックリストを代入
        $member_list[] = trim($_POST["list$i"]);

        if($member_list[$i] == ""){
            //欠席メンバーを$memberから削除、ただし欠席人数分をマイナスしないとずれていくのので -$absenceとしている
            $split = array_splice($member, $i - $absence, 1);
            $absence++;
        } else {
            //発表者をカウントアップ
            $count++;
        }
    }

2.指定した人数分出力

index.phpで選択メニューを指定して、result.phpで取得して指定されている人数分ランダムでメンバーを出力する

index.php

      <select name="num">
                <option>1</option>
                <option>2</option>
                <option>3</option>
                <option>4</option>
            </select>発表人数

result.php

$speak = trim($_POST["num"]);                                   //発表人数を取得

        for($j = 0; $j < $speak ; $j++){
            do{
                $t = 0;
                //配列は0からなので$countに-1をする
                $num = mt_rand(0, $count -1);

                for($k = 0; $k < $c; $k++) {
                    if($temp[$k] == $num){
                        $t = 1;
                    }
                }
                for($i = 0; $i < $yesterday_num; $i++){
                    if($member[$num] == $yesterday_name[$i]){
                        //前回の発表者と今回の発表者が同じ場合やり直し
                        $t = 1;
                    }
                }
            //$numが今まで表示された人と被っていたらやり直し
            } while ($t == 1);

            echo $member[$num];
            //一度表示された人を保存
            $temp[$j] = $num;
            $today[] = $member[$num];
            //発表者を表示した回数
            $c++;
        }

かなり強引に書いてしまいました、もっと行数を少なく、可読性を上げていきます!

3.エラー処理の実装

エラーというかこのままだと処理が止まってしまうので エラーになったらerror.phpに逃がします。

    //今回話すことができるメンバー
    $can_speak = array_diff($member,$yesterday_name);
    //今回話すことが出来る人数
    $can_speak_num = count($can_speak);

    //発表人数より在席人数のほうが少ないとき
    if($count < $speak){
        header("Location:error.php") ;
        exit;
    }

    $possible = $possible - $yesterday_num;
    //発表人数より前回の発表人数の方が多いとき
    if($possible < $speak){
        header("Location:error.php") ;
        exit;
    }

    //今回話すことが可能な人数より発表人数の方が多いとき
    if($can_speak_num < $speak){
        header("Location:error.php") ;
        exit;
    }

これも中身が同じですしもっと短くできるのでまた書き換えていきます。

まだまだ直すところや実装すべきこと、理解すべきことは沢山ありますが 一つ一つでも身につけていきます!

ランダム指名アプリケーション制作2

フォームとPOSTを理解しよう

ランダム指名アプリケーション制作の第二回目は大きくつまずいたのでモリモリ書いていきます!

1.ファイルを分割

2.チェックボックスのデータを渡す

1.ファイルを分割

まず前回作ったものは一つのファイル内で完結してたので、ファイルを分けてデータを渡します。 データを渡すのはPOSTを使います

こんな感じです

index.php(受け渡す方)

<form method="post" action="result.php">

result.php(受け取る方)

    if(isset($_POST['rand'])){      //更新ボタンが押されたらランダムでメンバーを出力する
        $num = rand(0, 7);
        echo $member[$num];
    }

もちろん見た目は変わりません、、が遷移するのでページに動きが出ます→やる気が出ます

2.チェックボックスのデータを渡す

チェックボックスを入れたのですがどーしても上手くいかずにいました、、、

このような感じで書いていました

//index.php
<?php  foreach($member as $data):?>
                  <input type="checkbox" name="list" checked>
                  <!--メンバーを表示するチェックボックス -->
                  <?php $i++?>
                <?= $data;?>
            <?php  endforeach;?>

//result.php
for($i = 0; $i < 8;$i++){
        $member_list[] = $_POST["list"];
    }

ですがこれではindex.phpでループを回してもname属性が同じ「list」で更新されてしまっていました。。。

ですのでとりあえずチェックボックスを変えました

//index.php
<input type="checkbox" name="list<?= $i; ?>" value="<?= $i; ?>" checked>
//result.php
    for($i = 0; $i < 8;$i++){
        $member_list[] = $_POST["list$i"];
    }

これでデータを取得は出来たのであとはうまいこと変換していきます。 本日は以上になります。

ランダム指名アプリケーション制作1

アプリケーション制作再開

お疲れ様です、半年以上久しぶりの更新になります、、、

今回から新たにPHPなどを使いアプリケーションを制作していきその軌跡を記していきます。

1.仕様

2.製作開始

1.仕様

  • 一定数のメンバーからランダムに選出して名前を表示する
  • 不在メンバーを除外出来るようにする(チェックボックスなどで)
  • 表示する人数を複数名に変えられるようにする

2.製作開始

まずはhtmlでページを作り

ボタンを作ります

        <form action="index.php" method = "post">
             <input type="submit" name="rand" value="更新" />
        </form>

こんな感じです f:id:nonaka-katuma-hal:20170421190547j:plain

続いてボタンを押すとランダムに名前を表示する処理になります。

        <?php
        if(isset($_POST['rand'])){
            $name = rand(0, 7);
            echo $member[$name];
        }
        ?>

チェックボックスの制作にも入りました

        <form method="post" action="">
            <input type="checkbox" name="food[]" value="Aさん"><?= $member[0]?>
            <input type="checkbox" name="food[]" value="Bさん"><?= $member[1]?>
            <input type="checkbox" name="food[]" value="Cさん"><?= $member[2]?>
            <input type="checkbox" name="food[]" value="Dさん"><?= $member[3]?>
            <input type="checkbox" name="food[]" value="Eさん"><?= $member[4]?>
            <input type="checkbox" name="food[]" value="Fさん"><?= $member[5]?>
            <input type="checkbox" name="food[]" value="Gさん"><?= $member[6]?>
            <input type="checkbox" name="food[]" value="Hさん"><?= $member[7]?>
        </form>

とりあえずはそんなところで 失礼致します!