SQLで重複を無視した結果を得る方法

このQ&Aのポイント
  • 大規模商談の営業リストを作成するために、SQLで重複を無視した結果を得る方法を教えてください。
  • 提供されたテーブルから、特定の列を重複なく取得するためには、DISTINCTキーワードを使用します。しかし、この方法では特定の列だけが重複なくなりますが、他の列は重複したままです。
  • 重複を無視して全体の行を取得するためには、GROUP BY句を使用します。GROUP BY句は、指定した列でグループ化し、各グループの1行だけを採用します。そのため、GROUP BY句を使用してname列をグループ化することで、全体の行で重複をなくすことができます。
回答を見る
  • ベストアンサー

無視されるdistinct

お世話になります  大規模商談をまとめた営業のリストを作るSQLを書こうとしています。   営業部員テーブル (test.person) id | name ----+------ 1 | 山田 2 | 高橋 3 | 田中 商談テーブル (test.deal) id | person_id | customer | amount ----+-----------+----------+-------- 1 | 1 | XX商事 | 20000 2 | 3 | BB電機 | 10000 3 | 2 | ZZ不動産 | 2000 4 | 1 | RR証券 | 8000 期待している検索結果 name | amount | customer ------+--------+---------- 山田 | 20000 | XX商事 田中 | 10000 | BB電機 高橋 | 2000 | ZZ不動産 下記のようなSQLを書きました。 select distinct name,amount,customer from test.deal,test.person where person.id=deal.person_id order by amount desc  しかし、nameをdistinctしているにもかかわらず、結果は下記の通り、「山田」が重複しています。 name | amount | customer ------+--------+---------- 山田 | 20000 | XX商事 田中 | 10000 | BB電機 山田 | 8000 | RR証券 高橋 | 2000 | ZZ不動産 いろいろと調べて、group by を使えばいい、というようなやり方を示している例も多かったのですが、それもうまくいきません。(必要であれば載せます) 期待通りの結果を得るにはどのようなSQLを書けばよろしいでしょうか。 よろしくお願いいたします。

  • annyG
  • お礼率70% (67/95)

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

  • ベストアンサー
回答No.4

SQLの基本操作の一つである「group by」を、理解できていませんね。 基本操作から、しっかり勉強すべきです。 >実はgroup by も試してみたのですが、どうもうまくいきません。 >とりあえず、下記のようなSQLを書いてみました。 >select name,max(amount),customer >from test.deal,test.person >where person.id=deal.person_id >group by name >order by max(amount) desc 理解できていないまま、いい加減なことをやっていますよ? > ERROR: column "deal.customer" must appear in the GROUP BY clause or be >used in an aggregate function; >言われるままに、group byの中にcustomerを入れると下記のような結果に >なり、group byを付けても付けなくても同じになります エラーの内容を取り違えて、デタラメな対処を行っていますよ? >group by を使用するとして、名前の重複を避けるにはどのようにしたら 名前の重複を起こさない(つまり、どのデータを活かすか?)が、不明瞭だし、SQLとして指定されていないのですよ。 どうしたい(どのデータを活かしたい)のですか? また、得たい結果(仕様)で、まだまだ不明瞭な点があります。 person_id毎に、最大のamountを得るのは簡単です。 しかし、同じperson_idで求めた最大のamountが、二箇所以上のcustomerで記録されていた場合、どういう結果を得たいのでしょうか? 理解できていないのに、デタラメの上にさらにデタラメを繰り返すのでなく、簡単なクエリから順次、組み立てていきましょう。 今回のクエリは、次の(1)~(3)の順に組み立てていくと、具体的な仕様が明確でない部分が明確になり、SQLの理解も進むと思います。 (1)test_deal表で、person_id毎に最大のamountを得る (2)(1)に該当するtest_deal表のidを得る  →全idとするのか、最大のidあるいは最小のidとするのか、仕様の明確化が必要 (3)(2)のidと、test_person表を結合する

その他の回答 (4)

回答No.5

