• ベストアンサー

group by 関数で表示するカラムを選ぶ方法

いつもお世話になっております。 MySQLで、group by関数を使用した際の表示カラムをコントロールしたいのですが、やり方が分りません。 具体的には id | e_mail | date 1 | t1@t.jp| 2005-05-21 2 | t1@t.jp| 2005-05-22 3 | t1@t.jp| 2005-05-23 4 | t1@t.jp| 2005-05-24 5 | t1@t.jp| 2005-05-25 6 | t1@t.jp| 2005-05-26 7 | t1@t.jp| 2005-05-27 8 | t1@t.jp| 2005-05-28 というデータがあります。 このデータをe_mailでグループ化した場合に、表示されるe_mailを好きなidのものに置き換えたいのです。 通常のSQL文 select id,e_mail,date from table_name group by e_mail だと、どのidのt1@t.jpというアドレスが表示されるのかコントロールできません。 好きなidやdateのt1@t.jpというe_mailを抽出する方法をご教授頂けると大変助かります。 宜しくお願い致します。

  • nikuq
  • お礼率75% (477/631)
  • MySQL
  • 回答数8
  • ありがとう数7

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

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

代表的な書き方を忘れていました。 SQL-92で規定され、SQL Server以外の主要なRDBMSで実装されている「行値式(または行値構成子)」という書き方です。 <e_mail毎に最新の行を得たい> select * from t1 where (e_mail,date) in(select e_mail,max(date) from t1 group by e_mail); <e_mail毎に最古の行を得たい> select * from t1 where (e_mail,date) in(select e_mail,min(date) from t1 group by e_mail); #6回答のSQLでは、e_mail、dateしか取り出していませんでした。 それ以外の列も取り出せるようにしたい場合は、以下のように書けます。また、別名を再使用していたので、その部分も変更しました。 <e_mail毎に最新の行を得たい> select a.* from t1 as a, (select x.e_mail,x.date,count(*) as rank from t1 as x,t1 as y where x.e_mail=y.e_mail and x.date<=y.date group by x.e_mail,x.date) as b where a.e_mail=b.e_mail and a.date=b.date and rank=1 ; <e_mail毎に最古の行を得たい> select a.* from t1 as a, (select x.e_mail,x.date,count(*) as rank from t1 as x,t1 as y where x.e_mail=y.e_mail and x.date>=y.date group by x.e_mail,x.date) as b where a.e_mail=b.e_mail and a.date=b.date and rank=1 ;

nikuq
質問者

お礼

ありがとうございます! いろんな副問合せの形があるんですね。 SQLは奥が深いですね。 本当に勉強になります!ありがとうございました!

その他の回答 (7)

回答No.7

#3、#6回答者です。 #6回答のSQLは、以下のような書き方もできます。 <e_mail毎にdateが最新の行を得たい> select x.e_mail,x.date from t1 as x, (select e_mail,max(date) as max_date from t1 group by e_mail) as y where x.e_mail=y.e_mail and x.date=y.max_date ; <<e_mail毎にdateが最古の行を得たい> select x.e_mail,x.date from t1 as x, (select e_mail,min(date) as min_date from t1 group by e_mail) as y where x.e_mail=y.e_mail and x.date=y.min_date ;

回答No.6

#3回答者です。 RDBMSにおいて、格納順の検索は保証されません。 仮にRDBMS側で、後方追加が原則であっても、前方の領域の行が削除された場合、再利用される場合もあります。 そのため、格納順を意識したい場合は、利用者側で通番やタイムスタンプで意識する必要があります。 <e_mail毎に最新の行を得たい場合> select * from (select x.e_mail,x.date,count(*) as rank from t1 as x,t1 as y where x.e_mail=y.e_mail and x.date<=y.date group by x.e_mail,x.date) as x where rank=1 ; <e_mail毎に最古の行を得たい場合> select * from (select x.e_mail,x.date,count(*) as rank from t1 as x,t1 as y where x.e_mail=y.e_mail and x.date>=y.date group by x.e_mail,x.date) as x where rank=1 ;

  • mooboogie
  • ベストアンサー率68% (28/41)
回答No.5

