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

# 3 Introduction to MySQL: MySQL チュートリアル

この章では、 `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: ********

`********` とかかれている部分にはあなたのパスワードを入れます； `mysql` が `Enter 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` のいくつかの事を説明しています：

- 通常、コマンドは、セミコロンで終わる SQL ステートメントから、構成されます。 (セミコロンが必要とされないいくつかの例外があります。 以前に述べた `QUIT` はそのうちの一つです。後で他も出てきます。)
- コマンドを発行すると、`mysql` はそれをサーバーに送り、結果を表示します。 その後、 `mysql>` プロンプトを出し、他のコマンドが受け付けれる状態であると 示します。
- `mysql` はクエリの結果を表にして出します。 最初の行は項目のラベル名です。 その下の行に、クエリの結果が続きます。 通常、項目のラベル名はデータベースのテーブルから あなたが取り出したフィールド名になります。 テーブルのフィールド名以外の式を あなたが検索したのなら(ちょうど例のように)、`mysql` は与えられた式自身を 項目のラベル名として表示します。
- `mysql` は何レコード(rows)返ってきたかを示し、実行にどれくらいの時間が かかったかも示します。 これはおおざっぱなサーバーのパフォーマンスを示します。 これらの値は wall clock time (CPU や マシンタイムではなく) を使用しており、さらに、 サーバーの負荷、およびネットワーク待ち時間といった要因にも影響されるので、 不正確です。 (この章の他の例題においては ``rows in set'' の行は省きます。)

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

    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` が、まだ文が終わっておらず、残りの部分の入力を待っている ことを示します。 The prompt is your friend, because it provides valuable feedback. If you use that feedback, you will always be aware of what `mysql` is waiting for.

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

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

Here, too, notice the prompt. It switches back to `mysql>` after you type `\c`, providing feedback to indicate that `mysql` is ready for a new command.

The following table shows each of the prompts you may see and summarizes what they mean about the state that `mysql` is in:

Prompt | Meaning
`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 realizing 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 hit RETURN 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:

- Create a database
- Create a table
- Load data into the table
- Retrieve data from the table in various ways
- Use multiple tables

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 or Zip format.

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.

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 Creating a Table

Creating the database is the easy part, but at this point it's empty, as `SHOW TABLES` will tell you:

    mysql> SHOW TABLES;
    Empty set (0.00 sec)

The harder part is deciding what the structure of your database should be: what tables you will need and what columns will be in each of them.

You'll want a table that contains a record for each of your pets. This can be called the `pet` table, and it should contain, as a bare minimum, each animal's name. Because the name by itself is not very interesting, the table should contain other information. For example, if more than one person in your family keeps pets, you might want to list each animal's owner. You might also want to record some basic descriptive information such as species and sex.

How about age? That might be of interest, but it's not a good thing to store in a database. Age changes as time passes, which means you'd have to update your records often. Instead, it's better to store a fixed value such as date of birth. Then, whenever you need age, you can calculate it as the difference between the current date and the birth date. MySQL provides functions for doing date arithmetic, so this is not difficult. Storing birth date rather than age has other advantages, too:

- You can use the database for tasks such as generating reminders for upcoming pet birthdays. (If you think this type of query is somewhat silly, note that it is the same question you might ask in the context of a business database to identify clients to whom you'll soon need to send out birthday greetings, for that computer-assisted personal touch.)
- You can calculate age in relation to dates other than the current date. For example, if you store death date in the database, you can easily calculate how old a pet was when it died.

You can probably think of other types of information that would be useful in the `pet` table, but the ones identified so far are sufficient for now: name, owner, species, sex, birth, and death.

Use a `CREATE TABLE` statement to specify the layout of your table:

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

`VARCHAR` is a good choice for the `name`, `owner`, and `species` columns because the column values will vary in length. The lengths of those columns need not all be the same, and need not be `20`. You can pick any length from `1` to `255`, whatever seems most reasonable to you. (If you make a poor choice and it turns out later that you need a longer field, MySQL provides an `ALTER TABLE` statement.)

Animal sex can be represented in a variety of ways, for example, `"m"` and `"f"`, or perhaps `"male"` and `"female"`. It's simplest to use the single characters `"m"` and `"f"`.

The use of the `DATE` data type for the `birth` and `death` columns is a fairly obvious choice.

Now that you have created a table, `SHOW TABLES` should produce some output:

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

To verify that your table was created the way you expected, use a `DESCRIBE` statement:

    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    |       |
    +---------+-------------+------+-----+---------+-------+

You can use `DESCRIBE` any time, for example, if you forget the names of the columns in your table or what types they are.

### 3.3.3 Loading Data into a Table

After creating your table, you need to populate it. The `LOAD DATA` and `INSERT` statements are useful for this.

Suppose your pet records can be described as shown below. (Observe that MySQL expects dates in `YYYY-MM-DD` format; this may be different than what you are used to.)

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 |

Because you are beginning with an empty table, an easy way to populate it is to create a text file containing a row for each of your animals, then load the contents of the file into the table with a single statement.

You could create a text file ``pet.txt'` containing one record per line, with values separated by tabs, and given in the order in which the columns were listed in the `CREATE TABLE` statement. For missing values (such as unknown sexes or death dates for animals that are still living), you can use `NULL` values. To represent these in your text file, use `\N`. For example, the record for Whistler the bird would look like this (where the whitespace between values is a single tab character):