#4回答の1箇所訂正。 <訂正前> (3)(2)のidと、test_person表を結合する ↓ <訂正後> (3)(2)のidの行のperson_idと、test_person表を結合する =====以下、独り言===== select person_id,max(amount) from test_deal group by person_id ; select * from test_deal as d where id=(select min(id) from test_deal where d.person_id=person_id having d.amount=max(amount) ) order by id ; select * from test_person as p inner join ( select * from test_deal as d where id=(select min(id) from test_deal where d.person_id=person_id having d.amount=max(amount) ) ) as x on p.id=x.person_id order by p.id ;

annyG
質問者

お礼

 すばらしいです。これは難しいんじゃないかと思っていたので、正直いって驚きました。  実は質問を投稿する前から、これはgroup by で解決できそうに見えて実はそうじゃない、というパターンじゃないかという気がしていました。ですが相関サブクエリなどをちょっと書いてみても、どうもいい方法が思いつかないので質問させていただいた次第です。  group by なしの having というのはまだあまり勉強していないところなので、これを機に調べてみたいと思います。  SQLの奥の深さを改めて教えていただいた気分です。本当にありがとうございました。

  • denbee
  • ベストアンサー率28% (192/671)
回答No.3

回答にあるような条件づけをしたいのであれば、Distinctではいけません。 ちゃんとamountがMAXのものだけを収集する条件づけのためにも、Group by句が必要です。 とりあえず、以下のページを参考にしてみてください。 http://www.techscore.com/tech/sql/05_08.html

annyG
質問者

補足

ありがとうございます。 実はgroup by も試してみたのですが、どうもうまくいきません。 とりあえず、下記のようなSQLを書いてみました。 select name,max(amount),customer from test.deal,test.person where person.id=deal.person_id group by name order by max(amount) desc すると、下記のようなエラーになります。 > ERROR: column "deal.customer" must appear in the GROUP BY clause or be used in an aggregate function; 言われるままに、group byの中にcustomerを入れると下記のような結果になり、group byを付けても付けなくても同じになります name | max | customer ------+-------+---------- 山田 | 20000 | XX商事 田中 | 10000 | BB電機 山田 | 8000 | RR証券 高橋 | 2000 | ZZ不動産  group by を使用するとして、名前の重複を避けるにはどのようにしたらよろしいでしょうか。 よろしくお願いいたします。

  • denbee
  • ベストアンサー率28% (192/671)
回答No.2

何をしたいのかがよくわかりません。 上記の例ですと、山田は2件の商談をまとめたにもかかわらず、どちらか1件(金額が大きい方?)でしか ランキングに載せたくないわけですか? 「各部員のまとめた商談を、金額の大きい順に並べる。 ただし、複数の商談をまとめた部員は、もっとも金額の大きい商談だけを 表示させる」 という動作?

annyG
質問者

補足

はい、そういうことです。 例を変えるならば、こんなものです 1 2.19.41 渋井 陽子 三井住友海上 2004. 9.25 大   阪 2 2.21.47 高橋 尚子 積 水 化 学 1998.12.06 バ ン コ ク 3 2.21.18 野口みずき グローバリー 2003. 1.26 大   阪 4 2.21.45 千葉 真子 豊田自動織機 2003. 1.26 大   阪 5 2.21.51 坂本 直子 天 満 屋 2003. 1.26 大   阪 6 2.22.12 山口 衛里 天 満 屋 1999.11.21 東   京 7 2.22.46 土佐 礼子 三井住友海上 2002. 4.14 ロ ン ド ン 8 2.22.56 弘山 晴美 資 生 堂 2000. 1.30 大   阪 9 2.23.26 大南 博美 UFJ銀行 2004. 9.25 ベ ル リ ン 10 2.23.30 小崎 まり ノ ー リ ツ 2003. 1.26 大   阪 http://www.geocities.jp/majikanahappy/marathonkiroku.html 高橋尚子は2時間22分台で何回か走っていますが、ここには載ってません。

回答No.1

>nameをdistinctしているにもかかわらず 重複排除しているのは、nameでだけでなく、name,amount,customerの組み合わせでの指定になっています。 >期待している検索結果 「RR証券」を検索対象から外すのは、どういう条件でですか?

annyG
質問者

補足

ありがとうございます。 なるほど、distinctは全てにかかるのですね。とても勉強になりました。 RR証券をはずす条件(というか、理由)は、 この検索結果は営業部員個人のランキングですので、山田さんが1位と3位に2回出てくるのは望ましくない、ということです。 上記、補足になっておりますでしょうか。 よろしくお願いいたします。

