MySQL道普請便り

第54回SQLコメントを使ってみよう

普段プログラムを書く時に、プログラムの解説や引数のヒントとしてコメントを書くことがあると思います。SQLを書く際にも同様にコメントを残したい場合があります。そこで、今回はSQL文にコメントを書く方法と、SQLにコメントを書くとどのようなことができるのかについて軽く解説していきます。

検証環境

今回はmacOS Sierra(10.12.6)Homebrewを利用してインストールしたMySQL(5.7.19)に対して行っています。また同じくHomebrewを利用してインストールしたSqlite3(3.9.2)を一部使用しています。

MySQLのコメント文の書き方

MySQLでSQLに使えるコメント文は、次で説明する以下の3通りの書き方があります。次からはそれらについて説明を行っていきます。

#を使ってコメントを書く

#を使ってコメントを書いてみた例が以下になります。

mysql> #コメント
mysql>

この例ではSQLに関係の無い日本語をコメントとして入れていますが、SQLでエラーが起こってないことがわかります。また、#から行末までがコメントとして扱われます。なので、以下のような形でSQLの途中にコメントをすることもできます。

mysql> select 1 +  #コメント
    -> 1;
+---------+
| 1 +
1 |
+---------+
|       2 |
+---------+
1 row in set (0.01 sec)
mysql>

しかし、この場合はカラム欄が崩れてしまいます。こちらは改行文字までコメントとして扱われるため、改行文字がサーバに送られてしまうため発生する問題です。

-- を使ってコメントを書く

先ほどの#を使った例と同様に、今度は--を使ってコメントを書いてみます。

mysql> -- コメント
mysql>

先ほどと同様に、こちらもコメントとして認識されているのがわかります。しかし、次の例ではどうでしょうか?

mysql> --コメント
    -> ;

行が継続した時と同じ表示が表示されていてコメントとして扱われていない事がわかります。一体上と下では何が違うのでしょうか。

実は、--の後ろにスペースが入ってるか入ってないかの違いによるものです。--は、1--1(1から-1を引く)等に使われる可能性があります。

mysql> select 1--1;
+------+
| 1--1 |
+------+
|    2 |
+------+
1 row in set (0.00 sec)

mysql>

負の数を引く場合にコメントとして扱われてしまうとちょっと困ってしまいますね。なので、--の後ろにスペースなどの空白文字や制御文字がある場合にのみコメントと解釈するようになってます。ちなみに、1---1の結果は0になります。

mysql> select 1---1;
+-------+
| 1---1 |
+-------+
|     0 |
+-------+
1 row in set (0.00 sec)

/**/を使ってコメントを書く

#を使った場合、--を使った場合のどちらも、複数行に渡ってコメントをすることはできません。そういった場合には、この/**/を使ってコメントを書きます。こちらはC言語やJavaなどのように/*から*/で囲まれるまでの部分をコメントとして扱います。そのため、#--の時は行末までがコメントとなっていましたが、/**/では以下のように1行のSQLの途中にコメントを挟むことができます。

mysql> select 1 + /*コメント*/ 1;
+--------+
| 1 +  1 |
+--------+
|      2 |
+--------+
1 row in set (0.00 sec)
mysql>

また以下のように複数行に渡ってコメントを入力することもできます。

mysql> select 1 + /*
   /*> コメント
   /*> コメント2
   /*> */ 1;
+--------+
| 1 +  1 |
+--------+
|      2 |
+--------+
1 row in set (0.00 sec)
mysql>

このコメントの構文には、上で紹介した通常のコメント以外にMySQLで使える独自の拡張があります。/*!から始まるコメントは、MySQLで実行した時だけに実行されるもので、あまり使うことはないとは思いますが、他のRDBMSに載せ替える場合やMySQL固有の実装への依存を減らしたい場合などに使うことができます。

mysql> SELECT 1 /*!, Point(1, 1) */;
+---+---------------------------+
| 1 | Point(1, 1)               |
+---+---------------------------+
| 1 |              �?      �?   |
+---+---------------------------+
1 row in set (0.00 sec)

PointはMySQLの固有の関数なので、他のRDBMSでは実行できない場合もあるとは思いますが、その場合にもエラーになること無く実行することができます。

今回は例としてsqlite3で実行をしてみます。

sqlite> SELECT 1 , Point(1, 1);
Error: no such function: Point

sqlite3にはPoint関数が無いため、そのような関数はありませんというエラーが発生します。

sqlite> SELECT 1 /*!, Point(1, 1) */;
1

しかし、先ほどのコメント記法と同様に記述をすると、sqlite3ではSELECT 1;というSQLとして扱われて問題なく動作する事がわかります。複数の種類のRDBMSを同じデータに対して用途に分けて使い分けをしたい場合などに、どうしてもMySQL固有の関数を使いたい場合などに使用できます。

