👾

Myポケモンずかんを作ってSQL文での四大命令文とNULLについて整理してみた

2024/08/17に公開

プログラミング学習のアウトプットとして記事にまとめました🐣
学習最中のエンジニア志願者の理解整理に役立てれば幸いです✨

4つの基本的な命令(四大命令文)

テーブルに登録されてあるデータを操作するSQL文は以下の四大命令文を使用します。

  • SELECT(選択) :データを取得
  • INSERT(挿入) :データを追加
  • UPDATE(更新) :データを更新
  • DELETE(削除) :データを削除

このまま使用してしまうと全てのデータが対象になってしまうので
ある条件で絞り込みたい…

そんなときには、WHERE句を使用します。

WHERE句の特徴

  • 該当する条件がある行をだけを絞り込んで選択できる(デフォは全て対象)
  • SELECT文、UPDATE文、DELETE文には使用できる(INSERT文は使えない)
  • WHEREのあとには条件式

条件式が複数になった場合

条件式を複数にしたい場合は、論理演算子'NOT'や'AND'、'OR'で繋げることができます。

ポケモン様のお力をお借りします🙇🏻‍♀️
https://zukan.pokemon.co.jp

(例)オリジナルポケモンずかんっぽいもの
データベース 「db_Pokemon」
テーブル 「profile」

+----+-----------------+-----------+
| id | name            | type      |
+----+-----------------+-----------+
|  1 | ピカチュウ      | でんき    |
|  2 | カイリュー      | ひこう    |
|  3 | ヤドラン        | みず      |
|  4 | ピジョン        | ひこう    |
|  5 | コダック        | みず      |
+----+-----------------+-----------+

