Go to the first, previous, next, last section, table of contents.


3 Tutorial Introduction

この章では、 mysql クライアントプログラムの使用の仕方と 単純なデータベースの作成と使用の仕方を例題としてとり上げます。 mysql (``terminal monitor'' や ``monitor'' として参照されます)は MySQL サーバーに接続できる対話モードのプログラムで、 クエリの実行や結果の表示が可能です。 mysql はバッチモードも可能です: クエリをまずファイルに書いておき、 そしてそのファイルを mysql に実行させます。 どちらの方法でも mysql はこの章の説明でカバーされます。

mysql の提供するオプションを見るには、 --help オプションを 実行します:

shell> mysql --help

この章では mysql が既にあなたのマシンにインストールされているものとし、 また MySQL サーバーに接続可能であるとします。 もしそうでないなら、 あなたの MySQL 管理者に連絡を取ってください。 (もしあなた自身が管理者なら、このマニュアルの他のセクションを参照してください。)

本章ではデータベース設定の全体のプロセス、データベースの使用について述べます。 もしあなたが既に存在しているデータベースにアクセスする事だけに興味があるなら、 この章のデータベース、テーブルの作成方法の説明を読み飛ばしてもかまいません。

この章が本質的にはチュートリアルであるので、多くの詳細は、かならず違う章にあります。 ここに書かれている事柄で、 さらに詳しい情報についてはマニュアルの適切なセクションを調べて下さい。

3.1 サーバーへの接続と切断

サーバーに mysql コマンドから接続するためには、通常、 MySQL ユーザ名、パスワードを指定する必要があるでしょう。 もしあなたがログインしている以外のマシンの上でサーバーが走っていれば、 あなたは、ホスト名を明示する必要があるでしょう。 まずあなたの管理者に問い合わせて、あなたが使うべき接続のためのパラメーターを見つけ出して下さい。 (すなわち、どのようなホスト、ユーザー名とパスワードを使うべきなのか。) 適切なパラメーターを知っていれば、あなたは、以下のようにして接続できます:

shell> mysql -h host -u user -p
Enter password: ********

******** とかかれている部分にはあなたのパスワードを入れます; mysqlEnter password: プロンプトを出したときに。

きちんと動けば、いくつかの情報と mysql> プロンプトが現れます:

shell> mysql -h host -u user -p
Enter password: ********
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 459 to server version: 3.22.20a-log

Type 'help' for help.

mysql>

このプロンプトは mysql がコマンド入力を待っている状態を示します。

いくつかの MySQL インストレーションでは、ローカルホストで 実行されているサーバーに、ユーザーに``匿名''(名前無し)の接続を許しています。 もしあなたのマシンがこの場合に当てはまるなら、mysql をオプション無しで 起動すべきです:

shell> mysql

接続が成功した後、 mysql> プロンプトで、QUIT とタイプすれば いつでも接続を切ることができます:

mysql> QUIT
Bye

Control-D で切断してもかまいません。

以下のセクションでのほとんどの例では、あなたがサーバーに接続しているものと しています。その場合は mysql> プロンプトによって、それを示しています。

3.2 Entering Queries

前のセクションで述べたように、あなたがサーバーとつながっていることを確かめて下さい。 この状態ではまだどんなデータベースも選択していない状態です。しかしそれはかまいません。 ここでは、テーブルの作成やデータの入力、取り出しよりも、 いかにクエリを発行するかに重点を置きます。 このセクションでは、あなた自身を mysql の動きに慣れさせるために、 あなたがやってみることができるであろう、いくつかのクエリを使用して、 コマンド入力の基本的な原則を述べます。

サーバーのバージョン、今日の日付をサーバーに問い合わせる、単純なコマンド がここにあります。 以下のように mysql> プロンプトの後に入力し RETURN キーを押してみてください:

mysql> SELECT VERSION(), CURRENT_DATE;
+--------------+--------------+
| VERSION()    | CURRENT_DATE |
+--------------+--------------+
| 3.22.20a-log | 1999-03-19   |
+--------------+--------------+
1 row in set (0.01 sec)
mysql>

このクエリは、mysql のいくつかの事を説明しています:

キーワードは、いかなる大文字小文字でも記述できます。 以下に示すクエリは同じです:

mysql> SELECT VERSION(), CURRENT_DATE;
mysql> select version(), current_date;
mysql> SeLeCt vErSiOn(), current_DATE;

以下のクエリは、mysql を簡単な計算機として使用した例です:

mysql> SELECT SIN(PI()/4), (4+1)*5;
+-------------+---------+
| SIN(PI()/4) | (4+1)*5 |
+-------------+---------+
|    0.707107 |      25 |
+-------------+---------+

今までは見てきたたコマンドは、比較的短い、一行のの文です。 あなたは一行に複数、文を書くことが出来ます。 それぞれの文の終わりにはセミコロンを付けます:

mysql> SELECT VERSION(); SELECT NOW();
+--------------+
| VERSION()    |
+--------------+
| 3.22.20a-log |
+--------------+

+---------------------+
| NOW()               |
+---------------------+
| 1999-03-19 00:15:33 |
+---------------------+

コマンドは一行にかく必要もありません。 複数行にわたる長いコマンドでも問題ありません。 mysql はセミコロンで、一文の終わりと見なします。 その行の最後を文の最後とは 見なしません。 (いうなれば、mysql は自由な入力を許し、セミコロンが現れるまでは それらの入力された行を実行しません)

複数行にまたがった文の例です:

mysql> SELECT
    -> USER()
    -> ,
    -> CURRENT_DATE;
+--------------------+--------------+
| USER()             | CURRENT_DATE |
+--------------------+--------------+
| joesmith@localhost | 1999-03-18   |
+--------------------+--------------+

この例では、複数にまたがるクエリにおいて、最初の行の入力のあと、 いかにプロンプトが mysql> から -> に変わるかを示しています。 これは mysql が、まだ文が終わっておらず、残りの部分の入力を待っている ことを示します。プロンプトは役立つフィードバックを提供してくれるあなたの友 人です。そのフィードバックを使用すると、mysql が何を待っているのか にいつも気が付くでしょう。

入力中にコマンドの実行を取りやめようと思った場合、 \c でこれをキャンセルできます:

mysql> SELECT
    -> USER()
    -> \c
mysql>

ここでもプロンプトに注意してください。\c のタイプ後に mysql> に戻っています。mysql が新しいコマンドの準備ができた ことを示すフィードバックを提供しています。

次のテーブルはあなたが目にするであろう各プロンプトと、それらが意味する mysql がどの状態にあるかについての要約です:

プロンプト 意味
mysql> 新しいコマンドの待状態
-> 複数行にまたがるコマンドの、次の行の入力を待っている状態。
'> シングルクオート (`'') で始められた文字の、次の行の入力を待っている状態。
"> ダブルクオート (`"') で始められた文字の、次の行の入力を待っている状態。

あなたが文をセミコロンで終わらすことを忘れて実行した場合に、 複数行の入力待ちが起こります。 この場合、 mysql は 次の入力を待ちます:

mysql> SELECT USER()
    ->

If this happens to you (you think you've entered a statement but the only response is a -> prompt), most likely mysql is waiting for the semicolon. If you don't notice what the prompt is telling you, you might sit there for a while before realising what you need to do. Enter a semicolon to complete the statement, and mysql will execute it:

mysql> SELECT USER()
    -> ;
+--------------------+
| USER()             |
+--------------------+
| joesmith@localhost |
+--------------------+

The '> and "> prompts occur during string collection. In MySQL, you can write strings surrounded by either `'' or `"' characters (for example, 'hello' or "goodbye"), and mysql lets you enter strings that span multiple lines. When you see a '> or "> prompt, it means that you've entered a line containing a string that begins with a `'' or `"' quote character, but have not yet entered the matching quote that terminates the string. That's fine if you really are entering a multiple-line string, but how likely is that? Not very. More often, the '> and "> prompts indicate that you've inadvertantly left out a quote character. For example:

mysql> SELECT * FROM my_table WHERE name = "Smith AND age < 30;
    ">

If you enter this SELECT statement, then press Enter and wait for the result, nothing will happen. Instead of wondering why this query takes so long, notice the clue provided by the "> prompt. It tells you that mysql expects to see the rest of an unterminated string. (Do you see the error in the statement? The string "Smith is missing the second quote.)

