サブクエリーは
SELECT
ステートメントの
FROM
節内で正当です。実際の構文はこれです。
SELECT ... FROM (subquery
) [AS]name
...
[AS]
節は強制なので、name
FROM
節内のすべてのテーブルは名前を持つ必要があります。subquery
選択リスト内のすべてのカラムは固有の名前を持たなければいけません。
説明するために、このテーブルを持っていると仮定してください。
CREATE TABLE t1 (s1 INT, s2 CHAR(5), s3 FLOAT);
ここに、この例のテーブルを利用して、FROM
節の中でサブクエリーを利用する方法の説明があります。
INSERT INTO t1 VALUES (1,'1',1.0); INSERT INTO t1 VALUES (2,'2',2.0); SELECT sb1,sb2,sb3 FROM (SELECT s1 AS sb1, s2 AS sb2, s3*2 AS sb3 FROM t1) AS sb WHERE sb1 > 1;
結果: 2, '2', 4.0
.
ここに別の例があります。グループ分けされたテーブルの、合計セットの平均を知りたいと仮定します。これは機能しません。
SELECT AVG(SUM(column1)) FROM t1 GROUP BY column1;
しかし、このクエリーは要求された情報を提供します。
SELECT AVG(sum_column1) FROM (SELECT SUM(column1) AS sum_column1 FROM t1 GROUP BY column1) AS t1;
サブクエリーの中で利用されたカラム名
(sum_column1
)
が外部クエリーの中で認められていることに注意してください。
FROM
節内のサブクエリーは、スカラー、カラム、行、そしてテーブルを返すことができます。FROM
節内のサブクエリーは、JOIN
演算の ON
節内で利用されないかぎり、相関サブクエリーになることができません。
FROM
節内のサブクエリーは、EXPLAIN
ステートメント
(派生一時テーブルが作られた)
に対しても実行することができます。これは、最適化フェーズ中に上位レベルのクエリーにすべてのテーブルに関する情報が必要であり、かつサブクエリーが実行されないかぎり
FROM
節内のサブクエリーによって表されているテーブルを使用できないために発生します。
特定の状況下では、EXPLAIN
SELECT
を使用してテーブルデータを変更することが可能です。これは、外部クエリーが任意のテーブルにアクセスし、内部クエリーが、テーブルの
1
つ以上の行を変更するストアドファンクションを呼び出す場合に発生する可能性があります。たとえば、次に示すように作成された、データベース
d1
内の 2
つのテーブル t1
と
t2
があるとします。
mysql>CREATE DATABASE d1;
Query OK, 1 row affected (0.00 sec) mysql>USE d1;
Database changed mysql>CREATE TABLE t1 (c1 INT);
Query OK, 0 rows affected (0.15 sec) mysql>CREATE TABLE t2 (c1 INT);
Query OK, 0 rows affected (0.08 sec)
ここで、t2
を変更するストアドファンクション
f1
を作成します。
mysql>DELIMITER //
mysql>CREATE FUNCTION f1(p1 INT) RETURNS INT
mysql>BEGIN
mysql>INSERT INTO t2 VALUES (p1);
mysql>RETURN p1;
mysql>END //
Query OK, 0 rows affected (0.01 sec) mysql>DELIMITER ;
次に示すように、EXPLAIN
SELECT
でこの関数を直接参照しても、t2
には何も影響を与えません。
mysql>SELECT * FROM t2;
Empty set (0.00 sec) mysql>EXPLAIN SELECT f1(5);
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ | 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used | +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 1 row in set (0.00 sec) mysql>SELECT * FROM t2;
Empty set (0.00 sec)
これは、SELECT
ステートメントが、出力の
table
および
Extra
カラムで表示できるためにどのテーブルも参照しなかったためです。また、これは次の入れ子の
SELECT
にも当てはまります。
mysql>EXPLAIN SELECT NOW() AS a1, (SELECT f1(5)) AS a2;
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ | 1 | PRIMARY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used | +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 1 row in set, 1 warning (0.00 sec) mysql>SHOW WARNINGS;
+-------+------+------------------------------------------+ | Level | Code | Message | +-------+------+------------------------------------------+ | Note | 1249 | Select 2 was reduced during optimization | +-------+------+------------------------------------------+ 1 row in set (0.00 sec) mysql>SELECT * FROM t2;
Empty set (0.00 sec)
ただし、外部の
SELECT
がいずれかのテーブルを参照している場合、オプティマイザはサブクエリーでもこのステートメントを実行します。
mysql>EXPLAIN SELECT * FROM t1 AS a1, (SELECT f1(5)) AS a2;
+----+-------------+------------+--------+---------------+------+---------+------+------+---------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+--------+---------------+------+---------+------+------+---------------------+ | 1 | PRIMARY | a1 | system | NULL | NULL | NULL | NULL | 0 | const row not found | | 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | | | 2 | DERIVED | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used | +----+-------------+------------+--------+---------------+------+---------+------+------+---------------------+ 3 rows in set (0.00 sec) mysql>SELECT * FROM t2;
+------+ | c1 | +------+ | 5 | +------+ 1 row in set (0.00 sec)
また、これは、ここに示したような
EXPLAIN
SELECT
ステートメントが、実行に長い時間がかかる可能性があることも示します。
EXPLAIN SELECT * FROM t1 AS a1, (SELECT BENCHMARK(1000000, MD5(NOW())));
これは、BENCHMARK()
関数が t1
内の行ごとに 1 回実行されるためです。