ここからちょっといたずらをします。
ピカチュウのときと、みずタイプのとき
かわいいタイプに変えちゃいましょう。((ぇ

UPDATE profile
SET type = 'かわいい'
WHERE name = 'ピカチュウ' OR type = 'みず';
+----+-----------------+--------------+
| id | name            | type         |
+----+-----------------+--------------+
|  1 | ピカチュウ        | かわいい     |
|  2 | カイリュー        | ひこう       |
|  3 | ヤドラン          | かわいい     |
|  4 | ピジョン          | ひこう       |
|  5 | コダック          | かわいい     |
+----+-----------------+--------------+

ANDとORを同時に使うとき

はい、最初の状態に戻しまして、ANDとORを同時に使いたい場合を考えます。
ここにteamフィールドを追加します。

+----+-----------------+-----------+-------+
| id | name            | type      | team |
+----+-----------------+-----------+-------+
|  1 | ピカチュウ       | でんき     | A     |
|  2 | カイリュー        | ひこう     | A     |
|  3 | ヤドラン          | みず       | A     |
|  4 | ピジョン          | ひこう     | B     |
|  5 | コダック          | みず       | B     |
+----+-----------------+------------+-------+

①ひこうタイプのときか、みずタイプのとき
かつ
②チームA
なら小悪魔タイプに更新します😈

①と②両方の条件を満たすのはカイリュー、ヤドランだけです。

では当てはめてみましょう。

UPDATE profile
SET type = '小悪魔'
WHERE type = 'ひこう' OR type = 'みず' AND team = 'A';
+----+-----------------+-----------+-------+
| id | name            | type      | team  |
+----+-----------------+-----------+-------+
|  1 | ピカチュウ       | でんき      | A     |
|  2 | カイリュー       | 小悪魔      | A     |
|  3 | ヤドラン         | 小悪魔      | A     |
|  4 | ピジョン         | 小悪魔      | B     |
|  5 | コダック         | みず        | B     |
+----+-----------------+------------+-------+

…ピジョンまで小悪魔に!
これではちょっと期待していた結果とは異なってしまいます。

なぜかというと、
演算子には優先順位があり、
ANDとORでは
ANDが優先されてしまうので
結果が変わってきてしまうのです!

こちら参考です。
https://learn.microsoft.com/ja-jp/sql/t-sql/language-elements/operator-precedence-transact-sql?view=sql-server-ver16

ORの優先度高くしたいときには、
①の式を()で囲うと
()内が優先されて、解決します!
算数の四則演算のときに使う()みたいですねー!

UPDATE profile
SET type = '小悪魔'
WHERE (type = 'ひこう' OR type = 'みず') AND team = 'A';

結果は、

+----+-----------------+-----------+-------+
| id | name            | type      | team  |
+----+-----------------+-----------+-------+
|  1 | ピカチュウ       | でんき      | A     |
|  2 | カイリュー       | 小悪魔      | A     |
|  3 | ヤドラン         | 小悪魔      | A     |
|  4 | ピジョン         | ひこう      | B     |
|  5 | コダック         | みず        | B     |
+----+-----------------+------------+-------+

意図した通りの結果になってくれました🎉


NULLについて

さらにポケモンずかんらしくゲットした日時を入れるフィールドを追加してみます。

-- ゲットした日時のフィールドを追加
ALTER TABLE profile
ADD COLUMN catch_date DATETIME;

-- 既にゲットしたポケモンに日時を設定
UPDATE profile
SET catch_date = '2024-08-01 10:00:00'
WHERE name = 'ピカチュウ';

-- まだゲットしていないポケモンにNULLを設定
-- (デフォはNULLなので必要ないですが後の説明で使うので記載しました)
UPDATE profile
SET catch_date = NULL
WHERE name IN ('カイリュー', 'ヤドラン', 'ピジョン', 'コダック');
+----+-----------------+-----------+---------------------+
| id | name            | type      | catch_date          |
+----+-----------------+-----------+---------------------+
|  1 | ピカチュウ      | でんき    | 2024-08-01 10:00:00 |
|  2 | カイリュー      | ひこう    | NULL                |
|  3 | ヤドラン        | みず      | NULL                |
|  4 | ピジョン        | ひこう    | NULL                |
|  5 | コダック        | みず      | NULL                |
+----+-----------------+-----------+---------------------+

最初はピカチュウだけで他はまだゲットしていないので空欄のNULLになります。

さてさて、物語を進めていくと…

あっ!
野生のピジョンがとびだしてきた!
いけっ!モンスターボール!



やったー!ピジョンをゲットした!

名前はピジョンで、まだゲットしていなければ、ゲットした時点の日時を更新します。

UPDATE profile
SET catch_date = NOW()
WHERE name = 'ピジョン' AND catch_date = NULL;
+----+-----------------+-----------+---------------------+
| id | name            | type      | catch_date          |
+----+-----------------+-----------+---------------------+
|  1 | ピカチュウ      | でんき    | 2024-08-01 10:00:00 |
|  2 | カイリュー      | ひこう    | NULL                |
|  3 | ヤドラン        | みず      | NULL                |
|  4 | ピジョン        | ひこう    | NULL                |
|  5 | コダック        | みず      | NULL                |
+----+-----------------+-----------+---------------------+

あれ、更新されませんねー🫠

ここでポイントになるのが、

先ほどの-- まだゲットしていないポケモンにNULLを設定
では= NULLが使えましたが、
WHERE句の中ではIS NULLを使うルールになっています。

UPDATE profile
SET catch_date = NOW()
WHERE name = 'ピジョン' AND catch_date IS NULL;
+----+-----------------+-----------+---------------------+
| id | name            | type      | catch_date          |
+----+-----------------+-----------+---------------------+
|  1 | ピカチュウ      | でんき    | 2024-08-01 10:00:00 |
|  2 | カイリュー      | ひこう    | NULL                |
|  3 | ヤドラン        | みず      | NULL                |
|  4 | ピジョン        | ひこう    | 2024-08-17 18:37:40 |
|  5 | コダック        | みず      | NULL                |
+----+-----------------+-----------+---------------------+

無事更新されました🦅


MyポケモンずかんでDBを作成してみました。

1つのカラムには1つのデータを格納するのが基本だそうです。
カイリューのようにひこうタイプとドラゴンタイプで2つ属性タイプを持つポケモンもいましたがとりあえず今回は1つだけにしました。

複数の属性タイプを格納したい場合は

  • profileテーブルに基本情報
  • typesテーブルに属性タイプ
    というように、テーブルを分けて管理するようです。

(,)で区切って2つ以上格納しようと思えばできるけど、
データの検索や更新が難しくなるため、あまり推奨されないとのことです。

簡単なポケモンずかんのDBひとつ作るのにも奥が深い…👾笑

ここまでお読みいただきありがとうございました!
間違い等ございましたらご指摘よろしくお願いします🙇🏻‍♀️

Discussion