At this point, what do you do? The simplest thing is to cancel the command. However, you cannot just type \c in this case, because mysql interprets it as part of the string that it is collecting! Instead, enter the closing quote character (so mysql knows you've finished the string), then type \c:

mysql> SELECT * FROM my_table WHERE name = "Smith AND age < 30;
    "> "\c
mysql>

The prompt changes back to mysql>, indicating that mysql is ready for a new command.

It's important to know what the '> and "> prompts signify, because if you mistakenly enter an unterminated string, any further lines you type will appear to be ignored by mysql@-including a line containing QUIT! This can be quite confusing, especially if you don't know that you need to supply the terminating quote before you can cancel the current command.

3.3 Creating and Using a Database

Now that you know how to enter commands, it's time to access a database.

Suppose you have several pets in your home (your menagerie) and you'd like to keep track of various types of information about them. You can do so by creating tables to hold your data and loading them with the desired information. Then you can answer different sorts of questions about your animals by retrieving data from the tables. This section shows you how to:

The menagerie database will be simple (deliberately), but it is not difficult to think of real-world situations in which a similar type of database might be used. For example, a database like this could be used by a farmer to keep track of livestock, or by a veterinarian to keep track of patient records. A menagerie distribution containing some of the queries and sample data used in the following sections can be obtained from the MySQL web site. It's available in either compressed tar format (http://www.mysql.com/Downloads/Contrib/Examples/menagerie.tar.gz) or Zip format (http://www.mysql.com/Downloads/Contrib/Examples/menagerie.zip).

Use the SHOW statement to find out what databases currently exist on the server:

mysql> SHOW DATABASES;
+----------+
| Database |
+----------+
| mysql    |
| test     |
| tmp      |
+----------+

The list of databases is probably different on your machine, but the mysql and test databases are likely to be among them. The mysql database is required because it describes user access privileges. The test database is often provided as a workspace for users to try things out.

Note that you may not see all databases if you don't have the SHOW DATABASES privilege. 「4.3.1 GRANTREVOKE 構文」節参照.

If the test database exists, try to access it:

mysql> USE test
Database changed

Note that USE, like QUIT, does not require a semicolon. (You can terminate such statements with a semicolon if you like; it does no harm.) The USE statement is special in another way, too: it must be given on a single line.

You can use the test database (if you have access to it) for the examples that follow, but anything you create in that database can be removed by anyone else with access to it. For this reason, you should probably ask your MySQL administrator for permission to use a database of your own. Suppose you want to call yours menagerie. The administrator needs to execute a command like this:

mysql> GRANT ALL ON menagerie.* TO your_mysql_name;

where your_mysql_name is the MySQL user name assigned to you.

3.3.1 Creating and Selecting a Database

If the administrator creates your database for you when setting up your permissions, you can begin using it. Otherwise, you need to create it yourself:

mysql> CREATE DATABASE menagerie;

Under Unix, database names are case-sensitive (unlike SQL keywords), so you must always refer to your database as menagerie, not as Menagerie, MENAGERIE, or some other variant. This is also true for table names. (Under Windows, this restriction does not apply, although you must refer to databases and tables using the same lettercase throughout a given query.)

Creating a database does not select it for use; you must do that explicitly. To make menagerie the current database, use this command:

mysql> USE menagerie
Database changed

Your database needs to be created only once, but you must select it for use each time you begin a mysql session. You can do this by issuing a USE statement as shown above. Alternatively, you can select the database on the command-line when you invoke mysql. Just specify its name after any connection parameters that you might need to provide. For example:

shell> mysql -h host -u user -p menagerie
Enter password: ********

Note that menagerie is not your password on the command just shown. If you want to supply your password on the command-line after the -p option, you must do so with no intervening space (for example, as -pmypassword, not as -p mypassword). However, putting your password on the command-line is not recommended, because doing so exposes it to snooping by other users logged in on your machine.

3.3.2 テーブルの作成

データベースを作成することは容易ですが、作成しただけでは中身はからっぽです。 例えば SHOW TABLES を実行してみると以下のようになるでしょう:

mysql> SHOW TABLES;
Empty set (0.00 sec)

難しいのはデータベースの構造をどうするかを決定することです。 どんなテーブルが必要で、その中にどんな要素を入れるかです。

まずそれぞれのペットに関するレコードを含んだテーブルが必要でしょう。 これは pet テーブルとしましょう。 そしてその中には、最低でもそれぞれの動物の名前は入れる必要があるでしょう。 名前だけではあまり面白くないのでその他の情報も入れることにしましょう。例えば、もし家族の2人以上がペットを買っているならば、飼い主の名前も入れたくなるでしょう。 またその他にもペットの種類や性別など、いくつかの基本的な情報も入れたくなるかもしれません。

年齢はどうでしょうか? 確かにいいかもしれませんが、データベースに蓄積するにはあまり良くないものです。 年齢は時とともに変化します。つまりその都度レコードを更新する必要があるということです。 これに代わるデータとして適切なのは、例えば誕生日です。 そうしておいて年齢が必要なときは今日の日付と誕生日から計算すればよいのです。 MySQL には日付を算術演算する関数がありますので、難しいことはありません。 年齢ではなくて誕生日を記録しておくことには他のメリットもあります。

その他にも pet テーブルに加えるべき有用な情報はいろいろあるでしょう。 しかしとりあえずはこの辺で十分としましょう。名前、飼い主、種類、性別、誕生日、そして死亡日です。

CREATE TABLE 文を使ってテーブルのレイアウトを指定しましょう:

mysql> CREATE TABLE pet (name VARCHAR(20), owner VARCHAR(20),
    -> species VARCHAR(20), sex CHAR(1), birth DATE, death DATE);

name, owner,そしてspecies フィールドには VARCHAR を用いた方がよいでしょう。なぜならこれらの値の長さは変化するからです。 これらのフィールドの長さは全て同じである必要もなく、20文字である必要もありません。 1から255の間でもっともリーズナブルな値を選べばよいでしょう。 (長さの選択を誤ってあとで文字数が足らなくなったとしても、 MySQLは ALTER TABLE で長さを変えることができます)

動物の性別を表す値にはいくつかのタイプが考えられます。 "m""f" 、あるいは"male""female" なども考えられるでしょう。 ここでは最も簡単に、一文字の "m""f" で表すことにしましょう。

birthdeath のフィールドには、明らかに DATE データ型を用いるべきでしょう。

テーブルを作ってみると、SHOW TABLES で何らかの出力が得られるはずです:

mysql> SHOW TABLES;
+---------------------+
| Tables in menagerie |
+---------------------+
| pet                 |
+---------------------+

テーブルが期待したとおりに作成されたかどうかをチェックするために、 DESCRIBE 文を使います:

mysql> DESCRIBE pet;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| name    | varchar(20) | YES  |     | NULL    |       |
| owner   | varchar(20) | YES  |     | NULL    |       |
| species | varchar(20) | YES  |     | NULL    |       |
| sex     | char(1)     | YES  |     | NULL    |       |
| birth   | date        | YES  |     | NULL    |       |
| death   | date        | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+

DESCRIBE 文はいつでも、 例えばテーブルの列の名前やそのタイプを忘れてしまったときにも使うことが出来ます。

3.3.3 ファイルからデータをテーブルへ取り込む

テーブルを作ったら、中にデータを入れる必要があります。 このとき LOAD DATA 文とINSERT 文を用いると便利です。

例えばあなたのペットに関する記録が以下のようになっていたとします。 (MySQLにおける日付の表記が 'YYYY-MM-DD' の形式になっていることに注意してください。 あなたが慣れている形式とは異なるかもしれません)

name owner species sex birth death
Fluffy Harold cat f 1993-02-04
Claws Gwen cat m 1994-03-17
Buffy Harold dog f 1989-05-13
Fang Benny dog m 1990-08-27
Bowser Diane dog m 1998-08-31 1995-07-29
Chirpy Gwen bird f 1998-09-11
Whistler Gwen bird 1997-12-09
Slim Benny snake m 1996-04-29

もし空のテーブルから作り始めるのなら、 一行に一つのペットのデータを記述したテキストファイルを作っておいて、 先に挙げた命令で中身を読み込ませると楽です。

そのファイルを `pet.txt' とします。 各レコードを一行ずつ書き、各項目はタブで区切ります。 項目の順番は CREATE TABLE 文で定義したときと同じ順番とします。 項目が空のときは(例えばペットがまだ生きている場合、死亡日欄は空白です) NULL を用いることが出来ます。ファイル中では \N を用います。 例えば鳥の Whistler のレコードは以下のようになります。(項目の間の空白はタブ1個です):

name owner species sex birth death
Whistler Gwen bird \N 1997-12-09 \N

このファイル `pet.txt' をテーブル pet に読み込むには、以下のコマンドを用います:

mysql> LOAD DATA LOCAL INFILE "pet.txt" INTO TABLE pet;

もし必要であれば、項目の区切りや行末の符号を LOAD DATA 文で明示的に定めることが出来ます。 デフォルトでは区切りはタブ、行末はラインフィードです。 これにより `pet.txt' を適切に読み込むことが出来ます。

また新しい複数のレコードを1個づつ追加したいときは INSERT が便利です。 それぞれの項を CREATE TABLE で定義したときと同じ順番で入力するだけで追加できます。 例えばDianeが新しくハムスターをもらってきてPuffballと名づけました。 INSERT を用いて以下のようにレコードを追加することが出来ます:

mysql> INSERT INTO pet
    -> VALUES ('Puffball','Diane','hamster','f','1999-03-30',NULL);

文字列や日付を引用符号で括っていることに注意してください。 また INSERT を用いて空白の項を入力するときには NULL を直接挿入することができます。 LOAD DATA を使っているときとは違って \N は使えません。

この例から、初めにレコードを INSERT 文で入力するのは、 LOAD DATA 文を用いるよりも相当多くのタイピングを要してしまうことがわかると思います。

3.3.4 Retrieving Information from a Table

The SELECT statement is used to pull information from a table. The general form of the statement is:

SELECT what_to_select
FROM which_table
WHERE conditions_to_satisfy

what_to_select indicates what you want to see. This can be a list of columns, or * to indicate ``all columns.'' which_table indicates the table from which you want to retrieve data. The WHERE clause is optional. If it's present, conditions_to_satisfy specifies conditions that rows must satisfy to qualify for retrieval.

3.3.4.1 Selecting All Data

The simplest form of SELECT retrieves everything from a table:

mysql> SELECT * FROM pet;
+----------+--------+---------+------+------------+------------+
| name     | owner  | species | sex  | birth      | death      |
+----------+--------+---------+------+------------+------------+
| Fluffy   | Harold | cat     | f    | 1993-02-04 | NULL       |
| Claws    | Gwen   | cat     | m    | 1994-03-17 | NULL       |
| Buffy    | Harold | dog     | f    | 1989-05-13 | NULL       |
| Fang     | Benny  | dog     | m    | 1990-08-27 | NULL       |
| Bowser   | Diane  | dog     | m    | 1998-08-31 | 1995-07-29 |
| Chirpy   | Gwen   | bird    | f    | 1998-09-11 | NULL       |
| Whistler | Gwen   | bird    | NULL | 1997-12-09 | NULL       |
| Slim     | Benny  | snake   | m    | 1996-04-29 | NULL       |
| Puffball | Diane  | hamster | f    | 1999-03-30 | NULL       |
+----------+--------+---------+------+------------+------------+

This form of SELECT is useful if you want to review your entire table, for instance, after you've just loaded it with your initial dataset. As it happens, the output just shown reveals an error in your datafile: Bowser appears to have been born after he died! Consulting your original pedigree papers, you find that the correct birth year is 1989, not 1998.

There are least a couple of ways to fix this:

As shown above, it is easy to retrieve an entire table. But typically you don't want to do that, particularly when the table becomes large. Instead, you're usually more interested in answering a particular question, in which case you specify some constraints on the information you want. Let's look at some selection queries in terms of questions about your pets that they answer.

3.3.4.2 Selecting Particular Rows

You can select only particular rows from your table. For example, if you want to verify the change that you made to Bowser's birth date, select Bowser's record like this:

mysql> SELECT * FROM pet WHERE name = "Bowser";
+--------+-------+---------+------+------------+------------+
| name   | owner | species | sex  | birth      | death      |
+--------+-------+---------+------+------------+------------+
| Bowser | Diane | dog     | m    | 1989-08-31 | 1995-07-29 |
+--------+-------+---------+------+------------+------------+

The output confirms that the year is correctly recorded now as 1989, not 1998.

String comparisons are normally case-insensitive, so you can specify the name as "bowser", "BOWSER", etc. The query result will be the same.

You can specify conditions on any column, not just name. For example, if you want to know which animals were born after 1998, test the birth column:

mysql> SELECT * FROM pet WHERE birth >= "1998-1-1";
+----------+-------+---------+------+------------+-------+
| name     | owner | species | sex  | birth      | death |
+----------+-------+---------+------+------------+-------+
| Chirpy   | Gwen  | bird    | f    | 1998-09-11 | NULL  |
| Puffball | Diane | hamster | f    | 1999-03-30 | NULL  |
+----------+-------+---------+------+------------+-------+

You can combine conditions, for example, to locate female dogs:

mysql> SELECT * FROM pet WHERE species = "dog" AND sex = "f";
+-------+--------+---------+------+------------+-------+
| name  | owner  | species | sex  | birth      | death |
+-------+--------+---------+------+------------+-------+
| Buffy | Harold | dog     | f    | 1989-05-13 | NULL  |
+-------+--------+---------+------+------------+-------+

The preceding query uses the AND logical operator. There is also an OR operator:

mysql> SELECT * FROM pet WHERE species = "snake" OR species = "bird";
+----------+-------+---------+------+------------+-------+
| name     | owner | species | sex  | birth      | death |
+----------+-------+---------+------+------------+-------+
| Chirpy   | Gwen  | bird    | f    | 1998-09-11 | NULL  |
| Whistler | Gwen  | bird    | NULL | 1997-12-09 | NULL  |
| Slim     | Benny | snake   | m    | 1996-04-29 | NULL  |
+----------+-------+---------+------+------------+-------+

AND and OR may be intermixed. If you do that, it's a good idea to use parentheses to indicate how conditions should be grouped:

mysql> SELECT * FROM pet WHERE (species = "cat" AND sex = "m")
    -> OR (species = "dog" AND sex = "f");
+-------+--------+---------+------+------------+-------+
| name  | owner  | species | sex  | birth      | death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen   | cat     | m    | 1994-03-17 | NULL  |
| Buffy | Harold | dog     | f    | 1989-05-13 | NULL  |
+-------+--------+---------+------+------------+-------+

3.3.4.3 Selecting Particular Columns

If you don't want to see entire rows from your table, just name the columns in which you're interested, separated by commas. For example, if you want to know when your animals were born, select the name and birth columns:

mysql> SELECT name, birth FROM pet;
+----------+------------+
| name     | birth      |
+----------+------------+
| Fluffy   | 1993-02-04 |
| Claws    | 1994-03-17 |
| Buffy    | 1989-05-13 |
| Fang     | 1990-08-27 |
| Bowser   | 1989-08-31 |
| Chirpy   | 1998-09-11 |
| Whistler | 1997-12-09 |
| Slim     | 1996-04-29 |
| Puffball | 1999-03-30 |
+----------+------------+

To find out who owns pets, use this query:

mysql> SELECT owner FROM pet;
+--------+
| owner  |
+--------+
| Harold |
| Gwen   |
| Harold |
| Benny  |
| Diane  |
| Gwen   |
| Gwen   |
| Benny  |
| Diane  |
+--------+

However, notice that the query simply retrieves the owner field from each record, and some of them appear more than once. To minimise the output, retrieve each unique output record just once by adding the keyword DISTINCT:

mysql> SELECT DISTINCT owner FROM pet;
+--------+
| owner  |
+--------+
| Benny  |
| Diane  |
| Gwen   |
| Harold |
+--------+

You can use a WHERE clause to combine row selection with column selection. For example, to get birth dates for dogs and cats only, use this query:

mysql> SELECT name, species, birth FROM pet
    -> WHERE species = "dog" OR species = "cat";
+--------+---------+------------+
| name   | species | birth      |
+--------+---------+------------+
| Fluffy | cat     | 1993-02-04 |
| Claws  | cat     | 1994-03-17 |
| Buffy  | dog     | 1989-05-13 |
| Fang   | dog     | 1990-08-27 |
| Bowser | dog     | 1989-08-31 |
+--------+---------+------------+

3.3.4.4 Sorting Rows

You may have noticed in the preceding examples that the result rows are displayed in no particular order. However, it's often easier to examine query output when the rows are sorted in some meaningful way. To sort a result, use an ORDER BY clause.

Here are animal birthdays, sorted by date:

mysql> SELECT name, birth FROM pet ORDER BY birth;
+----------+------------+
| name     | birth      |
+----------+------------+
| Buffy    | 1989-05-13 |
| Bowser   | 1989-08-31 |
| Fang     | 1990-08-27 |
| Fluffy   | 1993-02-04 |
| Claws    | 1994-03-17 |
| Slim     | 1996-04-29 |
| Whistler | 1997-12-09 |
| Chirpy   | 1998-09-11 |
| Puffball | 1999-03-30 |
+----------+------------+

On character type columns, sorting@-like all other comparison operations@-is normally performed in a case-insensitive fashion. This means that the order will be undefined for columns that are identical except for their case. You can force a case-sensitive sort by using the BINARY cast: ORDER BY BINARY(field).

To sort in reverse order, add the DESC (descending) keyword to the name of the column you are sorting by:

mysql> SELECT name, birth FROM pet ORDER BY birth DESC;
+----------+------------+
| name     | birth      |
+----------+------------+
| Puffball | 1999-03-30 |
| Chirpy   | 1998-09-11 |
| Whistler | 1997-12-09 |
| Slim     | 1996-04-29 |
| Claws    | 1994-03-17 |
| Fluffy   | 1993-02-04 |
| Fang     | 1990-08-27 |
| Bowser   | 1989-08-31 |
| Buffy    | 1989-05-13 |
+----------+------------+

You can sort on multiple columns. For example, to sort by type of animal, then by birth date within animal type with youngest animals first, use the following query:

mysql> SELECT name, species, birth FROM pet ORDER BY species, birth DESC;
+----------+---------+------------+
| name     | species | birth      |
+----------+---------+------------+
| Chirpy   | bird    | 1998-09-11 |
| Whistler | bird    | 1997-12-09 |
| Claws    | cat     | 1994-03-17 |
| Fluffy   | cat     | 1993-02-04 |
| Fang     | dog     | 1990-08-27 |
| Bowser   | dog     | 1989-08-31 |
| Buffy    | dog     | 1989-05-13 |
| Puffball | hamster | 1999-03-30 |
| Slim     | snake   | 1996-04-29 |
+----------+---------+------------+

Note that the DESC keyword applies only to the column name immediately preceding it (birth); species values are still sorted in ascending order.

3.3.4.5 日付の計算

MySQL はいくつかの日付の計算を行う関数を提供します。 例えば、年の計算や日付の部分を取り出したり。

To determine how many years old each of your pets is, compute the difference in the year part of the current date and the birth date, then subtract one if the current date occurs earlier in the calendar year than the birth date. The following query shows, for each pet, the birth date, the current date, and the age in years.

mysql> SELECT name, birth, CURRENT_DATE,
    -> (YEAR(CURRENT_DATE)-YEAR(birth))
    -> - (RIGHT(CURRENT_DATE,5)<RIGHT(birth,5))
    -> AS age
    -> FROM pet;
+----------+------------+--------------+------+
| name     | birth      | CURRENT_DATE | age  |
+----------+------------+--------------+------+
| Fluffy   | 1993-02-04 | 2001-08-29   |    8 |
| Claws    | 1994-03-17 | 2001-08-29   |    7 |
| Buffy    | 1989-05-13 | 2001-08-29   |   12 |
| Fang     | 1990-08-27 | 2001-08-29   |   11 |
| Bowser   | 1989-08-31 | 2001-08-29   |   11 |
| Chirpy   | 1998-09-11 | 2001-08-29   |    2 |
| Whistler | 1997-12-09 | 2001-08-29   |    3 |
| Slim     | 1996-04-29 | 2001-08-29   |    5 |
| Puffball | 1999-03-30 | 2001-08-29   |    2 |
+----------+------------+--------------+------+

Here, YEAR() pulls out the year part of a date and RIGHT() pulls off the rightmost five characters that represent the MM-DD (calendar year) part of the date. The part of the expression that compares the MM-DD values evaluates to 1 or 0, which adjusts the year difference down a year if CURRENT_DATE occurs earlier in the year than birth. The full expression is somewhat ungainly, so an alias (age) is used to make the output column label more meaningful.

The query works, but the result could be scanned more easily if the rows were presented in some order. This can be done by adding an ORDER BY name clause to sort the output by name:

mysql> SELECT name, birth, CURRENT_DATE,
    -> (YEAR(CURRENT_DATE)-YEAR(birth))
    -> - (RIGHT(CURRENT_DATE,5)<RIGHT(birth,5))
    -> AS age
    -> FROM pet ORDER BY name;
+----------+------------+--------------+------+
| name     | birth      | CURRENT_DATE | age  |
+----------+------------+--------------+------+
| Bowser   | 1989-08-31 | 2001-08-29   |   11 |
| Buffy    | 1989-05-13 | 2001-08-29   |   12 |
| Chirpy   | 1998-09-11 | 2001-08-29   |    2 |
| Claws    | 1994-03-17 | 2001-08-29   |    7 |
| Fang     | 1990-08-27 | 2001-08-29   |   11 |
| Fluffy   | 1993-02-04 | 2001-08-29   |    8 |
| Puffball | 1999-03-30 | 2001-08-29   |    2 |
| Slim     | 1996-04-29 | 2001-08-29   |    5 |
| Whistler | 1997-12-09 | 2001-08-29   |    3 |
+----------+------------+--------------+------+

To sort the output by age rather than name, just use a different ORDER BY clause:

mysql> SELECT name, birth, CURRENT_DATE,
    -> (YEAR(CURRENT_DATE)-YEAR(birth))
    -> - (RIGHT(CURRENT_DATE,5)<RIGHT(birth,5))
    -> AS age
    -> FROM pet ORDER BY age;
+----------+------------+--------------+------+
| name     | birth      | CURRENT_DATE | age  |
+----------+------------+--------------+------+
| Chirpy   | 1998-09-11 | 2001-08-29   |    2 |
| Puffball | 1999-03-30 | 2001-08-29   |    2 |
| Whistler | 1997-12-09 | 2001-08-29   |    3 |
| Slim     | 1996-04-29 | 2001-08-29   |    5 |
| Claws    | 1994-03-17 | 2001-08-29   |    7 |
| Fluffy   | 1993-02-04 | 2001-08-29   |    8 |
| Fang     | 1990-08-27 | 2001-08-29   |   11 |
| Bowser   | 1989-08-31 | 2001-08-29   |   11 |
| Buffy    | 1989-05-13 | 2001-08-29   |   12 |
+----------+------------+--------------+------+

似たクエリが、既に死んでしまった動物の、死んだ時点の年齢を調べるのにも 使用できます。 どの動物が死んでいるかどうかは、death 値が NULL か どうかで判断します。 これらの値が 非NULL ならば、 deathbirth の差の計算を行います:

mysql> SELECT name, birth, death,
    -> (YEAR(death)-YEAR(birth)) - (RIGHT(death,5)<RIGHT(birth,5))
    -> AS age
    -> FROM pet WHERE death IS NOT NULL ORDER BY age;
+--------+------------+------------+------+
| name   | birth      | death      | age  |
+--------+------------+------------+------+
| Bowser | 1989-08-31 | 1995-07-29 |    5 |
+--------+------------+------------+------+

このクエリでは、 death <> NULL ではなく death IS NOT NULL を 使用します。 なぜなら、 NULL は特別な値だからです。 これは後で解説します。 「3.3.4.6 NULL 値の振る舞い」節参照.

もしあなたが翌月誕生日の動物を知りたいとします。 この種の計算では、 年と日が関係ありません。 birth フィールドの月だけを単に 取り出したくなるでしょう。 MySQL は日付の部分を取り出すいくつかの関数を 提供します。 YEAR(), MONTH(), DAYOFMONTH() など。 ここでは MONTH() がいいでしょう。 これがどのように動くか確かめるには、 birthMONTH(birth) の両方を表示させるクエリを実行してみます:

mysql> SELECT name, birth, MONTH(birth) FROM pet;
+----------+------------+--------------+
| name     | birth      | MONTH(birth) |
+----------+------------+--------------+
| Fluffy   | 1993-02-04 |            2 |
| Claws    | 1994-03-17 |            3 |
| Buffy    | 1989-05-13 |            5 |
| Fang     | 1990-08-27 |            8 |
| Bowser   | 1989-08-31 |            8 |
| Chirpy   | 1998-09-11 |            9 |
| Whistler | 1997-12-09 |           12 |
| Slim     | 1996-04-29 |            4 |
| Puffball | 1999-03-30 |            3 |
+----------+------------+--------------+

来月誕生日を迎える動物を見つけるのは簡単です。 現在4月だとします。 すると、5月生まれの動物を探します:

mysql> SELECT name, birth FROM pet WHERE MONTH(birth) = 5;
+-------+------------+
| name  | birth      |
+-------+------------+
| Buffy | 1989-05-13 |
+-------+------------+

もし現在が12月なら、ちょっと困るかもしれません。 月の数字 (12) に 1 を足して 13 月生まれの動物を探すわけにはいきません。 かわりに1月生まれの 動物を探します。

現在が何月なのかを気にすることなく、動作するクエリを書くことが可能です。 この方法では、あなたは月の数字をクエリに使用することがありません。 DATE_ADD() 関数は与えた日付からある時間を足すことが可能です。 もし現時点 NOW() の値に 1ヶ月 足し、 MONTH() で月の 部分を取り出し、その結果を、誕生月を調べるために使用します:

mysql> SELECT name, birth FROM pet
    -> WHERE MONTH(birth) = MONTH(DATE_ADD(NOW(), INTERVAL 1 MONTH));

同じことができる別の方法として、剰余関数 を使用した結果に 1 を足す方法があります。 (もし今月が12月なら、剰余関数 (MOD) を使用した結果は 0 になります):

mysql> SELECT name, birth FROM pet
    -> WHERE MONTH(birth) = MOD(MONTH(NOW()), 12) + 1;

Note that MONTH returns a number between 1 and 12. And MOD(something,12) returns a number between 0 and 11. So the addition has to be after the MOD(), otherwise we would go from November (11) to January (1).

3.3.4.6 NULL 値の振る舞い

あなたがそれに慣れるまでは、NULL 値には驚くかもしれません。 概念的に、NULL 値は ``値無し'' か ``未知な値'' を意味し、 他の値よりもいくぶん異なって扱われます。 NULL の評価の際には、数値の比較演算子 =, <, <> を 使用することは出来ません。 あなた自身これをデモするために、以下のようにしてみてください:

mysql> SELECT 1 = NULL, 1 <> NULL, 1 < NULL, 1 > NULL;
+----------+-----------+----------+----------+
| 1 = NULL | 1 <> NULL | 1 < NULL | 1 > NULL |
+----------+-----------+----------+----------+
|     NULL |      NULL |     NULL |     NULL |
+----------+-----------+----------+----------+

確実にこれらの比較からいかなる意味がある結果も受け取りません。 この代わりに、 IS NULL , IS NOT NULL 演算子を使用します:

mysql> SELECT 1 IS NULL, 1 IS NOT NULL;
+-----------+---------------+
| 1 IS NULL | 1 IS NOT NULL |
+-----------+---------------+
|         0 |             1 |
+-----------+---------------+

MySQL では, 0 や NULL は false(偽) で、それ以外全てが true(真)です。 The default truth value from a boolean operation is 1.

この NULL の特別な扱いはなぜなのか。 前のセクションを見てください。 どの動物がもはや生きていないことを決定づけるためには、 death <> NULL ではなく death IS NOT NULL の使用が 必要とされるのです。

Two NULL values are regarded as equal in a GROUP BY.

When doing an ORDER BY, NULL values are presented first if you do ORDER BY ... ASC and last if you do ORDER BY ... DESC.

Note that between MySQL 4.0.2 - 4.0.10, NULL values incorrectly were always sorted first regardless of the sort direction.

3.3.4.7 パターン・マッチ

MySQL は標準SQLのパターン・マッチを提供します。 また、拡張された正規表現を基にした形式のパターン・マッチ、 これは vi, grep , sed など UNIX のユーティリティに 使用されている物と似ていますが、これも提供します。

SQL パターン・マッチは、 `_' でいかなる1文字とも一致し、 `%' であらゆる0こ以上の文字列に一致します。 MySQL では、デフォルトで SQL パターンはケース非依存です。 いくつか例を以下に示します。 SQLパターンを使用する場合、 =!= を使用しないように注意してください。 LIKENOT LIKE を代わりに使用します。

`b' から始まる名前を見つけるには:

mysql> SELECT * FROM pet WHERE name LIKE "b%";
+--------+--------+---------+------+------------+------------+
| name   | owner  | species | sex  | birth      | death      |
+--------+--------+---------+------+------------+------------+
| Buffy  | Harold | dog     | f    | 1989-05-13 | NULL       |
| Bowser | Diane  | dog     | m    | 1989-08-31 | 1995-07-29 |
+--------+--------+---------+------+------------+------------+

`fy' で終わる名前を見つけるには:

mysql> SELECT * FROM pet WHERE name LIKE "%fy";
+--------+--------+---------+------+------------+-------+
| name   | owner  | species | sex  | birth      | death |
+--------+--------+---------+------+------------+-------+
| Fluffy | Harold | cat     | f    | 1993-02-04 | NULL  |
| Buffy  | Harold | dog     | f    | 1989-05-13 | NULL  |
+--------+--------+---------+------+------------+-------+

`w' を含む名前を見つけるには:

mysql> SELECT * FROM pet WHERE name LIKE "%w%";
+----------+-------+---------+------+------------+------------+
| name     | owner | species | sex  | birth      | death      |
+----------+-------+---------+------+------------+------------+
| Claws    | Gwen  | cat     | m    | 1994-03-17 | NULL       |
| Bowser   | Diane | dog     | m    | 1989-08-31 | 1995-07-29 |
| Whistler | Gwen  | bird    | NULL | 1997-12-09 | NULL       |
+----------+-------+---------+------+------------+------------+

5文字の名前を見つけるには, `_' パターン文字を使用して:

mysql> SELECT * FROM pet WHERE name LIKE "_____";
+-------+--------+---------+------+------------+-------+
| name  | owner  | species | sex  | birth      | death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen   | cat     | m    | 1994-03-17 | NULL  |
| Buffy | Harold | dog     | f    | 1989-05-13 | NULL  |
+-------+--------+---------+------+------------+-------+

MySQL では他のパターン・マッチの形も提供されます。正規表現の拡張を使用して。 これらのパターン・マッチをテストする際には、REGEXPNOT REGEXP 演算子(あるいはRLIKE, NOT RLIKE 演算子。これらは同義です) を使用します。

拡張正規表現のいくつかの特徴:

以下は拡張された正規表現がどう動くかの例です。 上に示した LIKE のクエリは REGEXP で以下のように書き換えれます:

`b' で始まる名前をみつけるには、`^' で名前の頭にマッチさせ、 かつ `[bB]' として、大文字小文字にもマッチさせます:

mysql> SELECT * FROM pet WHERE name REGEXP "^b";
+--------+--------+---------+------+------------+------------+
| name   | owner  | species | sex  | birth      | death      |
+--------+--------+---------+------+------------+------------+
| Buffy  | Harold | dog     | f    | 1989-05-13 | NULL       |
| Bowser | Diane  | dog     | m    | 1989-08-31 | 1995-07-29 |
+--------+--------+---------+------+------------+------------+

Prior to MySQL Version 3.23.4, REGEXP is case-sensitive, and the previous query will return no rows. To match either lowercase or uppercase `b', use this query instead:

mysql> SELECT * FROM pet WHERE name REGEXP "^[bB]";

From MySQL 3.23.4 on, to force a REGEXP comparison to be case-sensitive, use the BINARY keyword to make one of the strings a binary string. This query will match only lowercase `b' at the beginning of a name:

mysql> SELECT * FROM pet WHERE name REGEXP BINARY "^b";

To find names ending with `fy', use `$' to match the end of the name:

mysql> SELECT * FROM pet WHERE name REGEXP "fy$";
+--------+--------+---------+------+------------+-------+
| name   | owner  | species | sex  | birth      | death |
+--------+--------+---------+------+------------+-------+
| Fluffy | Harold | cat     | f    | 1993-02-04 | NULL  |
| Buffy  | Harold | dog     | f    | 1989-05-13 | NULL  |
+--------+--------+---------+------+------------+-------+

To find names containing a lowercase or uppercase `w', use this query:

mysql> SELECT * FROM pet WHERE name REGEXP "w";
+----------+-------+---------+------+------------+------------+
| name     | owner | species | sex  | birth      | death      |
+----------+-------+---------+------+------------+------------+
| Claws    | Gwen  | cat     | m    | 1994-03-17 | NULL       |
| Bowser   | Diane | dog     | m    | 1989-08-31 | 1995-07-29 |
| Whistler | Gwen  | bird    | NULL | 1997-12-09 | NULL       |
+----------+-------+---------+------+------------+------------+

正規表現はもし値中のどこかにでもあればマッチするため、 SQL パターンのように、パターンの前後にワイルドカードを書く必要はありません。

5文字の名前を見つけるには、`^'`$' を使用して名前の初めと終わりに マッチさせ、その間に `.' を5個入れます:

mysql> SELECT * FROM pet WHERE name REGEXP "^.....$";
+-------+--------+---------+------+------------+-------+
| name  | owner  | species | sex  | birth      | death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen   | cat     | m    | 1994-03-17 | NULL  |
| Buffy | Harold | dog     | f    | 1989-05-13 | NULL  |
+-------+--------+---------+------+------------+-------+

前のクエリは `{n}' ``n回繰り返し'' オペレーターで 書換え可能です。

mysql> SELECT * FROM pet WHERE name REGEXP "^.{5}$";
+-------+--------+---------+------+------------+-------+
| name  | owner  | species | sex  | birth      | death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen   | cat     | m    | 1994-03-17 | NULL  |
| Buffy | Harold | dog     | f    | 1989-05-13 | NULL  |
+-------+--------+---------+------+------------+-------+

3.3.4.8 Counting Rows

Databases are often used to answer the question, ``How often does a certain type of data occur in a table?'' For example, you might want to know how many pets you have, or how many pets each owner has, or you might want to perform various kinds of censuses on your animals.

Counting the total number of animals you have is the same question as ``How many rows are in the pet table?'' because there is one record per pet. The COUNT() function counts the number of non-NULL results, so the query to count your animals looks like this:

mysql> SELECT COUNT(*) FROM pet;
+----------+
| COUNT(*) |
+----------+
|        9 |
+----------+

Earlier, you retrieved the names of the people who owned pets. You can use COUNT() if you want to find out how many pets each owner has:

mysql> SELECT owner, COUNT(*) FROM pet GROUP BY owner;
+--------+----------+
| owner  | COUNT(*) |
+--------+----------+
| Benny  |        2 |
| Diane  |        2 |
| Gwen   |        3 |
| Harold |        2 |
+--------+----------+

Note the use of GROUP BY to group together all records for each owner. Without it, all you get is an error message:

mysql> SELECT owner, COUNT(owner) FROM pet;
ERROR 1140 at line 1: Mixing of GROUP columns (MIN(),MAX(),COUNT()...)
with no GROUP columns is illegal if there is no GROUP BY clause

COUNT() and GROUP BY are useful for characterising your data in various ways. The following examples show different ways to perform animal census operations.

Number of animals per species:

mysql> SELECT species, COUNT(*) FROM pet GROUP BY species;
+---------+----------+
| species | COUNT(*) |
+---------+----------+
| bird    |        2 |
| cat     |        2 |
| dog     |        3 |
| hamster |        1 |
| snake   |        1 |
+---------+----------+

Number of animals per sex:

mysql> SELECT sex, COUNT(*) FROM pet GROUP BY sex;
+------+----------+
| sex  | COUNT(*) |
+------+----------+
| NULL |        1 |
| f    |        4 |
| m    |        4 |
+------+----------+

(In this output, NULL indicates sex unknown.)

Number of animals per combination of species and sex:

mysql> SELECT species, sex, COUNT(*) FROM pet GROUP BY species, sex;
+---------+------+----------+
| species | sex  | COUNT(*) |
+---------+------+----------+
| bird    | NULL |        1 |
| bird    | f    |        1 |
| cat     | f    |        1 |
| cat     | m    |        1 |
| dog     | f    |        1 |
| dog     | m    |        2 |
| hamster | f    |        1 |
| snake   | m    |        1 |
+---------+------+----------+

You need not retrieve an entire table when you use COUNT(). For example, the previous query, when performed just on dogs and cats, looks like this:

mysql> SELECT species, sex, COUNT(*) FROM pet
    -> WHERE species = "dog" OR species = "cat"
    -> GROUP BY species, sex;
+---------+------+----------+
| species | sex  | COUNT(*) |
+---------+------+----------+
| cat     | f    |        1 |
| cat     | m    |        1 |
| dog     | f    |        1 |
| dog     | m    |        2 |
+---------+------+----------+

Or, if you wanted the number of animals per sex only for known-sex animals:

mysql> SELECT species, sex, COUNT(*) FROM pet
    -> WHERE sex IS NOT NULL
    -> GROUP BY species, sex;
+---------+------+----------+
| species | sex  | COUNT(*) |
+---------+------+----------+
| bird    | f    |        1 |
| cat     | f    |        1 |
| cat     | m    |        1 |
| dog     | f    |        1 |
| dog     | m    |        2 |
| hamster | f    |        1 |
| snake   | m    |        1 |
+---------+------+----------+

3.3.4.9 Using More Than one Table

The pet table keeps track of which pets you have. If you want to record other information about them, such as events in their lives like visits to the vet or when litters are born, you need another table. What should this table look like? It needs:

Given these considerations, the CREATE TABLE statement for the event table might look like this:

mysql> CREATE TABLE event (name VARCHAR(20), date DATE,
    -> type VARCHAR(15), remark VARCHAR(255));

As with the pet table, it's easiest to load the initial records by creating a tab-delimited text file containing the information:

name date type remark
Fluffy 1995-05-15 litter 4 kittens, 3 female, 1 male
Buffy 1993-06-23 litter 5 puppies, 2 female, 3 male
Buffy 1994-06-19 litter 3 puppies, 3 female
Chirpy 1999-03-21 vet needed beak straightened
Slim 1997-08-03 vet broken rib
Bowser 1991-10-12 kennel
Fang 1991-10-12 kennel
Fang 1998-08-28 birthday Gave him a new chew toy
Claws 1998-03-17 birthday Gave him a new flea collar
Whistler 1998-12-09 birthday First birthday

Load the records like this:

mysql> LOAD DATA LOCAL INFILE "event.txt" INTO TABLE event;

Based on what you've learned from the queries you've run on the pet table, you should be able to perform retrievals on the records in the event table; the principles are the same. But when is the event table by itself insufficient to answer questions you might ask?

Suppose you want to find out the ages of each pet when they had their litters. The event table indicates when this occurred, but to calculate the age of the mother, you need her birth date. Because that is stored in the pet table, you need both tables for the query:

mysql> SELECT pet.name,
    -> (TO_DAYS(date) - TO_DAYS(birth))/365 AS age,
    -> remark
    -> FROM pet, event
    -> WHERE pet.name = event.name AND type = "litter";
+--------+------+-----------------------------+
| name   | age  | remark                      |
+--------+------+-----------------------------+
| Fluffy | 2.27 | 4 kittens, 3 female, 1 male |
| Buffy  | 4.12 | 5 puppies, 2 female, 3 male |
| Buffy  | 5.10 | 3 puppies, 3 female         |
+--------+------+-----------------------------+

There are several things to note about this query:

You need not have two different tables to perform a join. Sometimes it is useful to join a table to itself, if you want to compare records in a table to other records in that same table. For example, to find breeding pairs among your pets, you can join the pet table with itself to pair up males and females of like species:

mysql> SELECT p1.name, p1.sex, p2.name, p2.sex, p1.species
    -> FROM pet AS p1, pet AS p2
    -> WHERE p1.species = p2.species AND p1.sex = "f" AND p2.sex = "m";
+--------+------+--------+------+---------+
| name   | sex  | name   | sex  | species |
+--------+------+--------+------+---------+
| Fluffy | f    | Claws  | m    | cat     |
| Buffy  | f    | Fang   | m    | dog     |
| Buffy  | f    | Bowser | m    | dog     |
+--------+------+--------+------+---------+

In this query, we specify aliases for the table name in order to refer to the columns and keep straight which instance of the table each column reference is associated with.

3.4 データベースとテーブルの情報を得る

データベースやテーブルの名前が何であったか、あるいはテーブルの構造はどうであったか、 (なんというフィールドがあったのか)忘れてしまった場合。 MySQL ではいくつかのデータベースとテーブルの情報を提供する文を通じて この問題を処理します。

あなたは既に SHOW DATABASES を知っているはずで, これはサーバーが 管理するデーターベースの一覧を表示します。 現在選択しているデータベースが 何であるかを知るには、DATABASE() 関数を使用します:

mysql> SELECT DATABASE();
+------------+
| DATABASE() |
+------------+
| menagerie  |
+------------+

もしデータベースをまだ何も選択していなければ、結果はブランクです。

データベースに含まれるテーブルを見つけるには(たとえば、あなたがテーブル名を 知らない場合)、このコマンドを使用します:

mysql> SHOW TABLES;
+---------------------+
| Tables in menagerie |
+---------------------+
| event               |
| pet                 |
+---------------------+

もしテーブルの構造を知りたいなら、DESCRIBE コマンドが便利です; これはテーブルのそれぞれのフィールドについての情報を表示します。

mysql> DESCRIBE pet;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| name    | varchar(20) | YES  |     | NULL    |       |
| owner   | varchar(20) | YES  |     | NULL    |       |
| species | varchar(20) | YES  |     | NULL    |       |
| sex     | char(1)     | YES  |     | NULL    |       |
| birth   | date        | YES  |     | NULL    |       |
| death   | date        | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+

Field はフィールド名を示し、Type はフィールドのデータ型、 Null はこのフィールドが Null 値を含むかを示し、 Key はこのフィールドがインデックス化されているかを示し、 Default はフィールドのデフォルトの値を示します。

もしテーブルにインデックスを持っているなら、 SHOW INDEX FROM tbl_name がそれらの情報を示します。

3.5 一般的なクエリー例

以下は、MySQLの一般的な問題を解決するための例です。

Some of the examples use the table shop to hold the price of each article (item number) for certain traders (dealers). 各業者に対して各商品の価格が1つ決められているとし、(article, dealer)をレコードの主キーとします。

Start the command-line tool mysql and select a database:

mysql your-database-name

(MySQLのインストールを通常通り行った場合は、'test'データベースをお使いいただけます。)

以下のSQL文でサンプル テーブルを作成します。

CREATE TABLE shop (
 article INT(4) UNSIGNED ZEROFILL DEFAULT '0000' NOT NULL,
 dealer  CHAR(20)                 DEFAULT ''     NOT NULL,
 price   DOUBLE(16,2)             DEFAULT '0.00' NOT NULL,
 PRIMARY KEY(article, dealer));

INSERT INTO shop VALUES
(1,'A',3.45),(1,'B',3.99),(2,'A',10.99),(3,'B',1.45),(3,'C',1.69),
(3,'D',1.25),(4,'D',19.95);

サンプル データを表示します。

mysql> SELECT * FROM shop;

+---------+--------+-------+
| article | dealer | price |
+---------+--------+-------+
|    0001 | A      |  3.45 |
|    0001 | B      |  3.99 |
|    0002 | A      | 10.99 |
|    0003 | B      |  1.45 |
|    0003 | C      |  1.69 |
|    0003 | D      |  1.25 |
|    0004 | D      | 19.95 |
+---------+--------+-------+

3.5.1 カラムの最大値

”articleカラムの最大値は?”

SELECT MAX(article) AS article FROM shop

+---------+
| article |
+---------+
|       4 |
+---------+

3.5.2 特定のカラムの最大値を含んだ行

”最も高い価格の商品の番号と、業者、価格を求める。”

ANSI SQL(MySQLではVersion4.1から)では、副問い合わせを使用することで簡単に求められます。

SELECT article, dealer, price
FROM   shop
WHERE  price=(SELECT MAX(price) FROM shop)

MySQL4.1以前では、以下の2つのステップで求めます。

  1. SELECT構文でテーブルから最大値を取得します。
  2. 1で求めた値をに使用して、実際のクエリーをコンパイルします。
    SELECT article, dealer, price
    FROM   shop
    WHERE  price=19.95
    

その他には全ての行をpriceカラムをもとに降順で並び替え、 MySQL特有 LIMIT 節を使用して最初の行のみを取得する方法があります。

SELECT article, dealer, price
FROM   shop
ORDER BY price DESC
LIMIT 1

注意:一番高い商品が複数存在する場合は(例えば、19.95ドルの商品が複数ある場合)、LIMIT 節はそのうちの1つの商品しか表示しません。

3.5.3 カラムのグループごとの最大値

”商品ごとの価格の最大値は?”

SELECT article, MAX(price) AS price
FROM   shop
GROUP BY article

+---------+-------+
| article | price |
+---------+-------+
|    0001 |  3.99 |
|    0002 | 10.99 |
|    0003 |  1.69 |
|    0004 | 19.95 |
+---------+-------+

3.5.4 The Rows Holding the Group-wise Maximum of a Certain Field

``For each article, find the dealer(s) with the most expensive price.''

In ANSI SQL (and MySQL Version 4.1 or greater), I'd do it with a subquery like this:

SELECT article, dealer, price
FROM   shop s1
WHERE  price=(SELECT MAX(s2.price)
              FROM shop s2
              WHERE s1.article = s2.article);

In MySQL versions prior to 4.1 it's best do it in several steps:

  1. Get the list of (article,maxprice).
  2. For each article get the corresponding rows that have the stored maximum price.

This can easily be done with a temporary table:

CREATE TEMPORARY TABLE tmp (
        article INT(4) UNSIGNED ZEROFILL DEFAULT '0000' NOT NULL,
        price   DOUBLE(16,2)             DEFAULT '0.00' NOT NULL);

LOCK TABLES shop read;

INSERT INTO tmp SELECT article, MAX(price) FROM shop GROUP BY article;

SELECT shop.article, dealer, shop.price FROM shop, tmp
WHERE shop.article=tmp.article AND shop.price=tmp.price;

UNLOCK TABLES;

DROP TABLE tmp;

If you don't use a TEMPORARY table, you must also lock the 'tmp' table.

``Can it be done with a single query?''

Yes, but only by using a quite inefficient trick that I call the ``MAX-CONCAT trick'':

SELECT article,
       SUBSTRING( MAX( CONCAT(LPAD(price,6,'0'),dealer) ), 7) AS dealer,
  0.00+LEFT(      MAX( CONCAT(LPAD(price,6,'0'),dealer) ), 6) AS price
FROM   shop
GROUP BY article;

+---------+--------+-------+
| article | dealer | price |
+---------+--------+-------+
|    0001 | B      |  3.99 |
|    0002 | A      | 10.99 |
|    0003 | C      |  1.69 |
|    0004 | D      | 19.95 |
+---------+--------+-------+

The last example can, of course, be made a bit more efficient by doing the splitting of the concatenated column in the client.

3.5.5 ユーザー変数の使用

MySQLのユーザー変数を使用すると、クライアントの一時変数に格納せずに結果を 記憶できます。 「6.1.4 ユーザー変数」節参照。

例えば、商品の価格の最大値と最小値を求めるには、以下のSELECT構文を実行します。

mysql> SELECT @min_price:=MIN(price),@max_price:=MAX(price) FROM shop;
mysql> SELECT * FROM shop WHERE price=@min_price OR price=@max_price;
+---------+--------+-------+
| article | dealer | price |
+---------+--------+-------+
|    0003 | D      |  1.25 |
|    0004 | D      | 19.95 |
+---------+--------+-------+

3.5.6 Using Foreign Keys

In MySQL 3.23.44 and up, InnoDB tables supports checking of foreign key constraints. 「7.5 InnoDB テーブル (3.23.6以上)」節参照. See also 「1.7.4.5 外部キー」節.

You don't actually need foreign keys to join 2 tables. The only thing MySQL currently doesn't do (in table types other than InnoDB), is CHECK to make sure that the keys you use really exist in the table(s) you're referencing and it doesn't automatically delete rows from a table with a foreign key definition. If you use your keys like normal, it'll work just fine:

CREATE TABLE person (
    id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
    name CHAR(60) NOT NULL,
    PRIMARY KEY (id)
);

CREATE TABLE shirt (
    id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
    style ENUM('t-shirt', 'polo', 'dress') NOT NULL,
    color ENUM('red', 'blue', 'orange', 'white', 'black') NOT NULL,
    owner SMALLINT UNSIGNED NOT NULL REFERENCES person(id),
    PRIMARY KEY (id)
);

INSERT INTO person VALUES (NULL, 'Antonio Paz');

INSERT INTO shirt VALUES
(NULL, 'polo', 'blue', LAST_INSERT_ID()),
(NULL, 'dress', 'white', LAST_INSERT_ID()),
(NULL, 't-shirt', 'blue', LAST_INSERT_ID());

INSERT INTO person VALUES (NULL, 'Lilliana Angelovska');

INSERT INTO shirt VALUES
(NULL, 'dress', 'orange', LAST_INSERT_ID()),
(NULL, 'polo', 'red', LAST_INSERT_ID()),
(NULL, 'dress', 'blue', LAST_INSERT_ID()),
(NULL, 't-shirt', 'white', LAST_INSERT_ID());

SELECT * FROM person;
+----+---------------------+
| id | name                |
+----+---------------------+
|  1 | Antonio Paz         |
|  2 | Lilliana Angelovska |
+----+---------------------+

SELECT * FROM shirt;
+----+---------+--------+-------+
| id | style   | color  | owner |
+----+---------+--------+-------+
|  1 | polo    | blue   |     1 |
|  2 | dress   | white  |     1 |
|  3 | t-shirt | blue   |     1 |
|  4 | dress   | orange |     2 |
|  5 | polo    | red    |     2 |
|  6 | dress   | blue   |     2 |
|  7 | t-shirt | white  |     2 |
+----+---------+--------+-------+

SELECT s.* FROM person p, shirt s
 WHERE p.name LIKE 'Lilliana%'
   AND s.owner = p.id
   AND s.color <> 'white';

+----+-------+--------+-------+
| id | style | color  | owner |
+----+-------+--------+-------+
|  4 | dress | orange |     2 |
|  5 | polo  | red    |     2 |
|  6 | dress | blue   |     2 |
+----+-------+--------+-------+

3.5.7 Searching on Two Keys

MySQL doesn't yet optimize when you search on two different keys combined with OR (searching on one key with different OR parts is optimized quite well):

SELECT field1_index, field2_index FROM test_table WHERE field1_index = '1'
OR  field2_index = '1'

The reason is that we haven't yet had time to come up with an efficient way to handle this in the general case. (The AND handling is, in comparison, now completely general and works very well.)

For the moment you can solve this very efficiently by using a TEMPORARY table. This type of optimization is also very good if you are using very complicated queries where the SQL server does the optimizations in the wrong order.

CREATE TEMPORARY TABLE tmp
SELECT field1_index, field2_index FROM test_table WHERE field1_index = '1';
INSERT INTO tmp
SELECT field1_index, field2_index FROM test_table WHERE field2_index = '1';
SELECT * from tmp;
DROP TABLE tmp;

The above way to solve this query is in effect a UNION of two queries. 「6.4.1.2 UNION Syntax」節参照.

3.5.8 Calculating Visits Per Day

The following shows an idea of how you can use the bit group functions to calculate the number of days per month a user has visited a web page.

CREATE TABLE t1 (year YEAR(4), month INT(2) UNSIGNED ZEROFILL,
             day INT(2) UNSIGNED ZEROFILL);
INSERT INTO t1 VALUES(2000,1,1),(2000,1,20),(2000,1,30),(2000,2,2),
            (2000,2,23),(2000,2,23);
SELECT year,month,BIT_COUNT(BIT_OR(1<<day)) AS days FROM t1
       GROUP BY year,month;

Which returns:

+------+-------+------+
| year | month | days |
+------+-------+------+
| 2000 |    01 |    3 |
| 2000 |    02 |    2 |
+------+-------+------+

The above calculates how many different days was used for a given year/month combination, with automatic removal of duplicate entries.

3.5.9 Using AUTO_INCREMENT

The AUTO_INCREMENT attribute can be used to generate a unique identity for new rows:

CREATE TABLE animals (
             id MEDIUMINT NOT NULL AUTO_INCREMENT,
             name CHAR(30) NOT NULL,
             PRIMARY KEY (id)
             );
INSERT INTO animals (name) VALUES ("dog"),("cat"),("penguin"),
                                  ("lax"),("whale");
SELECT * FROM animals;

Which returns:

+----+---------+
| id | name    |
+----+---------+
|  1 | dog     |
|  2 | cat     |
|  3 | penguin |
|  4 | lax     |
|  5 | whale   |
+----+---------+

You can retrieve the used AUTO_INCREMENT key with the LAST_INSERT_ID() SQL function or the mysql_insert_id() API function. Note: for a multi-row insert, LAST_INSERT_ID()/mysql_insert_id() will actually return the AUTO_INCREMENT key from the first inserted row. This allows multi-row inserts to be reproduced on other servers.

For MyISAM and BDB tables you can specify AUTO_INCREMENT on secondary column in a multi-column key. In this case the generated value for the autoincrement column is calculated as MAX(auto_increment_column)+1) WHERE prefix=given-prefix. This is useful when you want to put data into ordered groups.