`Whistler` | `Gwen` | `bird` | `\N` | `1997-12-09` | `\N`

To load the text file ``pet.txt'` into the `pet` table, use this command:

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

You can specify the column value separator and end of line marker explicitly in the `LOAD DATA` statement if you wish, but the defaults are tab and linefeed. These are sufficient for the statement to read the file ``pet.txt'` properly.

When you want to add new records one at a time, the `INSERT` statement is useful. In its simplest form, you supply values for each column, in the order in which the columns were listed in the `CREATE TABLE` statement. Suppose Diane gets a new hamster named Puffball. You could add a new record using an `INSERT` statement like this:

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

Note that string and date values are specified as quoted strings here. Also, with `INSERT`, you can insert `NULL` directly to represent a missing value. You do not use `\N` like you do with `LOAD DATA`.

From this example, you should be able to see that there would be a lot more typing involved to load your records initially using several `INSERT` statements rather than a single `LOAD DATA` statement.

### 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 data file: 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 are least a couple of ways to fix this:

- Edit the file ``pet.txt'` to correct the error, then empty the table and reload it using `DELETE` and `LOAD DATA`:

      mysql> SET AUTOCOMMIT=1;  # Used for quick re-create of the table
      mysql> DELETE FROM pet;
      mysql> LOAD DATA LOCAL INFILE "pet.txt" INTO TABLE pet;

  However, if you do this, you must also re-enter the record for Puffball.
- Fix only the erroneous record with an `UPDATE` statement:

      mysql> UPDATE pet SET birth = "1989-08-31" WHERE name = "Bowser";

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 minimize 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 |
    +----------+------------+

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` ならば、 `death` と `birth` の差の計算を行います：

    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()` がいいでしょう。 これがどのように動くか確かめるには、 `birth` と `MONTH(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` の使用が 必要とされるのです。

#### 3.3.4.7 パターン・マッチ

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

SQL パターン・マッチは、 ``_'` でいかなる１文字とも一致し、 ``%'` であらゆる0こ以上の文字列に一致します。 MySQL では、デフォルトで SQL パターンはケース非依存です。 いくつか例を以下に示します。 SQLパターンを使用する場合、 `=` や `!=` を使用しないように注意してください。 `LIKE` か `NOT 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 では他のパターン・マッチの形も提供されます。正規表現の拡張を使用して。 これらのパターン・マッチをテストする際には、`REGEXP` と `NOT REGEXP` 演算子（あるいは`RLIKE`, `NOT RLIKE` 演算子。これらは同義です） を使用します。

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

- ``.'` はいかなる一文字とも一致します。
- ``[...]'` は、かっこ内にある文字と一致します。 例えば、``[abc]'` は ``a'`, ``b'` あるいは ``c'` にマッチします。 文字を範囲指定する場合にはダッシュを使用します。 ``[a-z]'` はいかなる 小文字のアルファベット文字にも一致し、 ``[0-9]'` はいかなる数字にも 一致します。
- ``*'` は、先に指定されている文字 0 個以上にマッチします。 例えば、``x*'` は 文字 ``x'` がいくつも連続している物にマッチし、 ``[0-9]*'` はいかなる数値ともマッチし、 ``.*'` はあらゆる文字列に 一致します。
- 正規表現はケース依存です。 しかし大文字小文字どちらでもマッチさせたい場合、 文字クラスを使用できます。 例えば、 ``[aA]'` は大文字小文字の ``a'` に マッチし、``[a-zA-Z]'` は大文字小文字のいかなるアルファベット文字にもマッチします。
- パターンは、テストされた値の中のどこかにある場合、マッチします。 (SQL patterns match only if they match the entire value.)
- 値のはじめ、あるいは終わりに位置を指定してマッチさせたい場合は、 パターンの初めにマッチさせる場合は ``^'` を使用し、 パターンの終わりにマッチさせる場合は ``$'` を使用します。 (これらはアンカーと呼ばれます)

