Documentation Home
MySQL 5.6 リファレンスマニュアル
Download this Manual
PDF (US Ltr) - 27.1Mb
PDF (A4) - 27.2Mb
HTML Download (TGZ) - 7.2Mb
HTML Download (Zip) - 7.2Mb


13.2.10.11 サブクエリーの結合としての書き換え

場合によっては、一連の値におけるメンバーシップをテストするために、サブクエリーを使用する以外の方法が存在することがあります。また、クエリーをサブクエリーなしで書き換えることが可能なだけでなく、サブクエリーを使用する代わりにこれらの手法のいくつかを使用する方が効率的になる場合もあります。これらのうちの 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);

は次のように書き換えることができます。

SELECT table1.*
  FROM table1 LEFT JOIN table2 ON table1.id=table2.id
  WHERE table2.id IS NULL;

LEFT [OUTER] JOIN は、サーバーがそれをより適切に最適化できる可能性がある (MySQL Server だけに特有の事実ではありません) ため、同等のサブクエリーより高速になる場合があります。SQL-92 より前は、外部結合が存在しなかったため、サブクエリーが特定の処理を実行するための唯一の方法でした。今日では、MySQL Server やその他の多くの最新データベースシステムがさまざまなタイプの外部結合を提供しています。

MySQL Server は、1 つのテーブルからの情報や、場合によっては一度に多数のテーブルからの情報に基づいて行を効率的に削除するために使用できる複数テーブルの DELETE ステートメントをサポートしています。また、複数テーブルの UPDATE ステートメントもサポートされています。セクション13.2.2「DELETE 構文」およびセクション13.2.11「UPDATE 構文」を参照してください。


User Comments
  Posted by on January 17, 2004
Here is a rough description of one more method to do something equivalent to a subquery in a DELETE for older versions of MySQL that do not support it. It only works for the case where there is a unique key on the table. It requires making a temporary table and a temporary column on the table from which you wish to delete. However it's all done in a sequence of SQL commands which is a little cleaner than the other methods.

Let's say the table from which you want to delete is "origtable". First create a temporary table with the same structure as origtable (though without autoincrement columns), let's call it "temptable". Then fill it with the rows of origtable that you wish to delete, for example:

INSERT INTO temptable SELECT ... FROM origtable WHERE ...

It's important that all results from the SELECT statement should have unique keys that are present in origtable, in other words don't do something weird here like taking the cosine of the primary key. Next create a temporary new column on origtable to designate which rows you intend to delete, and default this to 1:

ALTER TABLE origtable ADD `tempdeleteflag` int(12) NOT NULL default 1;

Next set tempdeleteflag to 0 for the rows that are present in temptable using REPLACE:

REPLACE origtable SELECT id, col1, col2, ..., colN, 0 FROM temptable;

Now tempdeleteflag should be set to 0 for rows you intended to keep or 1 for rows you inteded to delete, so:

DELETE FROM origtable WHERE tempdeleteflag = 1;

Finally clean up the temporary column:

ALTER TABLE origtable DROP tempdeleteflag;

If you created temptable using TEMPORARY it will go away when your session ends, otherwise drop it now.

As an alternative, you can do the logic the other way here:
default tempdeleteflag to 0, select rows you wish to delete into temptable, then set tempdeleteflag to 1 on rows common to the two tables.

  Posted by David Buzz on May 6, 2004
In reference to the first user comment on this page, I have 2 comments:
1) GREAT CONCEPT - I use it a lot now!
2) You actually made a typo, and if done exactly as you describe you will delete all the rows you wanted to keep, and keep those you wanted to delete!.

You say to create a "temptable" and fill it with the rows you wish to delete... this should say "fill it with the rows you wish to KEEP", alternatively the following SQL DELETE statement should be inverted so that you delete those "where tempdeleteflag = 0";

Why? Well, you are defaulting the origtable to have a value of 1 in the tempdeleteflag column, and then setting it to 0 for those that you want to DELETE. (0 means delete) obviously then the DELETE statement should delete those that are 0. Alternatively, if you set it to 0 for those that you want to KEEP (0 means keep, then 1 means DELETE) then you DELETE those that are set to 1. Be very careful to get it right.

  Posted by anonymous on August 27, 2004
About the above comments, if one can

INSERT INTO temptable SELECT ... FROM origtable WHERE ...

to choose exactly what to DELETE, why not simply

DELETE FROM origtable WHERE <same where clause as above>

and be done with it?

  Posted by Are you mortal Then prepare to die. on November 24, 2004
About the last comment, presumably the select involves a join which a straight delete could not.

A final method is to use a left join to remove those rows you dont want from the results set and insert that results set into a new table and swap that table witht the table you wanted to delete from...

I hate this method so much I am hear reading how to do this....

DELETE FROM
WHERE
ROW(SUNID1,SUNID2) IN (
SELECT
SUNID1,SUNID2
FROM
toExcludeFromInterfaceBreakdown
);

Yay for subselects!
Sign Up Login You must be logged in to post a comment.