CREATE TABLE animals (
             grp ENUM('fish','mammal','bird') NOT NULL,
             id MEDIUMINT NOT NULL AUTO_INCREMENT,
             name CHAR(30) NOT NULL,
             PRIMARY KEY (grp,id)
             );
INSERT INTO animals (grp,name) VALUES("mammal","dog"),("mammal","cat"),
                  ("bird","penguin"),("fish","lax"),("mammal","whale");
SELECT * FROM animals ORDER BY grp,id;

Which returns:

+--------+----+---------+
| grp    | id | name    |
+--------+----+---------+
| fish   |  1 | lax     |
| mammal |  1 | dog     |
| mammal |  2 | cat     |
| mammal |  3 | whale   |
| bird   |  1 | penguin |
+--------+----+---------+

Note that in this case, the AUTO_INCREMENT value will be reused if you delete the row with the biggest AUTO_INCREMENT value in any group.

3.6 mysql のバッチモードでの使用

前のセクションでは、mysql を対話モードで使用し、クエリの入力と 結果を表示しました。 mysql はバッチモードでも実行可能です。 これを行うには、あなたが実行したいコマンドをファイルに書いておき、 そのファイルから入力を読み込むようにして mysql を実行します:

shell> mysql < batch-file

If you are running mysql under windows and have some special characters in the file that causes problems, you can do:

dos> mysql -e "source batch-file"

もし接続パラメターを指定する必要がある場合は、以下のようになるでしょう:

shell> mysql -h host -u user -p < batch-file
Enter password: ********

この方法で mysql を使用するとき、あなたはスクリプトファイルを 作成し、それを実行することになるでしょう。

If you want the script to continue even if you have errors, you should use the --force command-line option.

なぜスクリプトを使用するのか? それには以下の理由があります:

mysql をバッチモードで使用するか、対話モードで使用するかで、 デフォルトの出力形式が変わります。 例えば、 SELECT DISTINCT species FROM pet の 出力は対話モードでは次のようになります:

+---------+
| species |
+---------+
| bird    |
| cat     |
| dog     |
| hamster |
| snake   |
+---------+

しかし、バッチモードでは:

species
bird
cat
dog
hamster
snake

もしバッチモードでも対話モードのような出力を得たい場合には、mysql -t とします。 出力中に、実行したコマンドを表示させるならば、mysql -vvv とします。

You can also use scripts in the mysql command-line prompt by using the source command:

mysql> source filename;

3.7 Queries from Twin Project

At Analytikerna and Lentus, we have been doing the systems and field work for a big research project. This project is a collaboration between the Institute of Environmental Medicine at Karolinska Institutet Stockholm and the Section on Clinical Research in Aging and Psychology at the University of Southern California.

