• ベストアンサー

【SQL】existsでの商演算

閲覧ありがとうございます. 現在SQLでデータベースの勉強をしているのですが,existsを用いて商演算を行おうとしてわからない箇所が出てきたので,その点に関しての質問をさせて頂きます. 例として,A,Bと名付けた2つのテーブルを最初に用意します. [テーブル1(名前:机1)] | 番号 |氏名|年齢| 好物 | --------------------------- | 12 | あ | 1 | りんご | | 23 | い | 1 | すいか | | 23 | い | 1 | りんご | | 45 | え | 3 | すいか | | 45 | え | 3 | りんご | [テーブル2(名前:机2)] | 好物 | ---------- | りんご | | すいか | この机1を机2で割ることで,この要素を含む氏名を取り出したいと考えて,以下のようなSQL文を実行しました. select 氏名 from 机1 A where exists( select * from 机2 B where A.好物 = B.好物); [求めている結果表示] | 番号 |氏名| ------------- | 23 | い | | 45 | え | [実際に表示された結果] | 番号 |氏名| ------------- | 12 | あ | | 23 | い | | 23 | い | | 45 | え | | 45 | え | 実行すると (1)氏名が重複で表示されてしまう (2)「りんご」のみ好物の「あ」も表示されてしまう という問題が発生してしまい,色々と調べて考えたものの,結局分からなかったので,今に至ります. 長文・駄文すみませんでした. まだSQLを学び初めて少ししか経っていないので,全く違うことをしていたらすみません.よろしければ,問題解決へのアドバイスをお願いします.

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

  • ベストアンサー
  • qbr2
  • ベストアンサー率50% (62/123)
回答No.3

EXISTSを使って商演算を行っていく順序を書いておきます。 SELECT A.番号, A.氏名, A.年齢, A.好物,B.好物 FROM 机1 A,机2 B とすることで、机1と机2の全ての組み合わせが出力されます。 | 番号 |氏名|年齢| 好物 | --------------------------- | 12 | あ | 1 | りんご | | 12 | あ | 1 |すいか | | 23 | い | 1 | すいか | | 23 | い | 1 | りんご | | 45 | え | 3 | すいか | | 45 | え | 3 | りんご | 上の表から机1に含まれないレコードを抽出します。 SELECT A.番号, A.氏名, A.年齢, A.好物,B.好物 FROM 机1 A,机2 B WHERE NOT EXISTS (SELECT * FROM 机1 C WHERE A.番号=C.番号 AND A.氏名=C.氏名 AND A.年齢=C.年齢 AND B.好物=C.好物) | 番号 |氏名|年齢| 好物 | --------------------------- | 12 | あ | 1 |すいか | 最後に机1から、番号=12,氏名=あ,年齢=1 ではない番号、氏名を抽出します データの重複を回避するため、DISTINCTを使用しています。(別に、GROUP BY でも構いません) SELECT DISTINCT D.番号,D.氏名 FROM 机1 D WHERE NOT EXISTS (SELECT A.番号, A.氏名, A.年齢, A.好物,B.好物 FROM 机1 A,机2 B WHERE NOT EXISTS (SELECT * FROM 机1 C WHERE A.番号=C.番号 AND A.氏名=C.氏名 AND B.好物=C.好物) WHERE D.番号=A.番号,D.氏名=A.氏名,D.年齢=A.年齢) 上のSQLだと、少し冗長なのでまとめると、 SELECT DISTINCT A.番号,A.氏名 FROM 机1 A WHERE NOT EXISTS (SELECT 1 FROM 机2 B WHERE NOT EXISTS(SELECT 1 FROM 机1 C WHERE A.番号=C.番号 AND A.氏名=C.氏名 AND A.年齢=C.年齢 AND B.好物=C.好物)) となります。

logged
質問者

お礼

こちらが恐縮してしまうほどの丁寧な回答,ありがとうございました. おかげさまで.商演算において exists はどのような役割を持っているのか,ということについて自分なりに理解することができました.そして,質問の箇所に書いた問題点も,qbr2さんの回答を参考にして,無事に解決することができました. 本当にありがとうございました!

その他の回答 (2)

回答No.2

人毎に、すべての好物を持つか探す必要があるので、今の正規化されていないテーブル構成では、テーブル1を、「人と好物」の関連付けのためと、最終的に「人を絞る」ための2回、参照する必要があります。 ここのカテゴリ通り、RDBMSはPostgreSQLですか? バージョンは? <SQL例1>not existsを2段階で使用 select * from (select "番号","氏名" from t1 group by "番号","氏名") as x where not exists (select 1 from t2 as y where not exists (select 1 from t1 where x."番号"="番号" and y."好物"="好物" ) ) ; <SQL例2>exceptを使用 select * from (select "番号","氏名" from t1 group by "番号","氏名") as x where not exists (select "好物" from t2 except select "好物" from t1 where x."番号"="番号" ) ;