関連するQ&A

  • 行の結合?

    こんにちは。 SQLについて質問です。 id  name  goal 1  山田  東京 2  木下  北海道 3  高橋  大阪 3  高橋  沖縄 こういう状態でデータが入っていたとして、 idが3の高橋はgoalが違う状態で2件データがあります。 これを、 id  name  goal 1  山田  東京 2  木下  北海道 3  高橋  大阪、沖縄 こうなるようにしたいのですが、 どうSELECT文を書けばよいでしょうか? よろしくお願いします。  

  • SQLのテーブルの特定カラムでループ検索?

    説明が苦手でご迷惑をおかけします。 [denwa_table] id name telno 1 田中 080888866XX 2 山田 090999988XX 3 佐藤 050333366XX このようなテーブルがあり、 別で取得した 「0125815846584123584090999988XX3254158912_3546842」 のような文字列にID何番の人の電話番号が含まれているか 検索するPHPを作成しています。 初心者なので、いろいろわからないのですが、 特に理解できていないのが複数行の配列の操作です。 $sql = "select telno from denwa_table"; 電話番号部分のカラムだけをとってきてとかやればいいのでしょうか? 検索する部分は strstr($data,$data2)を使ったらできそうですが、SQLからとってきた番号の配列をどうやってループさせたらいいのでしょうか? わからないことだらけなのですがよろしくお願いします。

    • ベストアンサー
    • PHP
  • MYSQLで重複せずにカウント上位から取得したい

    お世話になります。 MYSQLにて以下のようなtableがあるとします。 id ex_id name count flag time memo 1 1 山田 100 on 10:11 テスト 2 1 山田 80 on 10:12 テスト2 3 2 田中 50 on 10:13 テスト3 4 3 鈴木 30 on 10:14 テスト4 5 3 鈴木 110 on 10:14 テスト5 6 3 鈴木 10 on 10:14 テスト6 このうち、countの数字が高いものから表示したいのですが、 ex_idが重複する場合はその数字が最も高いもののみ表示したく考えています。 目的とした表示結果順は以下です。 id ex_id name count flag time memo 5 3 鈴木 110 on 10:14 テスト5 1 1 山田 100 on 10:11 テスト 3 2 田中 50 on 10:13 テスト3 distinctやgroup byなど色々考えてみたのですが、思ったような挙動になりませんでした。 以上、よろしくお願い致します。

  • このような結果が得られるSQL文はどのように書けばいいのでしょうか?

    お世話になります。 どなたかご教授下さい。 下記のようなテーブルが2つあります。 table1 ・customer_id ・fromdate ・todate table2 ・customer_id ・executedate ・amount やりたいことは、顧客([customer_id])ごとに集計期間(executedate between [fromdate] and [todate])が異なるのですが、 その顧客ごとの集計期間内における総数(sum([amount])を出したいのです。 ただ、どのようにSQLを書けばいいのか検討がつかないので、どなたかご教授いただければなと思います。

  • access2007 VBAでSQLのUPDATE

    access2007 VBAでSQLのUPDATEの使い方の質問です 下のような顧客テーブルがあり ID   担当者  会社名     電話番号   1    山田   XX産業     1234 2          株式会社XX  244343 3    山本   YY会社     432054 4    田中   XX商事     59680 5          TT工業     5493 6    佐藤   jj加工      54354 7          XX工務店   43202 8    湯浅   Xx工業 担当者列が空白の行を見つけ、上から2行目までの担当者列に中村と入力したいのですが 以下のようにしても上手くいきません。 ("UPDATE 顧客テーブル SET 担当者 = '中村' WHERE 担当者 IN (SELECT TOP 2 担当者 FROM 顧客テーブル)") 上記テーブルですと、ID2、5の担当者名が中村になるようにしたいのです。 どなたかお知恵をお貸しください。

  • SQLで条件に合うデータの前後に文字をスマート付加

    こんにちは データベース(mdbファイル)で、次のような置き換えをしたいのですが、スマートなやり方をご存じでしたら教えてください。 Membersテーブル id, name, status 1, 田中, 200 2, 鈴木, 300 3, 高橋, 200 4, 中村, 400 Membersテーブルのうち、status が 200 のレコードになっている name の前後に「ABC」と「XYZ」を付加する、という操作です。 置き換え作業後は次のようになります。 Membersテーブル id, name, status 1, ABC田中XYZ, 200 2, 鈴木, 300 3, ABC高橋XYZ, 200 4, 中村, 400 Where status = 200 と指定して、帰ってきたレコードをループさせて、1件ずつUpdateすればできるのですが、そもそもSQLコマンドの時点でスマートにできるのではないかと思い質問した次第です。SQLは詳しくないのですが、意外に柔軟でスマートなことができるようですので。。。 対象のファイルはmdbで、スクリプトはまだ作っていませんが、vbsになるのではないかと思っています。 Windows 7 and 8 64bit MS Accessはありません

  • 副問い合わせ

    今はこのようなSQL文を書きたいですが・・ table1 user_id | time 1 | 122120 2 | 100530 table2 user_id | name 1  | 佐藤 2    | 田中 SQL文       結果はこう user_id|name| time 001 |佐藤| 122120 002 |田中| 100530 に出力したいけど、初心者なので、方法が良くわかりません。 ご教授ください。

  • SQL文 テーブルの作成方法について

    以下のようなTABLE1からTABLE2というテーブルを作成したいと考えております。 元テーブル(TABLE1)は、IDという項目がキーとなってデータが入っており、NAME1とNAME2という項目があります。 (NAME1は必ず値が入っていますが、NAME2は値が入っていない場合もあります) 加工後のテーブル(TABLE2)で、NAME1とNAME2の値を結合した形で結果を出力したいと考えております。 (新たに作成したNAMEカラムは、必ずしもユニークになっているとは限りません。NAMEとIDを組み合わせるとユニークになります) ---------------------------------------------------- ■ TABLE1 ID NAME1 NAME1_CATE NAME2 NAME2_CATE ---------------------------------------------------- 001 鈴木 A 山田 B 002 山本 A 003 佐藤 A 高橋 B ---------------------------------------------------- ---------------------------------------------------- ■ TABLE2 ID NAME NAME_CATE ---------------------------------------------------- 001 鈴木 A 001 山田 B 002 山本 A 003 佐藤 A 003 高橋 B ・・・ ---------------------------------------------------- いろいろ試していますが、どのようなSQL文を書いたらよいのか分かりません。 現状のSQL(エラーとなります) ====================================================================================== SELECT ID, NAME, NAME_CATE FROM (SELECT ID, NAME1 as NAME, NAME1_CATE as NAME_CATE FROM TABLE1 WHERE NAME1<>NULL) JOIN (SELECT ID, NAME2 as NAME, NAME2_CATE as NAME_CATE FROM TABLE1 WHERE NAME2<>NULL) ====================================================================================== 初歩的な質問になるかと思ってしまうかと思いますが、よろしくお願いいたします。

  • 配列の要素をキーにする

    Array (   [Id] => Array     (       [0] => 17       [1] => 18     )   [Name] => Array     (       [0] => 山田       [1] => 田中     ) ) のような配列があります。 これを、 Array (   [17] => 山田   [18] => 田中 ) のようにしたいのですが、どのようにすればよいでしょうか。 初心者質問で申し訳ないのですが、ご教授のほど宜しくお願い致します。

    • ベストアンサー
    • PHP
  • 次の条件を満たすSQL文をご教示下さい。

    テーブル名: list no | first_name | last_name | comment ----+------------+-----------+--------- 1 | 太郎 | 山田 | ほげ 2 | 次郎 | 田中 | ふが 3 | 花子 | 山田 | ぴよ 4 | 三郎 | 佐藤 | ぴよ 5 | 太郎 | 山田 | ぴよ 6 | 次郎 | 田中 | ふー 7 | 三郎 | 佐藤 | ふー 8 | 花子 | 山田 | ふー 上記の表から同じ”last_name”を持つ人の”first_name”と”last_name”を重複無しで抽出する(下記のような結果)SQL文は作成可能でしょうか。 結果 first_name | last_name ------------+----------- 太郎 | 山田 花子 | 山田 宜しくお願いします。