The project involves a screening part where all twins in Sweden older than 65 years are interviewed by telephone. Twins who meet certain criteria are passed on to the next stage. In this latter stage, twins who want to participate are visited by a doctor/nurse team. Some of the examinations include physical and neuropsychological examination, laboratory testing, neuroimaging, psychological status assessment, and family history collection. In addition, data are collected on medical and environmental risk factors.

More information about Twin studies can be found at: http://www.imm.ki.se/TWIN/TWINUKW.HTM

The latter part of the project is administered with a web interface written using Perl and MySQL.

Each night all data from the interviews are moved into a MySQL database.

3.7.1 Find all Non-distributed Twins

The following query is used to determine who goes into the second part of the project:

SELECT
        CONCAT(p1.id, p1.tvab) + 0 AS tvid,
        CONCAT(p1.christian_name, " ", p1.surname) AS Name,
        p1.postal_code AS Code,
        p1.city AS City,
        pg.abrev AS Area,
        IF(td.participation = "Aborted", "A", " ") AS A,
        p1.dead AS dead1,
        l.event AS event1,
        td.suspect AS tsuspect1,
        id.suspect AS isuspect1,
        td.severe AS tsevere1,
        id.severe AS isevere1,
        p2.dead AS dead2,
        l2.event AS event2,
        h2.nurse AS nurse2,
        h2.doctor AS doctor2,
        td2.suspect AS tsuspect2,
        id2.suspect AS isuspect2,
        td2.severe AS tsevere2,
        id2.severe AS isevere2,
        l.finish_date