以下は拡張された正規表現がどう動くかの例です。 上に示した `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 characterizing 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:

- To contain the pet name so you know which animal each event pertains to.
- A date so you know when the event occurred.
- A field to describe the event.
- An event type field, if you want to be able to categorize events.

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:

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:

- The `FROM` clause lists two tables because the query needs to pull information from both of them.
- When combining (joining) information from multiple tables, you need to specify how records in one table can be matched to records in the other. This is easy because they both have a `name` column. The query uses `WHERE` clause to match up records in the two tables based on the `name` values.
- Because the `name` column occurs in both tables, you must be specific about which table you mean when referring to the column. This is done by prepending the table name to the column name.

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 Examples of Common Queries

Here are examples of how to solve some common problems with MySQL.

Some of the examples use the table `shop` to hold the price of each article (item number) for certain traders (dealers). Supposing that each trader has a single fixed price per article, then (`article`, `dealer`) is a primary key for the records.

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

    mysql your-database-name

(In most MySQL installations, you can use the database-name 'test').

You can create the example table as:

    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);

Okay, so the example data is:

    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 The Maximum Value for a Column

``What's the highest item number?''

    SELECT MAX(article) AS article FROM shop

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

### 3.5.2 The Row Holding the Maximum of a Certain Column

``Find number, dealer, and price of the most expensive article.''

In ANSI SQL this is easily done with a sub-query:

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

In MySQL (which does not yet have sub-selects), just do it in two steps:

1. Get the maximum price value from the table with a `SELECT` statement.
2. Using this value compile the actual query:

       SELECT article, dealer, price
       FROM   shop
       WHERE  price=19.95

Another solution is to sort all rows descending by price and only get the first row using the MySQL specific `LIMIT` clause:

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

NOTE: If there are several most expensive articles (for example, each 19.95) the `LIMIT` solution shows only one of them!

### 3.5.3 Maximum of Column per Group

``What's the highest price per article?''

    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, I'd do it with a sub-query 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 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 Using user variables

You can use MySQL user variables to remember results without having to store them in temporary variables in the client. 「6.1.4 ユーザー変数」節参照.

For example, to find the articles with the highest and lowest price you can do:

    select @min_price:=min(price),@max_price:=max(price) from shop;
    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

You don't need foreign keys to join 2 tables.

The only thing MySQL doesn't do 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 table with a foreign key definition. If you use your keys like normal, it'll work just fine:

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

    CREATE TABLE shirts (
        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 persons,
        PRIMARY KEY (id)
    );

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

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

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

    INSERT INTO shirts 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 persons;
    +----+---------------------+
    | id | name                |
    +----+---------------------+
    |  1 | Antonio Paz         |
    |  2 | Lilliana Angelovska |
    +----+---------------------+

    SELECT * FROM shirts;
    +----+---------+--------+-------+
    | 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 persons p, shirts 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 good):

    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 an `UNION` of two queries.

### 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.6 `mysql` のバッチモードでの使用

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

    shell> mysql < batch-file

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

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

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

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

- もし繰り返しクエリを実行する場合(毎日とか毎週とか)、スクリプトを書くことで、 その実行の度にあなたがコマンドをタイプすることを省くことが可能です。
- もし既にあるクエリに似た新しいクエリを書く場合、それらをコピーし スクリプトファイルを編集できます。
- バッチモードはクエリの開発中や複数にまたがるコマンドには役に立ちます。 もしコマンドが間違っていたとしても全てを打ち直す必要がありません。 エラーを修正するためにスクリプトを編集し、再び `mysql` に実行させます。
- もし多くの出力を出すようなクエリの場合、ページャーを使用して出力を見ることが 出来ます。 出力がスクロールして画面から見えなくなるよりいいでしょう：

      shell> mysql < batch-file | more

- あなたはより処理を行うために、結果をファイルに書き出すことが可能です：

      shell> mysql < batch-file > mysql.out

- あなたは、他人へのあなたのスクリプトを配布することができます。これにより、ほかの人たちも コマンドを実行することができます。
- いくつかの状況では、対話モードでは使用に耐えません。 たとえば、クエリを `cron` ジョブとして実行する場合。 この場合、バッチモードでなければなりません。
- 端末が正しく扱えない文字を `mysql` コマンドに渡す場合。 たとえば、EUC-JP, Shift_JIS の漢字文字などは、端末や環境によっては直接入力できない場合もあるでしょう。 あるいは、文字コードの違う MySQL サーバーにデータを転送するときなども。

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

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

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

    species
    bird
    cat
    dog
    hamster
    snake

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

## 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 below 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

The Contrib section includes programs that let you authenticate your users from a MySQL database and also let you log your log files into a MySQL table. 「D Contributed Programs」節参照.

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.