こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

このようなDELETEはできますか?

こんにちは。DELETE文の削除条件について教えてください。

例えば下記のような2つのテーブルがあったとします。

ATABLE
KEY1(ID) KEY2(DATE) ・・・・・・・・・・
------------------------------------------------
100000 2004/09/01 ・・・・・・・・・・
200000 2004/09/01 ・・・・・・・・・・
300000 2004/09/01 ・・・・・・・・・・

BTABLE
KEY1(ID) KEY2(DATE) CODE ・・・・・・・・・・
------------------------------------------------
100000 2004/09/01 0 ・・・・・・・・・・
200000 2004/09/01 0 ・・・・・・・・・・
300000 2004/09/01 1 ・・・・・・・・・・

この2つのテーブルで、BTABLEのCODEが1のレコードにKEYで関連付くATABLEのレコードを削除したいのです。

プログラムの中では対応できるのですが、SQL1文で実行させることはできるでしょうか?

とりあえず下記のように作ってみました(いたずらに長いかもしれませんが)。

DELETE FROM ATABLE WHERE

KEY1 IN (SELECT ATABLE.KEY1 FROM ATABLE,BTABLE WHERE ATABLE.KEY1 = BTABLE.KEY1 AND ATABLE.KEY2 = BTABLE.KEY2 AND BTABLE.CODE = 1) AND

KEY2 IN (SELECT ATABLE.KEY2 FROM ATABLE,BTABLE WHERE ATABLE.KEY1 = BTABLE.KEY1 AND ATABLE.KEY2 = BTABLE.KEY2 AND BTABLE.CODE = 1)

これで良い/悪い、もっと簡潔にできる、などありましたら是非お聞かせ願えますでしょうか?

よろしくお願いします。

投稿日時 - 2004-09-15 13:22:17

QNo.1002733

困ってます

質問者が選んだベストアンサー

 #3です。
 おそらく、私のsqlは、標準SQLをサポートする大概のdbmsで有効だと思います。リストの比較は、どうかしら・・・この文法をsql serverがサポートしているかどうかはちょっと知りません。

 ちなみに、元のh164さんのsqlですが、どうも違和感を感じるなと思ったら、やっぱり、まずいです。微妙な問題が潜んでいます。

atable
key1 key2  ・・・
--------------------------
10000 2004/09/01
10000 2004/09/02
20000 2004/09/01
20000 2004/09/02

btable
key1 key2 code
--------------------------
10000 2004/09/01 1
10000 2004/09/02 0
20000 2004/09/01 0
20000 2004/09/02 1

 というデータを考えたとき、おそらく、削除レコードは、10000,2004/09/01と20000,2004/09/02の二つのレコードだと思われるでしょうが・・・
 実は、全部のレコードが削除されます。
 たとえば、10000,2004/09/02のレコードですが、まず、第一の比較に置いて10000,2004/09/01が副select文の結果セットに存在するので、key1の条件は真です。第二の比較でも同様に、副select文の結果セットに20000,2004/09/02が存在するので、この条件も真となります。というわけで、本来削除されるはずのない、10000,2004/09/02のレコードは、削除されます。

 複数フィールドにおける比較を、各フィールドの比較のAND条件で結合する時は、よほど注意をしないとこういう事があります。ご注意を。

 #1および、#2の方の回答では、この問題は発生しません。リストとして同時に比較しているからです。
 #3の私のSQLも大丈夫なはずです。レコードの比較時に、元のDELETE対象の現在の操作行を連動させているからです。(従って、副SELCT文のFROM句にはATABLEの指定がありません。これは、誤記ではありませんのでご注意を。)

投稿日時 - 2004-09-15 21:53:34

お礼

ありがとうございました。とても参考になりました。

投稿日時 - 2004-09-16 09:48:00

このQ&Aは役に立ちましたか?

6人が「このQ&Aが役に立った」と投票しています

回答(4)

ANo.3

delete from atable a
where exist (select * from btable b
where a.key1=b.key1 and
a.key2=b.key2 and
b.code=1);
でいけそうな気がします。
今テストできないので自信なしとしておきます。

投稿日時 - 2004-09-15 13:59:04

補足

回答を頂いた方々、どうもありがとうございます。

最初、私が書いた物より随分簡潔になりましたね。見易いです。

ちなみに、このSQLはSQL Serverでも動作しますでしょうか?(一応、両方の環境でやってみたいもので)

情報を小出しにしてしまい、申し訳ありません。

また、このカテゴリ(Oracle)にはあてはまらないかも知れませんが、よろしければご返答ください。

投稿日時 - 2004-09-15 14:54:13

ANo.2

GoF

DELETE FROM ATABLE WHERE
( KEY1, KEY2 ) IN (
 SELECT KEY1, KEY2
 FROM BTABLE
 WHERE CODE=1
)

動作チェックをしておりませんが、大丈夫だと思います。

投稿日時 - 2004-09-15 13:53:01

お礼

本来ならポイントを発行差し上げたいのですが、回答No1のご回答のna_kirajp様よりほんの数分の差ですが遅いご回答でしたので、ポイントを2名様にしかつけられないこともあり、今回はポイントの発行はなしとさせて頂きます。
ですが、感謝の気持ちに変わりないということはご理解下さい。ありがとうございました。

投稿日時 - 2004-09-16 09:55:35

ANo.1

こんにちは

提示のSQLで基本的に考え方は合っているし問題ないと思いますが、他の例として

delete from ATABLE where (ATABLE,KEY1,ATABLE,KEY2)
in (select KEY1,KEY2 from BTABLE where code=1);

なんて言うのはどうでしょうか?
違いは、BTABLEを一度参照するだけでATABLEを消せるので
パフォーマンス的には多少良いかと・・・

投稿日時 - 2004-09-15 13:51:34

お礼

ありがとうございました。
回答No2のGoF様と同内容のご回答でしたが、回答時間の関係でこちらにポイントを差し上げることにします

投稿日時 - 2004-09-16 09:55:00