FROM
        twin_project AS tp
        /* For Twin 1 */
        LEFT JOIN twin_data AS td ON tp.id = td.id
                  AND tp.tvab = td.tvab
        LEFT JOIN informant_data AS id ON tp.id = id.id
                  AND tp.tvab = id.tvab
        LEFT JOIN harmony AS h ON tp.id = h.id
                  AND tp.tvab = h.tvab
        LEFT JOIN lentus AS l ON tp.id = l.id
                  AND tp.tvab = l.tvab
        /* For Twin 2 */
        LEFT JOIN twin_data AS td2 ON p2.id = td2.id
                  AND p2.tvab = td2.tvab
        LEFT JOIN informant_data AS id2 ON p2.id = id2.id
                  AND p2.tvab = id2.tvab
        LEFT JOIN harmony AS h2 ON p2.id = h2.id
                  AND p2.tvab = h2.tvab
        LEFT JOIN lentus AS l2 ON p2.id = l2.id
                  AND p2.tvab = l2.tvab,
        person_data AS p1,
        person_data AS p2,
        postal_groups AS pg
WHERE
        /* p1 gets main twin and p2 gets his/her twin. */
        /* ptvab is a field inverted from tvab */
        p1.id = tp.id AND p1.tvab = tp.tvab AND
        p2.id = p1.id AND p2.ptvab = p1.tvab AND
        /* Just the sceening survey */
        tp.survey_no = 5 AND
        /* Skip if partner died before 65 but allow emigration (dead=9) */
        (p2.dead = 0 OR p2.dead = 9 OR
         (p2.dead = 1 AND
          (p2.death_date = 0 OR
           (((TO_DAYS(p2.death_date) - TO_DAYS(p2.birthday)) / 365)
            >= 65))))
        AND
        (
        /* Twin is suspect */
        (td.future_contact = 'Yes' AND td.suspect = 2) OR
        /* Twin is suspect - Informant is Blessed */
        (td.future_contact = 'Yes' AND td.suspect = 1
                                   AND id.suspect = 1) OR
        /* No twin - Informant is Blessed */
        (ISNULL(td.suspect) AND id.suspect = 1
                            AND id.future_contact = 'Yes') OR
        /* Twin broken off - Informant is Blessed */
        (td.participation = 'Aborted'
         AND id.suspect = 1 AND id.future_contact = 'Yes') OR
        /* Twin broken off - No inform - Have partner */
        (td.participation = 'Aborted' AND ISNULL(id.suspect)
                                      AND p2.dead = 0))
        AND
        l.event = 'Finished'
        /* Get at area code */
        AND SUBSTRING(p1.postal_code, 1, 2) = pg.code
        /* Not already distributed */
        AND (h.nurse IS NULL OR h.nurse=00 OR h.doctor=00)
        /* Has not refused or been aborted */
        AND NOT (h.status = 'Refused' OR h.status = 'Aborted'
        OR h.status = 'Died' OR h.status = 'Other')