またMySQLでは上記のコメント文の制御に追加でバージョンを指定することで、特定のバージョンより前のバージョンでは実行しないという制御もできます。バージョンの指定は5桁の数字で行われます。現在は、メジャーバージョンが一桁、マイナーバージョンが二桁(1桁の場合は頭に0を足します⁠⁠、リビジョン番号が2桁という形で割り振られます。

今回は5.7.19で実行しているため、たとえば5.7.20を表す/*!50720を指定すると、その部分は実行されないはずです。ちょっと試してみましょう。下のようにSELECT文のフィールドをHOSTとコメント内でUSERを宣言するようにしてみます。

mysql> use mysql
mysql> SELECT HOST /*!50720 , USER */ from user;
+---------------------------------------+
| HOST                                  |
+---------------------------------------+
| %                                     |
| %                                     |
| 127.0.0.1                             |
| ::1                                   |
| localhost                             |
| localhost                             |
| localhost                             |
+---------------------------------------+
7 rows in set (0.00 sec)

コメント内にあるUSERフィールドに関しては無視されていることがわかります。

では、続いて今回の検証環境である5.7.19を表す/*!50719に変更して実行してみましょう。

mysql> SELECT HOST /*!50719 , USER */ from user;
+---------------------------------------+-----------+
| HOST                                  | USER      |
+---------------------------------------+-----------+
| %                                     | new_user  |
| %                                     | test      |
| 127.0.0.1                             | root      |
| ::1                                   | root      |
| localhost                             |           |
| localhost                             | mysql.sys |
| localhost                             | root      |
+---------------------------------------+-----------+
7 rows in set (0.00 sec)

このようにバージョン指定をしてSQLを実行させることができます。

このコメント文の使い方でよく目にするものとしては第15回 mysqldumpを使ってバックアップするで紹介したmysqldumpの出力結果などです。そこで今回はmysqlデータベースをmysqldumpで取り出してみて、mysqldumpではコメント文がどのように使われているか見てみようと思います。

# mysqldump -uroot mysql > mysql.sql

すると以下のようなヘッダが見られます。どのような環境でmysqldumpを行ったかがわかるようなヘッダになっています。実行したOSやMySQLのバージョンが --を使った記法で書かれていることがわかります。

-- MySQL dump 10.13  Distrib 5.7.19, for osx10.11 (x86_64)
--
-- Host: localhost    Database: mysql
-- ------------------------------------------------------
-- Server version       5.7.19

続いて/*!から始まるコメントが付いています。

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

…以下略…

この中で/*!40101という文字からスタートする文字列があります。こちらは先ほど説明したとおり、特定のバージョン未満に対して実行をしないという指定になります。/*!40101とした場合は4.1.1より前のMySQLでは実行されません。

mysqldumpのように複数のバージョンで使われることを想定したユーティリティ等を作成する際に使われることが多いです。

ログにコメントを出力する

mysqlコマンドラインクライアントでは、コメント文が削られてしまいサーバまでコメントが到達しません。コメント文までがログに出力されてたら簡単にSQLを特定できるのにと思うかもしれませんが、そんな時は-c--commentsオプションを付けて実行してみましょう。

まずは通常ではどのような動作になるか確認してみましょう。

# mysql -uroot
mysql> SET GLOBAL general_log=1;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like 'general_log_file';
+------------------+-------------------------+
| Variable_name    | Value                   |
+------------------+-------------------------+
| general_log_file | /Users/kk2170/query.log |
+------------------+-------------------------+
1 row in set (0.01 sec)

まずは準備としてSET GLOBAL general_log=1で一般ログを保存する設定を有効にします。そして、show variablesを使って一般ログファイルが何処に出力されるかを確認しました。次に簡単なSELECT文を実行してみます。

mysql> SELECT 1 + /* コメント */ 1;
+--------+
| 1 +  1 |
+--------+
|      2 |
+--------+
1 row in set (0.00 sec)

この時一般ログファイルに追加された行を確認してみましょう。

2017-09-15T06:59:41.778679Z        17 Query     SELECT 1 +  1

となっていてコメントが保存されていないことがわかります。続いて、mysqlクライアントに-cオプションを付けて実行してみます。

# mysql -uroot -c
mysql> SELECT 1 + /* コメント */ 1;
+--------+
| 1 +  1 |
+--------+
|      2 |
+--------+
1 row in set (0.00 sec)

この時に一般ログファイルに追加された行をみ見てみます。

2017-09-15T07:06:35.230128Z        18 Query     SELECT 1 + /* コメント */ 1

今度はコメントまで保存されていることがわかります。以上のようにオプションを追加することで一般ログファイルにコメントを出力させることが出来ました。また繰り返しにはなりますが、この設定はmysqlコマンドラインクライアントでの話であって、アプリケーションからのアクセスの場合は場合はログにコメントが、そのまま出力されます。

まとめ

今回はMySQLで使えるコメント文の紹介を行いました。適切なコメント文を適切に残していると開発時にわかりやすくなるだけではなく、開発時の意図を残すことによりDBのチューニングをする際の手がかりにもなります。このようにコメントは上手に仕込んでおくと便利なので、コメント文を上手に使っていきましょう。

おすすめ記事

記事・ニュース一覧