インプリシットカラム
検索時のワイルドカード記号やインサート時の列名省略などクエリを省略することにより弊害が起こる場合がある。
目的:タイプ数を減らす
以下のようなユーザー情報があった際に全ての列を取得するにはどのような取得方法をするか。
User
user_id | user_name | user_email | tel |
---|---|---|---|
1 | TEST | test@example.com | 000-1111-2222 |
おそらく多くの人は
SELECT
user_id,
user_name,
user_email,
tel,
FROM
User;
ではなく、
SELECT * FROM User;
で、取得するかたが多いのではないでしょうか?
また、「User」テーブルの全列にデータを格納する際はどうするでしょうか。
INSERT INTO
Users(user_id, user_name, user_email, tel)
VALUES
(2, "TEST2", "test2@example.com", "111-2222-3333");
上記のように全列名を記載しますか??
それとも以下のように列名を省略しますか??
INSERT INTO
Users
VALUES
(2, "TEST2", "test2@example.com", "111-2222-3333");
暗黙的に列名を指定できる際は列名を省略することも多いのではないか。
列名の多い場合やどうせ全列取得、挿入するなら手間だと感じ省略することもあるかと思う。
リファクタリングによる問題
user_id | user_name | user_email | tel |
---|
先ほどのUsersテーブルに「age」列を追加することになった。
user_id | user_name | user_email | tel | age |
---|
テーブルに列が追加されたことを知らない場合、先ほど同様に以下のクエリにてデータを挿入しようとしたらエラーを返すようになった。
INSERT INTO
Users
VALUES
(2, "TEST2", "test2@example.com", "111-2222-3333");
このようにリファクタリングによって予期しない値が挿入される場合等ある。
また、列を削除して新たに追加した場合や、新たに追加した後に別の列を削除した場合などでは型さえ一致していればエラーを返さず本来想定していない列に別の列にの値を知らず知らずに挿入してしまうなども考えられる。
また、列が削除されている場合エラーを返すが明示的に列を指定していた方が原因究明がしやすい。
不要な列のみ除去
SQLには「指定した一部の列のみ除去した全ての列」を取得することができない。
- 前列をワイルドカードで取得する
- 明示的に必要な列のみ指定する
の2つの方法しかない。
アンチパターンを使用しても良い場合
- テストや検証で素早くクエリを発行したい場合
解決策
列名を明示的に指定する
ワイルドカードや暗黙的な列指定をせず、必要な列名は明示的に指定する
謝りの防止
列名を明示的にすることで致命的なミスを防ぐことが目的。
- テーブル定義の列の順番が変わっても明示的に指定していれば結果は一緒
- INSERT時に予期せぬ列に挿入されることを防げる
- テーブルから列が削除された際にしっかりとエラーで落ち、原因究明がしやすい
明示的に列名を指定することで誤った挿入や予期しない列順でのデータ返却がなくなり、エラー時の原因究明やメンテナンス性向上につながる。
それは多分、必要ない (YAGNI: You Ain't Gonna Need It)
YAGNIを簡単に説明すると、
- 必要になりそうなコードを書かない
- 必要になったら書く
- 必要だと思ったものは案外使われない
と、言う意味らしいです。(知らなかった)
使うかどうかわからないものを書いてパフォーマンスの影響が出たり、リスクが増す可能性があるなら必要最低限の列を指定しようと言うこと。
まとめ
必要な列だけを指定するようにしよう