ひょっとして。 「group byしたとき、最古のデータが選択されるので困る」(質問文のケース) という話でしょうか。 下記にズラズラ書きましたが、出来るというだけで意味はないスクリプトです。 最新のdateでの抽出目的でgroup byするのは意味が無いです。 それは#2、#3さんが書いてあるとおりです。 以下が本題です。 group byしただけだと、データベースの格納順で該当カラムの先頭データが表示されるようです。 逆に言えば、group byする前に用途にあった並びに並び替えないといけない。 つまり、今回の場合はdateを降順にしておかないといけない。 バージョンが5.xであると副問い合わせができるので、降順ソートしておいたレコード群をgroup byしてあげる必要があります。 drop table t3038229; create table t3038229 (email varchar(30), date varchar(10),comment varchar(30)); insert into t3038229 values ("t1@t.jp","2005-05-22","t1のDB格納先頭"), ("t1@t.jp","2005-05-25","あ"), ("t1@t.jp","2005-05-23","い"), ("t1@t.jp","2005-05-24","う"), ("t1@t.jp","2005-05-26","え"), ("t1@t.jp","2005-05-27","お"), ("t1@t.jp","2005-05-28","t1の最新"), ("t2@t.jp","2005-05-24","t2のDB格納先頭"), ("t1@t.jp","2005-05-21","か"), ("t2@t.jp","2005-05-25","き"), ("t2@t.jp","2005-05-23","く"), ("t2@t.jp","2005-05-26","t2の最新"), ("t3@t.jp","2005-05-25","t3のDB格納先頭"), ("t3@t.jp","2005-05-26","t3の最新"); /* 最新date抽出スクリプト */ select email,date,comment from (select email,date,comment from t3038229 order by date desc) as a group by a.email; /* group by しただけ */ select email,date,comment from t3038229 group by email;

nikuq
質問者

お礼

ありがとうございます! 副問い合わせという事ができるんですね。 今まで使った事がありませんでした。これは便利ですね! 副問合せを使用すれば、やりたいことが全て解決しました! 本当に助かりました!

  • mooboogie
  • ベストアンサー率68% (28/41)
回答No.4

そもそも「好きな」値を表示(抽出)させたいという要望を実現するのは、「where」です。 置き換えたい場合は、「replace」という関数が使えます。 select id,replace(e_mail,'@t.jp','@softbank.ne.jp'),date from table_name; 皆さんの仰る通り、group byを使ってやりたいことが見えないのでこのような回答になってしまいました。

nikuq
質問者

補足

ありがとうございます。 すみません。私の説明が全然不足しておりました。 皆さんがおっしゃる通り、group関数でグループ化するなら、idやdateでコントロールする必要はないです。 私がやりたい事は、e_mailでグループ化した際にdateでソートし、最新のt1@t.jpというe_mailのレコードを抽出したいという事なのです。

回答No.3

標準SQLでは、「group by」指定時には、select文の選択リストには、「group by」で指定した列か、max、min、countなどの集合関数しか指定できないことになっています。 <例> <<正しい例>> select c1,max(c2),min(c3) from t1 group by c1 <<誤った例>> select c1,c2,c3 from t1 group by c1 殆どのRDBMSでは、グルー化列や、集合関数で指定していない列を、select文の選択リストで指定すると、文法エラーにしています。 MySQLでは、このことに関して、拡張仕様を持っています。 http://dev.mysql.com/doc/refman/4.1/ja/group-by-hidden-fields.html?ff=nopfpls これは、 select c1,c2,c3 from t1 group by c1 としても、「文法エラーにはしない」という一方で、「c2やc3は、グループ化の結果、一意な値にならないなら、結果は保証しない」ということです。 利用者は、上記の前提条件を満たす場合にのみ、MySQLの拡張仕様を利用することができます。そうでないなら、この拡張仕様を利用すべきではありません。

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.2

そもそもすきなidを選ぶ時点でgroup byするのは整合性がないかと。 select `id`,`e_mail`,`date` from `table_name` where `e_mail`='t1@t.jp' and `id`='1' で十分では?

回答No.1

私はSQL 系のソフトの使用経験無いんで的外れだったらごめん。 >どのidのt1@t.jpというアドレスが表示されるのかコントロールできません。 そのクエリで表示されるの? 一応これを見ると http://www.atmarkit.co.jp/fnetwork/rensai/sql03/sql1.html >「SELECT」句には、GROUP BYで指定した列と集計関数のみを指定することができます。 を満たさないとき SQL Serverでエラーになっていて 以下と照らし合わせるとMySQLでも同じようなエラーが出るみたいなんだけど・・・ http://sqlzoo.net/howto/source/z.dir/err979/sqlserver http://sqlzoo.net/howto/source/z.dir/err979/mysql

