ANY
、IN
、そして SOME
を持つサブクエリ
ALL
を持つサブクエリ
EXISTS
と NOT EXISTS
FROM
条項内のサブクエリ
サブクエリは、別のステートメント内の SELECT
ステートメントです。
MySQL 4.1 から、MySQL 特有のいくつかの特徴と同様に、SQL スタンダードが要求する全てのサブクエリ型と演算子がサポートされています。
ここに、同じようなサブクエリの例があります。
SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);
この例の中では、SELECT * FROM t1 ...
は 外部クエリ (または 外部ステートメント)であり、(SELECT column1 FROM t2)
は サブクエリ です。これは、サブクエリが外部クエリ内で ネスト化された という事であり、実際、サブクエリを別のサブクエリ内で、相当な深さまでネスト化する事が可能です。サブクエリは必ずカッコ内に表示されなければいけません。
サブクエリの主な利点は次のような物になります。
それらは、ステートメントのそれぞれの部分を分離させる事ができるように、構造化された クエリを許容します。
それらは、複雑な接合や合併を要求されないように、演算を行う為の代替法を提供します。
多くの人の意見によると、それらは複雑な接合や合併と比べると、読み込みやすいという事です。実際これは、初期 SQL の 「Structured Query Language.」 の創案を人々に与えたサブクエリの発明でした。
ここに、SQL スタンダードによって指定され、MySQL 内でサポートされているサブクエリ構文に関する主なポイントを説明するステートメントの例があります。
DELETE FROM t1 WHERE s11 > ANY (SELECT COUNT(*) /* no hint */ FROM t2 WHERE NOT EXISTS (SELECT * FROM t3 WHERE ROW(5*t2.s1,77)= (SELECT 50,11*s1 FROM t4 UNION SELECT 50,77 FROM (SELECT * FROM t5) AS t5)));
サブクエリは、スカラ(単一値)、単一行、単一カラム、またはテーブル(1つ、または複数カラムの、1つ、または複数行) を返す事ができます。これらはスカラ、カラム、行、そしてテーブル サブクエリと呼ばれます。次のセクションで説明されているように、頻繁に特定の種類の結果を返すサブクエリは、特定のコンテキストの中だけで利用する事ができます。
サブクエリを利用する事ができるステートメントのタイプには、いくつかの制限があります。サブクエリは、普通の SELECT
が含む事のできるキーワードや条項を全て含む事ができます。それは DISTINCT
、GROUP BY
、ORDER BY
、LIMIT
、接合、インデックスヒント、UNION
構成、コメント、関数などです。
制限の1つは、サブクエリの外部ステートメントが SELECT
、INSERT
、UPDATE
、DELETE
、SET
、または DO
のうちのどれか1つでなければいけないという事です。その他の制限は、現在はサブクエリの中でテーブルを変更したり、同じテーブルから選択する事ができないという事です。これは、DELETE
、INSERT
、REPLACE
、UPDATE
、そして(サブクエリは SET
条項内で利用できる為) LOAD DATA INFILE
のようなステートメントに適応します。
サブクエリ構文の特定型に関する性能問題を含む、サブクエリ利用に関する制限のさらなる総合的な説明に関しては、 項D.3. 「サブクエリの規制」 で紹介されています。
簡単に言うと、サブクエリは単一値を戻すスカラ サブクエリという事になります。スカラ サブクエリは単純な演算子で、単一カラム値や直定数が正当であればほとんどどこでも利用する事ができ、データ
タイプ、長さ、 NULL
になり得るかどうかという指示など、全ての演算子が持つ特徴も全て持っています。ここにその例があります。
CREATE TABLE t1 (s1 INT, s2 CHAR(5) NOT NULL); INSERT INTO t1 VALUES(100, 'abcde'); SELECT (SELECT s2 FROM t1);
この SELECT
内のサブクエリは、CHAR
のデータ タイプを持ち、長さが5で、CREATE TABLE
時にデフォルトと同等の文字セットと照合が実施されており、そしてカラム内の値が NULL
になり得るという指示を持つ単一値('abcde'
)を返します。実際は、ほとんどのサブクエリが NULL
になり得ます。もし例で使用されたテーブルが空であれば、サブクエリの値は NULL
になるでしょう。
スカラ サブクエリを利用できないコンテキストがいくつかあります。もしステートメントが直定数値だけを許容するなら、サブクエリを利用する事はできません。例えば、LIMIT
が直定整数引数を要求し、LOAD DATA INFILE
が直定数文字列ファイル名を要求します。これらの値を供給するのにサブクエリを利用する事はできません。
次のセクションにある、より質素な構造を含む (SELECT column1 FROM t1)
の例を見る時、自分自身のコードが、それよりもさらに多様で、複雑な構造を含んでいると想像してください。
2つテーブルを作成すると仮定します。
CREATE TABLE t1 (s1 INT); INSERT INTO t1 VALUES (1); CREATE TABLE t2 (s1 INT); INSERT INTO t2 VALUES (2);
次に、SELECT
を実行します。
SELECT (SELECT s1 FROM t2) FROM t1;
2
の値を持つカラム s1
を含む行が t2
にあるので、その結果は 2
となります。
スカラ サブクエリは式の一部になり得ますが、もしそのサブクエリが関数に引数を与える演算子だとしても、括弧を忘れないでください。 例:
SELECT UPPER((SELECT s1 FROM t1)) FROM t2;
サブクエリの最もよく利用される方法はこの形の中にあります。
non_subquery_operand
comparison_operator
(subquery
)
comparison_operator
がこれらの演算子の1つであるところではこうです。
= > < >= <= <>
例:
... 'a' = (SELECT column1 FROM t1)
かつては、サブクエリが正当であるたった1つの場所は比較の右側でしたし、いまだにいくつかの古い DBMS がこれを主張しています。
ここに、接合と共に実行できない共通形サブクエリ比較の例があります。これは、テーブル t2
の最大値と同等の、テーブル t1
内の全ての値を検出します。
SELECT column1 FROM t1 WHERE column1 = (SELECT MAX(column2) FROM t2);
ここに、テーブルの1つに対する凝集を含む為、接合と共に利用する事ができないもうひとつの例があります。これは、与えられたカラムの中で2回現れる値を含む、テーブル
t1
の中の全ての行を検出します。
SELECT * FROM t1 AS t WHERE 2 = (SELECT COUNT(*) FROM t1 WHERE t1.id = t.id);
これらの演算子の1つを利用して実行された比較には、=
は行サブクエリと共に利用できるという例外がありますが、サブクエリはスカラを返さなければいけません。詳しくは 項5. 「行サブクエリ」 を参照してください。
ANY
、IN
、そして SOME
を持つサブクエリ構文:
operand
comparison_operator
ANY (subquery
)operand
IN (subquery
)operand
comparison_operator
SOME (subquery
)
比較演算子の後に続かなければいけない ANY
キーワードは、「もしサブクエリが返すカラム内の値の ANY
に対する比較が TRUE
であれば、TRUE
を返す」 という事を意味します。例:
SELECT s1 FROM t1 WHERE s1 > ANY (SELECT s1 FROM t2);
テーブル (10)
を含むテーブル t1
内に行があると仮定してください。10
以下である値 7
が t2
の中にあるので、もしテーブル t2
が (21,14,7)
を含むなら、その式は TRUE
です。もしテーブル t2
が (20,10)
を含むか、テーブル t2
が空であれば、その式は FALSE
です。もしテーブル t2
が (NULL,NULL,NULL)
を含むなら、その式は UNKNOWN
です。
サブクエリと共に利用される時、IN
という言葉は = ANY
のエイリアスとなります。従って、これら2つのステートメントは同じになります。
SELECT s1 FROM t1 WHERE s1 = ANY (SELECT s1 FROM t2); SELECT s1 FROM t1 WHERE s1 IN (SELECT s1 FROM t2);
式のリストと共に利用される時、IN
と = ANY
は同義語ではありません。IN
は式のリストを取る事ができますが、= ANY
はできません。詳しくは 項 「比較関数と演算子」 を参照してください。
NOT IN
は <> ANY
のエイリアスではありませんが、<> ALL
のエイリアスです。詳しくは 項4. 「ALL
を持つサブクエリ」 を参照してください。
SOME
という言葉は ANY
のエイリアスです。従って、これら2つのステートメントは同じになります。
SELECT s1 FROM t1 WHERE s1 <> ANY (SELECT s1 FROM t2); SELECT s1 FROM t1 WHERE s1 <> SOME (SELECT s1 FROM t2);
SOME
が利用される事はほとんどありませんが、なぜこれが役に立つのか、この例が表しています。通常、英語で 「a はどの b とも同等ではない」 と言うと、「 a と等しい b は無い」 と解釈されますが、SQL 構文ではそのような意味ではないのです。その構文は、「a と同等ではない b がいくつかある」 と意味します。<> SOME
を代わりに利用すると、そのクエリが本当に意味している事を全員がきちんと理解する助けになります。
ALL
を持つサブクエリ構文:
operand
comparison_operator
ALL (subquery
)
比較演算子の後に続かなければいけない ALL
という言葉は、「もしサブクエリが返すカラム内の値の ALL
に対する比較が TRUE
であれば、TRUE
を返す」 という事を意味します。例:
SELECT s1 FROM t1 WHERE s1 > ALL (SELECT s1 FROM t2);
テーブル (10)
を含むテーブル t1
内に行があると仮定してください。10
は t2
の中の3つの値全てよりも大きいので、もし t2
が (-5,0,+5)
を含むなら、その式は TRUE
です。10
よりも大きい単一値 12
がテーブル t2
にあるので、もしテーブル t2
が (12,6,NULL,-100)
を含むなら、その式は FALSE
です。もしテーブル t2
が (0,NULL,1)
を含むなら、その式は 不明 (NULL
) です。
最後に、もしテーブル t2
が空なら、その結果は TRUE
です。従って、テーブル t2
の時、次のステートメントは TRUE
です。
SELECT * FROM t1 WHERE 1 > ALL (SELECT s1 FROM t2);
しかし、テーブル t2
が空の時、このステートメントは NULL
です。
SELECT * FROM t1 WHERE 1 > (SELECT s1 FROM t2);
そして、テーブル t2
が空の時、次のステートメントは NULL
です。
SELECT * FROM t1 WHERE 1 > ALL (SELECT MAX(s1) FROM t2);
通常、NULL
値を含むテーブル と 空のテーブル は 「 エッジ ケースです。」サブクエリ コードを書き込む時、必ずそれら2つの可能性を考慮したかどうか、確認してください。
NOT IN
は <> ALL
のエイリアスです。従って、これら2つのステートメントは同じになります。
SELECT s1 FROM t1 WHERE s1 <> ALL (SELECT s1 FROM t2); SELECT s1 FROM t1 WHERE s1 NOT IN (SELECT s1 FROM t2);
この時点までの話は、単一値や値のカラムを返すサブクエリなどのような、スカラやカラム サブクエリに関しての物でした。行サブクエリ は単列を戻し、ひいては複数のカラム値を返す事ができるサブクエリ異型です。ここに2つ例があります。
SELECT * FROM t1 WHERE (1,2) = (SELECT column1, column2 FROM t2); SELECT * FROM t1 WHERE ROW(1,2) = (SELECT column1, column2 FROM t2);
もしテーブル t2
が column1 = 1
と column2 = 2
の場所に行を持っていれば、ここにあるクエリは両方 TRUE
です。
式 (1,2)
と ROW(1,2)
は時々 row constructors と呼ばれます。それら2つは同等の物です。それらは、別のコンテキストの中でも正当です。例えば、次の2つのステートメントは意味的に同等です。(1つ目は
MySQL 5.1.12 まで最適化する事ができませんが)
SELECT * FROM t1 WHERE (column1,column2) = (1,1); SELECT * FROM t1 WHERE column1 = 1 AND column2 = 1;
行コンストラクタは通常、2つ以上のカラムを返すサブクエリを持つ比較に対して利用します。例えば、次のクエリは要求に答え、「テーブル t2
にも存在する テーブル t1
内の全ての行を検出します。」
SELECT column1,column2,column3 FROM t1 WHERE (column1,column2,column3) IN (SELECT column1,column2,column3 FROM t2);
EXISTS
と NOT EXISTS
もしサブクエリが行を返せば、EXISTS subquery
は TRUE
で、NOT EXISTS subquery
は FALSE
です。例:
SELECT column1 FROM t1 WHERE EXISTS (SELECT * FROM t2);
もともと、EXISTS
サブクエリは SELECT *
で開始しますが、SELECT 5
や SELECT column1
、またそれ以外のどんな物でも開始する事ができます。MySQL はそのようなサブクエリの中では SELECT
リストを無視するので、何も変わらないのです。
先ほどの例では、もし t2
が NULL
値しか含まない物でも良いので、何かの行を含むのなら、EXISTS
の条件は TRUE
となります。[NOT] EXISTS
サブクエリは通常相互関係を持つので、実際はこれはよくあるような例ではありません。ここに、もう少し現実的な例があります。
複数の町には、どんな種類のお店がありますか?
SELECT DISTINCT store_type FROM stores WHERE EXISTS (SELECT * FROM cities_stores WHERE cities_stores.store_type = stores.store_type);
町ではないところには、どんな種類のお店がありますか?
SELECT DISTINCT store_type FROM stores WHERE NOT EXISTS (SELECT * FROM cities_stores WHERE cities_stores.store_type = stores.store_type);
全ての町には、どんな種類のお店がありますか?
SELECT DISTINCT store_type FROM stores s1 WHERE NOT EXISTS ( SELECT * FROM cities WHERE NOT EXISTS ( SELECT * FROM cities_stores WHERE cities_stores.city = cities.city AND cities_stores.store_type = stores.store_type));
最後の例は、二重にネスト化された NOT EXISTS
クエリです。それは、NOT EXISTS
条項の中に NOT EXISTS
条項を持っている、という事です。これは、正式に次の質問 「Stores
にはないお店がある町は存在しますか」? という質問に答えます。しかし、ネスト化した NOT EXISTS
が、次の質問 「x
は全ての y
に TRUE
ですか?」 に答える、と言う方が簡単です。
相関サブクエリ は、外部クエリ内にも現れるテーブルの参照を含むサブクエリです。例:
SELECT * FROM t1 WHERE column1 = ANY (SELECT column1 FROM t2 WHERE t2.column2 = t1.column2);
サブクエリの FROM
条項がテーブル t1
に言及しなくても、サブクエリは t1
のカラムへの参照を含むという事を覚えておいて下さい。ですので、MySQL はサブクエリの外側を見て、外部クエリ内の t1
を見付けます。
テーブル t1
が column1 = 5
と column2 = 6
の場所で行を含み、一方、 テーブル t2
は column1 = 5
と column2 = 7
の場所で行を含むと仮定してください。単純な式 ... WHERE column1 = ANY (SELECT column1 FROM t2)
は TRUE
となるでしょうが、例の中では、サブクエリ内の WHERE
条項は FALSE
ですので、((5,6)
が (5,7)
と同等ではない為) このサブクエリ全体としては FALSE
です。
スコープ ルール: MySQL は内側から外側まで評価します。例:
SELECT column1 FROM t1 AS x WHERE x.column1 = (SELECT column1 FROM t2 AS x WHERE x.column1 = (SELECT column1 FROM t3 WHERE x.column2 = t3.column1));
このステートメントの中では、SELECT column1 FROM t2 AS x ...
が t2
をリネームするので、x.column2
はテーブル t2
内のカラムでなければいけません。SELECT column1 FROM t1 ...
は とても遠くにある 外部クエリなので、これはテーブル t1
内のカラムではありません。
HAVING
か ORDER BY
条項内のサブクエリに対しては、MySQL は外部選択リストからもカラム名を探します。
特定の場合には、相関サブクエリは最適化されます。例:
val
IN (SELECTkey_val
FROMtbl_name
WHEREcorrelated_condition
)
そうでなければ、それらは役に立たず、スピードも遅くなりがちです。クエリを接合として書き換える事で、性能を向上させる事ができるかもしれません。
相関サブクエリは、外部クエリからの総計関数の結果を参照する事ができません。
FROM
条項内のサブクエリサブクエリは 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
ステートメント(派生テンポラリ テーブルが作られた) に対しても実行する事ができます。これは、上位レベルクエリが最適化の段階で全てのテーブルの情報を必要とする為に起こります。
これらはサブクエリにだけ適応するエラーです。このセクションでは、それらについて説明していきます。
サポートされていないサブクエリ構文
ERROR 1235 (ER_NOT_SUPPORTED_YET) SQLSTATE = 42000 Message = "This version of MySQL does not yet support 'LIMIT & IN/ALL/ANY/SOME subquery'"
これは、次の形のステートメントはまだ機能しないと言う意味です。
SELECT * FROM t1 WHERE s1 IN (SELECT s2 FROM t2 ORDER BY s1 LIMIT 1)
サブクエリからの不正カラム数
ERROR 1241 (ER_OPERAND_COL) SQLSTATE = 21000 Message = "Operand should contain 1 column(s)"
このエラーは、このような場合に起こります。
SELECT (SELECT column1, column2 FROM t2) FROM t1;
もし比較する事が目的であれば、複合カラムを帰すサブクエリを利用すると良いでしょう。詳しくは 項5. 「行サブクエリ」 を参照してください。しかし、別のコンテキスト内では、サブクエリはスカラ演算子でなければいけません。
サブクエリからの不正行数
ERROR 1242 (ER_SUBSELECT_NO_1_ROW) SQLSTATE = 21000 Message = "Subquery returns more than 1 row"
このエラーは、サブクエリが複数の行を返すステートメントで起こります。次の例を考えてみて下さい。
SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);
もし SELECT column1 FROM t2
が行を1つだけ返せば、その前のクエリは機能します。もしサブクエリが複数の行を返せば、エラー 1242が起きます。その場合、クエリは次のように書き直されなければいけません。
SELECT * FROM t1 WHERE column1 = ANY (SELECT column1 FROM t2);
サブクエリ内の不正使用されたテーブル
Error 1093 (ER_UPDATE_TABLE_USED) SQLSTATE = HY000 Message = "You can't specify target table 'x' for update in FROM clause"
このエラーは次のような場合に起きます。
UPDATE t1 SET column2 = (SELECT MAX(column1) FROM t1);
サブクエリは、SELECT
ステートメント同様 UPDATE
と DELETE
ステートメント内で正当なので、UPDATE
ステートメント内で、割り当ての為にサブクエリを利用する事ができます。しかし、同じテーブルを(この場合、テーブル t1
)サブクエリの FROM
条項と更新ターゲットの両方に対して利用する事はできません。
トランザクション ストレージ エンジンに対しては、サブクエリの失敗は、ステートメント全体の失敗を引き起こします。非トランザクション ストレージ エンジンに対しては、エラーが起こる前に行われたデータ修正が保持されます。
開発が進行中なので、最適化についての情報は長期的に信頼性があります。次のリストは、利用してみたいいくつかの興味深いトリックを紹介しています。
サブクエリ内の行数や行の順番に影響を与えるサブクエリ条項を利用してください。例:
SELECT * FROM t1 WHERE t1.column1 IN (SELECT column1 FROM t2 ORDER BY column1); SELECT * FROM t1 WHERE t1.column1 IN (SELECT DISTINCT column1 FROM t2); SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t2 LIMIT 1);
サブクエリと接合を置き換えてください。例えば、次の例を
SELECT DISTINCT column1 FROM t1 WHERE t1.column1 IN ( SELECT column1 FROM t2);
この次の物と置き換えます。
SELECT DISTINCT t1.column1 FROM t1, t2 WHERE t1.column1 = t2.column1;
サブクエリをサポートしない古いバージョンの MySQL の互換性で、いくつかのサブクエリは接合に変形する事ができます。しかし、いくつかの場合で、サブクエリを接合に変換する事で性能を向上させる事ができます。詳しくは 項11. 「MySQL 初期バージョンにおいて、サブクエリの接合としての書き換え」 を参照してください。
条項をサブクエリの外から中に移動させて下さい。例えば、次の例を
SELECT * FROM t1 WHERE s1 IN (SELECT s1 FROM t1 UNION ALL SELECT s1 FROM t2);
この次のクエリの代わりに利用します。
SELECT * FROM t1 WHERE s1 IN (SELECT s1 FROM t1) OR s1 IN (SELECT s1 FROM t2);
別の例として、このクエリを、
SELECT (SELECT column1 + 5 FROM t1) FROM t2;
この次のクエリの代わりに利用します。
SELECT (SELECT column1 FROM t1) + 5 FROM t2;
相関サブクエリの代わりに行サブクエリを利用してください。例えば、次の例を
SELECT * FROM t1 WHERE (column1,column2) IN (SELECT column1,column2 FROM t2);
この次のクエリの代わりに利用します。
SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t2 WHERE t2.column1=t1.column1 AND t2.column2=t1.column2);
a <> ALL (...)
ではなく NOT (a = ANY (...))
を利用してください。
x=1 OR x=2
ではなく x = ANY (table containing (1,2))
を利用してください。
EXISTS
ではなく = ANY
を利用してください。
必ず1つの行を返す相関サブクエリに対しては、IN
は必ず =
よりも遅いです。例えば、次の例を
SELECT * FROM t1 WHERE t1.col_name
= (SELECT a FROM t2 WHERE b =some_const
);
この次のクエリの代わりに利用します。
SELECT * FROM t1 WHERE t1.col_name
IN (SELECT a FROM t2 WHERE b =some_const
);
これらのトリックは、プログラムを早くしたり、遅くしたりする可能性があります。BENCHMARK()
関数のような MySQL 機能を利用すると、今の状況を改善する為のアイデアを見付ける事ができます。詳しくは 項 「情報関数」 を参照してください。
MySQL 自体が行う最適化のいくつかは次のような物です。
MySQL は非相関サブクエリを一度だけ実行します。EXPLAIN
を利用して、与えられたサブクエリが本当に非相関であるかどうかを確認してください。
MySQL は、サブクエリ中の選択リスト カラムがインデックスされる可能性の利点を利用する為に IN
、ALL
、ANY
、そして SOME
サブクエリを書き換えます。
MySQL は、EXPLAIN
が特別な接合タイプ(unique_subquery
または index_subquery
)として表現する、インデックス検索機能を利用した次の形のサブクエリを置き換えます。
... IN (SELECTindexed_column
FROMsingle_table
...)
MySQL は、NULL
値か空のセットが関連していない限り、MIN()
または MAX()
を含む式を利用した次の形の式を強化します。
value
{ALL|ANY|SOME} {> | < | >= | <=} (non-correlated subquery
)
例えば、次の WHERE
条項ですが、
WHERE 5 > ALL (SELECT x FROM t)
オプチマイザによってこのように扱われるでしょう。
WHERE 5 > (SELECT MAX(x) FROM t)
「MySQL がどのようにサブクエリを変形させるか」 というタイトルの章が、MySQL 内部マニュアルの http://dev.mysql.com/doc/ で参照可能です。
MySQL の初期バージョンでは(MySQL 4.1以前)、INSERT ... SELECT ...
と REPLACE ... SELECT ...
の形のネスト化されたクエリだけがサポートされていました。MySQL 5.1 ではそうでないとしても、値のセットの中でメンバーシップをテストする別の方法があるという事も事実です。また、場合によっては、クエリをサブクエリ無しで再書き込みする事だけでなく、先ほどの別のテクニックを利用した方がより効果的であるというのも事実です。その1つが
IN()
コンストラクトです。
例えば、次の例は
SELECT * FROM t1 WHERE id IN (SELECT id FROM t2);
次のように書き換えられます。
SELECT DISTINCT t1.* FROM t1, t2 WHERE t1.id=t2.id;
次のようなクエリは、
SELECT * FROM t1 WHERE id NOT IN (SELECT id FROM t2); SELECT * FROM t1 WHERE NOT EXISTS (SELECT id FROM t2 WHERE t1.id=t2.id);
IN()
を利用して次のように書き換えられます。
SELECT table1.* FROM table1 LEFT JOIN table2 ON table1.id=table2.id WHERE table2.id IS NULL;
サーバの方が上手最適化する事ができるかもしれないので、— MySQL サーバだけに特有であるというわけではない、LEFT [OUTER] JOIN
はそれに同等のサブクエリよりも早いかもしれません。 SQL-92 以前は外部接合が存在しなかったので、特定の作業をする為には、サブクエリが唯一の方法でした。現在は、MySQL
サーバやその他のデータベース システムが様々なタイプの外部接合を提供しています。
MySQL サーバは、1つのテーブル、または複数のテーブルから一度に出される情報に基づき、行を効果的に削除する為に利用する事ができる複合テーブル
DELETE
ステートメントをサポートします。複合テーブル UPDATE
ステートメントもまたサポートされています。