ORDER BY
        tvid;

Some explanations:

CONCAT(p1.id, p1.tvab) + 0 AS tvid
We want to sort on the concatenated id and tvab in numerical order. Adding 0 to the result causes MySQL to treat the result as a number.
column id
This identifies a pair of twins. It is a key in all tables.
column tvab
This identifies a twin in a pair. It has a value of 1 or 2.
column ptvab
This is an inverse of tvab. When tvab is 1 this is 2, and vice versa. It exists to save typing and to make it easier for MySQL to optimize the query.

This query demonstrates, among other things, how to do lookups on a table from the same table with a join (p1 and p2). In the example, this is used to check whether a twin's partner died before the age of 65. If so, the row is not returned.

All of the above exist in all tables with twin-related information. We have a key on both id,tvab (all tables), and id,ptvab (person_data) to make queries faster.

On our production machine (A 200MHz UltraSPARC), this query returns about 150-200 rows and takes less than one second.

The current number of records in the tables used above:
Table Rows
person_data 71074
lentus 5291
twin_project 5286
twin_data 2012
informant_data 663
harmony 381
postal_groups 100

3.7.2 Show a Table on Twin Pair Status

Each interview ends with a status code called event. The query shown here is used to display a table over all twin pairs combined by event. This indicates in how many pairs both twins are finished, in how many pairs one twin is finished and the other refused, and so on.

SELECT
        t1.event,
        t2.event,
        COUNT(*)
FROM
        lentus AS t1,
        lentus AS t2,
        twin_project AS tp
WHERE
        /* We are looking at one pair at a time */
        t1.id = tp.id
        AND t1.tvab=tp.tvab
        AND t1.id = t2.id
        /* Just the sceening survey */
        AND tp.survey_no = 5
        /* This makes each pair only appear once */
        AND t1.tvab='1' AND t2.tvab='2'
GROUP BY
        t1.event, t2.event;

3.8 Using MySQL with Apache

There are programs that let you authenticate your users from a MySQL database and also let you log your log files into a MySQL table.

You can change the Apache logging format to be easily readable by MySQL by putting the following into the Apache configuration file:

LogFormat \
        "\"%h\",%{%Y%m%d%H%M%S}t,%>s,\"%b\",\"%{Content-Type}o\",  \
        \"%U\",\"%{Referer}i\",\"%{User-Agent}i\""

In MySQL you can do something like this:

LOAD DATA INFILE '/local/access_log' INTO TABLE table_name
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\'


Go to the first, previous, next, last section, table of contents.