関連するQ&A

  • GROUP BY の指定で

    MySqlには不慣れな者です。 来店table id|text_date |name 1 |20120101010101|山田 2 |20120222001227|鈴木 3 |20120309035932|福田 4 |20120309035932|館山 5 |20120713121211|大沢 6 |20120822120127|矢島 といったテーブルがあるとします。 カラムtext_dateはCHARで、日時データを持っています。 (ちょっと解り辛いサンプルで失敬) SELECT text_date, count(*) FROM 来店table WHERE text_date >= "20120101010101" GROUP BY text_date; とするとid 3・4の同日時のみカウント2として以外はカウント1で出ると思います。 希望ですが、カラムtext_dateの時間部(8・9番目の数字)でカウントを取りたいのですが。 GROUP BY の指定方法でそのような事はできるのでしょうか? MySqlのリファレンスを色々探し回っているのですが、見つけることができません。 ご助力いただけると助かります。

    • ベストアンサー
    • MySQL
  • MYSQLでgroup by を教えてください。

    まだ初心者なんです。よろしくお願いいたします。 テーブル$tbl_nameに日付date コラムに (2009-11-3 14:25:06).(2009-11-3 11:25:06). (2009-11-5 12:25:06).(... ....と年齢 ageコラムに (18)(19)(20)... 性別コラムage に (danshi)(jyoshi) が入っています。 これを日付別 に内容が存在するだけ出力したいのです。 出力内容は(18)→25、(19)→13、(20)→7、の数だけ、 同様に(danshi)→20、(jyoshi)→25、というように 〇月〇日18才は25人、19才は13人、20才は7人、 男子は20人、女子は25人と出したいのです。 $sql = "SELECT 'age',count(age) FROM $tbl_name group by 'date'"; $result = mysql_query($sql, $db) or die("クエリの送信に失敗しました。<br />SQL:".$sql); while ($row = mysql_fetch_assoc($result)){ $age .=$row;} 等記入しているのですが、何とも動きませんのです。 どうしたらよろしいものでしょう。よろしくお願いいたします。

  • SQLのcount()とgroup by

    以下のようなテーブルがあったとき、 tbl1 id | score 1 | 100 1 | 200 1 | 300 2 | 200 2 | 100 3 | 300 3 | 400 3 | 500 3 | 600 idでまとめて個数を出すとすると、 SELECT count(*) FROM tbl1 group by id とすれば count(*) 3 2 4 と結果が返ってきますが、この結果にidを足して id | count(*) 1 | 3 2 | 2 3 | 4 というようなSQLはどうやって書けばいいのでしょうか? MySQLでは、 SELECT id, count(*) FROM tbl1 group by id と書けるのですが、これは標準的なSQLではNGなそうなので、気になって質問しました。 よろしくお願いします。

  • group byで指定したカラム以外のカラムの値を取得したい

    t_meisaiは以下の定義で調味料の使用履歴を記録しています。 id int4 uniqueな値 date timestamp yy/mm/dd type int4 1 or 2 or 3 order int4 純粋な順番 typeには塩、砂糖のように固形のものは1、酢、醤油のように液状のものは2、それ以外は3が入ります。 orderはdate毎に使った順番が記録されていきます。 date || type のgroupごとの一番最初に使ったものだけ抽出したのが下のSQLです。 select date || type as key, min(order) from t_meisai group by key 上記の条件に当てはまるレコードのidを抽出したいのですがどうしたらよいのでしょうか?

  • group byを使う時に条件をつけたいです。

    どう頑張っても思いどうりにDBからデータがとれず困ってます... 例えばこんなテーブルがあったら(テーブル名が"test"、カラムが"name"と"id") table test name | id ---------- aa | 1 aa | 1 aa | 1 bb | 1 bb | 1 aa | 0 aa | 0 cc | 0 カラム"id"が0の時は、カラム"name"のgroup byせず カラム"id"が1の時だけ、カラム"name"のgroup byするには、どうすればいいのでしょう? このような感じにデータを取り出したいのです。 name | id  | COUNT ---------- aa | 1 | 3 bb | 1 | 2 aa | 0 | 1 aa | 0 | 1 cc | 0 | 1 よろしくお願いします。

    • ベストアンサー
    • MySQL
  • group byのSQLでインデックスを使いたい

    group byのSQLでインデックスは使えないものなのでしょうか. Using filesortにより,全レコードを読んでしまっています. どなたか解決法を教えてください. mysql> describe xxxxx; +--------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------+--------------+------+-----+---------+----------------+ | aaa_id | bigint(20) | | PRI | NULL | auto_increment | | bbb_id | bigint(20) | | MUL | 0 | | | ccc_id | bigint(20) | | MUL | 0 | | +--------+--------------+------+-----+---------+----------------+ mysql> explain select ccc_id from xxxxx group by ccc_id =2; +----+-------------+-------+-------+---------------+--------+---------+------+------+----------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+--------+---------+------+------+----------------------------------------------+ | 1 | SIMPLE | xxxxx | index | NULL | ccc_id | 8 | NULL | 628 | Using index; Using temporary; Using filesort | +----+-------------+-------+-------+---------------+--------+---------+------+------+----------------------------------------------+

    • ベストアンサー
    • MySQL
  • SQL GROUP BY

    SQLについてお聞きしたいです。番号カラムの中で最大の数字をもつフィールドと 同じコードを持つデータを、表から全て取得したいと思っているのですが 書き出すとGROUP BYの式が間違っているというエラーが出てしまいます。 SELECT * FROM 表 GROUP BY コード HAVING MAX(番号) = コード どう調べればいいのか分からず四苦八苦しています。どこを直せばよいでしょうか?

  • MySQLで、指定の複数カラムのみコピーする方法

    同じ構造の、  A_table と B_table があります。 それぞれに  id date name address mail comment という、6つのカラムがあります。 変更があった際に、 A_table にcsvで全データをインポートし、  B_table に変更のあったカラム( date name address mail )の列だけをコピーしたいと思っています。 ( id )は A_table と B_table 共通にし、変更しないことを前提としています。 ( comment )は外部から編集できるため、csvデータが最新の情報とは限りませんので、 csvデータでの変更は考えておりません。 レコード数としては、多い方だと思います。 上記の作業をしようと思っているのですが、 >> B_table に変更のあったカラム( date name address mail )の列だけをコピー する方法をご存じの方がいらっしゃいましたら、何卒、ご教授お願い致します。 また、 変更したいカラムだけ、csvデータとidを共通にすればインポート可能かな…と探してはみたのですが無いようで、こちらはできないと考えても大丈夫なのでしょうか。 (phpmyadminを利用しておりますが、カラム名を指定してインポートはできるのですが、  指定しないカラムは空白になって上書きされてしまいます。) ついでで申し訳ないですが、宜しければアドバイスをいただければと思います。

  • mysqlでカンマデータのgroup by

    初めての質問になります。 以下のようなテーブルで、dataカラムにカンマ区切りのデータを保存しているのですが、こちらはgroup byやcount等を使ってSQL一発で集計結果を取得できるのでしょうか? SELECT count(*) FROM TEST WHERE FIND_IN_SET('1', data)で1から順番に取得は出来るのですが、数が多いとちょっといかがなものかと思い、質問させていただきました。 環境:mysql5.5 ------------ |data ------------ |1,2,3 ------------ |1,2,10 ------------ |1,2,3,10 ------------ 期待する結果は以下のような感じです。 1|3 --------- 2|3 --------- 3|2 --------- 10|2

    • ベストアンサー
    • MySQL
  • GROUP BY/ORDER BYの併用で期待するORDERが得られま

    GROUP BY/ORDER BYの併用で期待するORDERが得られません。 データベース初心者です。よろしくお願いいたします。 table id group_id name 1 1 冷蔵庫1 2 2 カメラ1 3 2 カメラ2 4 2 カメラ3 5 3 テレビ1 のようなテーブルを、group_idでグループ化し、idの大きい順に並べた以下のようなデータ id group_id name 5 3 テレビ1 4 2 カメラ3 1 1 冷蔵庫1 を取得しようとして悩んでおります。 SELECT MAX(id) AS max_id, id, group_id, name FROM table GROUP BY group_id ORDER BY max_id DESC というクエリですと max_id id group_id name 5 5 3 テレビ1 4 x 2 y 1 1 1 冷蔵庫1 という結果が得られますが、xとyところが、期待するx=4、y=カメラ3とならないケースがあります。 いくつかのテーブルで試しましたが、期待する結果になるものとならないものがありました。 例えばこれを自己結合することも考えたのですが、WHERE句にASで命名した「max_id」が含まれると「max_idが不明」というエラーが出ます。 MySQLのバージョンは4.0.xでして、サブクエリーが使えません。 このような状況で、何か方法がございましたらご教授のほどお願い申し上げます。 「期待する結果がクエリ1回で得られない」ということを知れるだけでも構いません。 どうぞよろしくお願いいたします。

    • ベストアンサー
    • MySQL