logged
質問者

お礼

書き忘れてしまいすみませんでした.はい,このカテゴリを探したのもお察しの通り postgreSQL を使用しているからです. あと,バージョンは 1.8.4 です そして,回答ありがとうございました,先ほどchukenkenkouさんの回答を参考に実行してみたところ,自分が望む結果を得ることができました. not existを2回実行することや except を使用するなどの方法は知らなかったので,この機会に勉強させて頂きました. 本当にありがとうございました.

回答No.1

こんにちは 集合の商演算について、 うまく説明できないので、 多分この参考サイトに答えがのっているのではないでしょうか。

参考URL:
http://oraclesqlpuzzle.hp.infoseek.co.jp/12-5.html
logged
質問者

お礼

回答ありがとうございました. こんなサイトがあったんですね,まだまだ調べ方が足りなかったようです.すみません.ありがたく参考にさせてもらいます.

関連するQ&A

  • SQL EXISTS演算子について

    ------------------------------------------------------- SELECT DISTINCT 商社.商社名 FROM 商社 WHERE NOT EXISTS (SELECT * FROM 商品 WHERE NOT EXISTS (SELECT * FROM 納品 WHERE 納品.商品番号 = 商品.商品番号 AND 納品.商社番号 = 商社.商社番号)) 各テーブルレイアウト 納品([商品番号]、[商社番号]、納品数量) 商品([商品番号]、商品名) 商社([商社番号]、商社名) []は主キー 条件:納品表に行が存在することは、その商品を商社が納品することを意味する。 --------------------------------------------------------- 上記SQLは、「全ての商品を納入する商社の商社名を求める」ものだそうですが、なぜそうなるのか理解できません。 具体的にどういう判定でそうなるのか教えていただけないでしょうか。

  • distinct をexistsに変換する

    distinctをexistsに変換した方がパフォーマンスが良いようで、 例えば以下の例があるとします ---------------------------------- (前)SELECT DISTINCT a.ID1, a.NAME1 FROM TABLE1 a, TABLE2 b WHERE a.ID1 = b.ID2 (後)SELECT a.ID1, a.NAME1 FROM TABLE1 a    WHERE EXISTS ( SELECT 'X' FROM TABLE2 b WHERE a.ID1 = b.ID2) ---------------------------------- もっと複雑なSQLの場合、EXISTSに変換できるのでしょうか?。複雑なSQLとは、 「複数のテーブルからカラムを取得」「テーブル結合が2つ以上」「外部結合」 などのSQLで、以下に例を示します。 (例)SELECT DISTINCT a.ID1,a.NAME1,b.ID2,b.NAME2,c.ID3,c.NAME3    FROM TABLE1 a,TABLE2 b,TABLE3 c    WHERE a.ID1 = b.ID1(+)      AND a.ID1 = c.ID1(+)

  • DELETE 文とEXISTSの使い方について(Oracle10g)

    DELETE 文とEXISTSの使い方について(Oracle10g) 2つのテーブル(A、B)を外部結合して、B側がNULLとなったレコードを A側から削除する、というDELETE文が作りたいのですが、 EXISTS句を使ってみたもののどうも使い方がわからず苦戦しています。 目的は2つのテーブルを同期させる事で このSQLを実行する時点で、常にA>Bになっています。 目的を達成できるSQLを教えてください。 <削除対象レコードをSELECTするSQL> SELECT * FROM A, B WHERE A.KEY1 = B.KEY1(+) AND A.KEY2 = B.KEY2(+) AND B.KEY1 IS NULL ; <上をDELETE文にしてみたつもりが、削除0件になってしまうSQL> DELETE FROM A WHERE EXISTS( SELECT 1 FROM B WHERE A.KEY1 = B.KEY1(+) AND A.KEY2 = B.KEY2(+) AND B.KEY1 IS NULL ) ;

  • アクセス2010 EXISTSの使い方

    テーブルA F1 F2 あい False いえ True おか True きく True けこ False テーブルB F1 あ か け TB1にTB2が含まれるデータを抽出して テーブルC F1 あい けこ をつくりたい。 DoCmd.RunSQL "INSERT INTO テーブルC (F1) " + _ "SELECT F1 From テーブルA " + _ "Where F2=False And " + _ "EXISTS (SELECT * FROM テーブルB WHERE テーブルA.F1 Like '*テーブルB.F1*' );" としたのですが、追加件数は「0」です。 Likeの使い方が悪いのか、EXISTSが悪いのか? どのようにしたらTB3の結果を得られるでしょうか?

  • SQL '%@'とは?

    こんばんわ。 SQLの質問なのですが、 SELECT * FROM aテーブル WHERE aテーブル.番号 IN '%@' というSQL文が 学校で使われていましたが、 '%@'とは何を指すのでしょうか? 調べても分からなかったので ご教授願います。

  • ACCESSのSQLの書き方

    ACCESSでのSQL文の書き方を教えてください。 テーブルtbl_Aとテーブルtbl_Bがあり, tbl_Aで得られた数値とtbl_Bで得られた数値を加えたものを結果として表示します。 どう書けばよろしいのでしょうか。どうしてもエラーになってしまいます。 イメージとしてはこんな感じです。 select (select ~~ from tbl_A where ~~)+(select ~~ from tbl_B where ~~) (もしoracleならば,「from dual」というのを最後に付けるんですが。)

  • SQL得意な方

    仕事で困っています、 なにとぞお力添えを。 テーブル1から、TOP50 でaとbを表示させたいのです。 で、その際の条件として、 開始するレコードも指定したいのです。 下記SQLの[○]の部分に50が入っていたら、 51~100件を表示する、と、いうような。 SELECT TOP 50 a,b FROM テーブル1 WHERE c='1' AND a >= '' AND a NOT IN ( SELECT TOP 〇 a FROM テーブル1) ORDER BY a で、順調だったのですが、WHERE条件が なんだか怪しいらしく、 a >= ''の時だけはきちんと動くのですが、 ANDでc='1'をつけた所、普通に全件表示されてしまいます。 [ちゃんと51件目から100件目を表示するSQL] SELECT TOP 50 a,b FROM テーブル1 WHERE a >= '' AND a NOT IN ( SELECT TOP 〇 a FROM テーブル1) ORDER BY a [何故か全件表示になるSQL] SELECT TOP 50 a,b FROM テーブル1 WHERE c='1' AND a >= '' AND a NOT IN ( SELECT TOP 〇 a FROM テーブル1) ORDER BY a ※[何故かNOT IN (~)の部分がまったく働いていない] どうしてなのでしょう?。 解りにくい質問で大変申し訳ないのですが どなたかご教授いただけないでしょうか。

  • SQLの問題です。

    以下のような二つのテーブルがあります。 社員テーブル 社員番号 社員氏名 1     花子 2     太郎 所属テーブル 社員番号 所属番号 1     10 1     20 2     30 欲しいのは以下の結果です。 1 花子 2 太郎 以下のSQLを実行すると、 SELECT distinct a.社員番号, a.社員氏名, b.所属番号 FROM 社員 a,所属 b where a.社員番号 = b.社員番号 order by 所属番号 1 花子 1 花子 2 太郎 となってしまいます。 先に述べたとおりの結果を取得するにはどういうSQLを書いたらいいでしょうか? お知恵を貸してください。宜しくお願いします。 Oracle8iを使用しています。   

  • SQL文でexistsの使い方がわかりません。

    受注表と作業員表のデータベースをaccessで作りました。 受注表の中には受注CD、作業開始時間、作業終了時間、作業日、作業員1、作業員2のフィールドがあります。 作業員表には氏名、作業可能開始時間、作業可能終了時間 作業可能日のフィールドがあります。 受注表に登録する作業員の氏名を一覧表で表示させたいときはどのようなSQL文を作れば良いのでしょうか? 受注表には作業日が同じで作業開始時間と作業終了時間が重なるものがあり、その場合には先に受注した作業に担当者1か担当者2として登録されている作業員は一覧表に表示させないようにしたいのですがやり方がわかりません。not existsの中が特にわかりません。 select 氏名 from 作業員表 where 作業可能開始時間 <= 1430 and 作業可能終了時間 >= 1530 and 作業可能日=2010/10/1 and not exists (select * from 受注表 where 受注表.作業員1 = 作業員表.氏名 or 受注表.作業員2 = 作業員表.氏名 and 受注表.作業開始時間 <= 1430 and 受注表.作業終了時間 >= 1530 and 受注表.作業日=2010/10/1) 上記のSQL文を作って受注表に登録されていない作業員を表示させようと試してみましたが失敗しました。 作業日、作業開始時間、作業終了時間はフォームを作成してそこで入力します。

  • SQLについて

    SELECT テーブル名.A テーブル名.B FROM テーブル名 WHERE テーブル名.A = Y テーブル名.B = Z SELECT 別テーブル名.A 別テーブル名.B FROM 別テーブル という2つのSQLがあったとします。この時、別テーブルのSELECT文より取得してきた、AとBを上の式の条件(Y,Z)で両方同時に使用したい場合、どのようなSQLを書いたら良いのでしょうか? 1文にまとめて書く場合です。