MySQLでの効率的なランキング作成の方法

このQ&Aのポイント
  • MySQLでのランキングを作成するための効率の良いSQLの方法を教えてください。
  • テーブル名hogeの中から、dateが1週間以内でかつflgがtrueのデータをkbn毎に5つ取得し、同じ点数の場合は日付が古い順に並べてn位のフォーマットで順位を表示します。
  • 取得した結果はkbn、順位、name、scoreの4つのカラムで表示してください。もし5つのレコードが存在しなかった場合は、順位のみを表示し他のカラムはnullとします。
回答を見る
  • ベストアンサー

MySQLでのランキングを作成するSQL

ランキングを作成する、効率の良いSQLを教えて下さい。 MySQLで、以下の状態です。 テーブル名: hoge カラム: id,kbn,name,score,flg,date id…自動 kbn…1~4 name…string score…int flg…bool date…年月日 (1)dateが1週間以内のデータのみ (2)flgがtrueのデータのみ (3)kbn毎に、5レコード取得 (4)順位は、点数が重複している場合は同一の順位をつけSQLで生成しn位のフォーマット (5)6レコード以降に同一スコアのデータがある場合は日付が古い順 (6)scoreは、n点のフォーマット (7)該当データが5レコード存在しなかった場合は、順位だけをセットし他をnull 欲しい結果は、以下の状態です。 kbn,順位,name,score 1 ,1位 ,ホゲ,100点 1 ,2位 ,あい, 85点 1 ,2位 ,かき, 85点 1 ,4位 ,くけ, 70点 1 ,5位 ,さし, 65点 2 ,1位 ,すせ, 99点 2 ,1位 ,たち, 99点 2 ,3位 ,つて, 80点   ・   ・   ・ 4 ,4位 ,らり, 10点 null ,5位 ,null, null 以上、よろしくお願い致します。

  • MySQL
  • 回答数1
  • ありがとう数11

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

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

//元データ create table hoge(id int not null primary key,kbn int,name varchar(10),score int,flg tinyint,d date); insert into hoge values(1,1,'a',100,1,'2014-03-10'),(2,1,'b',90,1,'2014-03-11'),(3,1,'c',80,1,'2014-03-12'),(4,1,'d',90,1,'2014-03-13'),(5,1,'e',80,1,'2014-03-10'),(6,1,'f',80,1,'2014-03-11'),(7,2,'g',0,1,'2014-03-12'),(8,2,'h',100,0,'2014-03-13'),(9,2,'i',100,1,'2014-03-10'),(10,2,'j',100,1,'2014-03-11'),(11,2,'k',100,1,'2014-03-12'),(12,2,'l',100,1,'2014-03-13'),(13,3,'m',100,1,'2014-03-10'),(14,3,'n',100,1,'2014-03-11'); とりあえず検索条件がかぶるので一度 (1)(2)をつかってビューを作ります。 //view作成 create view v_hoge as select * from hoge where d between curdate() - interval 1 week and curdate() + interval 1 week and flg = 1; //結果 select * ,(select count(*)+1 from v_hoge as v2 where v1.kbn=v2.kbn and v1.score<v2.score) as rank1 from v_hoge as v1 where kbn in (select kbn from v_hoge group by kbn having count(*)>=5) having (select count(*)+1 from v_hoge as v2 where v1.kbn=v2.kbn and (v1.score<v2.score or v1.score=v2.score and v1.d>v2.d) ) <=5 order by kbn asc,rank1 asc; (1)は「何の」一週間以内なのか不明。たぶん今日の? また一週間とは前も先もあるので命題が中途半端 (4)と(6)のフォーマットはsql側でやらずに出力側のプログラムでやるべき (キャストや結合が無駄なため) (5)はkbnごとに日付がユニークでないと順位が決定できない (7)は意味不明 5個データがないのに5位ってどういうこと?しかもkbnまでnullじゃ何を示しているか?

RYO-88
質問者

お礼

yambejp 様 ご回答ありがとうございます。 説明が不足していたり悪かったりでしたが ほぼ、欲しかった状態でございます。 (5)は、仕様を検討してみます。 (7)は確かに意味不明でした。 サンプルデータで、そのまま確認もでき 本当に助かりました。 誠にありがとうございました。

関連するQ&A

  • SQL文作成のお願い

    前提として下記のようなテーブルがあります。 テーブル名:test フィールド: 1)id: varchar, not null 2)name: varchar 3)date: timestamp with time zone, not null このテーブルに下記のようなレコードがあります。 '00001', 'A', '2005-01-01 00:00:00' '00001', 'B', '2005-07-01 00:00:00' '00001', 'C', '2005-11-01 00:00:00' '00002', 'X', '2005-01-20 00:00:00' '00002', 'Y', '2005-07-20 00:00:00' '00002', 'Z', '2005-11-20 00:00:00' ■今やりたいこと このテーブルからidごとにdateフィールド値が最近のレコードを取得したい。 ■やってみたこと 下記SQLを発行しました。 >select id, max(date) from test group by id order by id 結果==> 00001 2005-11-01 00:00:00 00002 2005-11-20 00:00:00 実際はnameフィールドの値も取得したいのですが、group by句を使うとフィールド指定ができませんでした。 ■だめだったSQL select id, name, max(date) from test group by id order by id どのようにSQLを書けばよろしいでしょうか?

  • SQL文に関して教えてください。

    SQL文に関して教えてください。 SQLServer2005を利用し、マイクロソフトアクセスでadpを利用して構築を初めて行っています。 そこで、SQLServerのビューこのような事は可能でしょうか? (ビューをネストすれば出来るのですが、1つのSQL内で完結させたい) 色々探し、近い物はあったのですが、若干異なります。 フィールドがID1、ID2、ID3、date、txtと存在するとします。 ID1 ID2 date txt 1 1 20100801 test 2 1 20100901 Null 3 3 20100928 Null txtフィールドがNullのレコードを対象とし、dateが一番古い日付のレコード、nullのレコード数を 取り出す。結果としては以下が出れば正解です。 (グループ化が必要かと思います) ID1 ID2 date レコード数 2 1 20100901 2 やはり難しいでしょうか? 御教授願います。

  • MySQLチューニング

    同順位を考慮したランクの取得について(1~55位まで) 下記の2つのテーブルがあります。 rankingscoreinfo フィールド名 型 長さ missionid integer 4 NOT NULL name varchar 20 NOT NULL skill integer 4 NOT NULL score integer 4 NOT NULL rankinginfo フィールド名 型 長さ NOT NULL missionid integer 4 NOT NULL name varchar 20 NOT NULL kind integer 4 NOT NULL missionidとname2つのテーブルの共通フィールドです。 この二つを組み合わせて同順位を考慮したスコアランキングを作成したいです。 1位のscoreが3人同点の場合、3人のスコアランキングは1位で次の人は4位になるようにしたいです。 SQLを組んだのですがレコード数が増えるにつれてどんどんSQLが返ってくる速度が遅くなって困っています。 この二つのテーブルの最速のSQLを組みたいのですがどなたか教えて下さい。 とりあえずINDEXは考慮なしでお願いします。 参考までに私が組んだSQLは下記のものになります。 SELECT d.name FROM (SELECT *, (SELECT COUNT(a.score)+1 FROM rankingscoreinfo AS a , rankinginfo as b WHERE a.missionid=10 AND a.skill= 2 AND b.kind = 2 AND a.missionid = b.missionid AND a.name = b.name AND a.score > c.score ) AS score_rank FROM rankingscoreinfo AS c WHERE c.missionid = 10 AND c.score AND c.skill=2 ) AS d , rankinginfo as e WHERE e.missionid = 10 AND e.kind = 2 AND d.skill = 2 AND d.missionid = e.missionid AND d.name = e.name AND d.score_rank >=1 AND d.score_rank <= 55 ORDER BY score_rank

    • ベストアンサー
    • MySQL
  • MySQLで日毎の最高点を取得するSQLについて

    何時もお世話になっております。 日付ごとの最高ポイントを取得する 効率の良いMySQLでのSQLをご教授下さい。 T_DATA flg kbn point biko date ------------------------------ true 3 90 NNN 20141231 true 1 80 XXX 20150101 true 2 60 YYY 20150101 true 3 70 XXX 20150101 true 1 40 xxx 20150201 true 2 60 yyy 20150201 true 1 60 AAA 20150301 true 2 90 BBB 20150301 true 3 40 CCC 20150301 true 1 60 aaa 20150401 true 2 70 bbb 20150401 true 3 30 ccc 20150401 false 4 90 ddd 20150401 ■欲しい状態 kbn point biko date ----------------------- 2 70 bbb 20150401 2 90 BBB 20150301 2 60 yyy 20150201 1 80 XXX 20150101 (1)dateカラム毎にpointカラムが最大のデータを取得したいです。 (2)flgカラムがtrueのデータのみ取得したいです。 (3)dateカラムが降順になるよう取得したいです。 (4)dateカラムは、直近4日分取得したいです。 以上の条件で取得したく思います。 どうぞ、よろしくお願い致します。

    • ベストアンサー
    • MySQL
  • SQL文について質問があります。

    PostgreSQLのSQL文で質問があります。 kekktaテーブルの構成 ---------------------- name:varchar(64) score : int 4 day : date ---------------------- 現在kekkaテーブルには以下のレコードが格納されています。 ------------------------------- yamada| -2|2003-04-30 yamada|-16|2003-05-01 yamada| 3|2003-05-02 yamada|-23|2003-05-02 honda |-12|2003-05-10 yamada| 12|2003-05-15 yamada| -6|2003-05-20 yamada| -8|2003-06-01 ------------------------------- このレコードで 2003年5月のyamadaさんのレコードの最新日付からの scoreの合計を取得したいと考えています。 ---------------------------------- select name, sum(score) from kekka where name='yamada' and day like '2003-05%' group by name offset 0 limit 4; (このSQLはもちろんうまくいきません) ---------------------------------- <出力したい結果> name | sum(score) --------------------- yamada | -14 です。 SQLがうまくできません。 宜しくお願いいたします。

  • 3つのテーブルを結合させたSQL文について

    3つのテーブルを結合させたSQL文について作成方法を教えてください。 よろしくお願いいたします。 【テーブル構成】 テーブル名---項目名/項目名・・・です。 tblA---id/del_flg/name tblB---id/del_flg/add tblC---id/del_flg/family 各テーブルはidによりリンクされます。 tblAのdel_flgは在籍者=0 退職者=1で、一人1レコードです。 tblBでは住所管理をしています。 旧情報を残したいので、更新時には新たにdel_flg=0でレコードを作成し、既存レコードはdel_flg=1に更新します。 tblCは、既婚者のみ作成されるレコードです。 つまり、tblBとtblCは、レコードが存在しない、あるいはdel_flg=0のみ、del_flg=0とdel_flg=1が混在 のどれかのパターンになります。 【やりたいこと】 いま、これらすべてのテーブルを全部つなげて、在籍している人の情報だけ集めたいのです。 tblAからはdel_flg=0のレコードをすべて取得したうえで、tblBとtblCにdel_flg=0のレコードがあればその情報も取得したい。 【経過】 select * from (tblA inner join tblB on tblA.id = tblB.id ) inner join tblC on tblA.id = tblC.id とりあえずwhere条件をつけなくても、tblCに存在している人しか取得ができないのです。 where条件も含めて、上記条件のもと、希望するようなSQLの組み立て方をご教授ねがいたいのでよろしくお願いいたします。 できれば、早目の回答が希望です。

    • ベストアンサー
    • MySQL
  • PHP,MySQLで3つのランキング

    前提: seisekiテーブルに id(Primary), student_id(生徒ID), kamoku_id(科目ID), score, time, created のフィールドがあります。 ランキングの順位条件は、同じ科目でscoreがより高く、timeがより短く、createdがより古い方が高位となります。 同じ科目を何度でも受講できる為、student_idはユニークではありません。 前提条件から、以下3つのランキングを取得したいと考えています。 ランキング1:科目毎のランキング(同じstudent_idが1~10位独占等可) ランキング2:自分(student_id)の全受講履歴と履歴毎のランキング ランキング3:id指定時のランキング情報 各ランキングは、1SQLである必要はなく、PHPでの加工も考慮に入れております。 試行錯誤しているのですが、ORDER BY区にどうやって順位を付ければ良いのか分からず、 SELECT * FROM seiseki ORDER BY kamoku_id DESC, score DESC, time ASC, created ASC ここから進みません・・・ 何卒、よろしくお願いいたします。

    • ベストアンサー
    • MySQL
  • アンケート結果を集計するSQLを教えて下さい

    アンケート結果を集計する効率の良いシンプルなSQLを教えて下さい。 MySQLで、以下の状態です。 テーブル名:hoge カラム:id,kbn id...auto kbn...1~5 欲しい結果は、以下の状態です。 順位,kbn,count 1位,5,60ポイント 2位,3,45ポイント 2位,1,45ポイント 4位,4,30ポイント 5位,2,10ポイント ※位やポイントはプログラム側で付与するので不要です。 2位の様に同点の場合は同じ順位を表示し、3位を飛ばし順位を表示させたく思います。 どうぞ、よろしくお願い致します。

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

    テーブル情報 id start_dt end_dt --+----------+---------- 1 2014-01-07 2014-01-20 2 2014-01-08 Null 3 2014-01-09 Null 4 2014-01-10 Null 5 2014-01-11 Null を以下のSQL文の場合 select * from infomation where start_dt <= '2014/01/10' and (end_dt >= '2014/01/10' or end_dt is null) order by start_dt desc limit 3 id start_dt end_dt --+----------+---------- 4 2014-01-10 Null 3 2014-01-09 Null 2 2014-01-08 Null が取得されます。 id start_dt end_dt --+----------+---------- 4 2014-01-10 Null 3 2014-01-09 Null 1 2014-01-07 2014-01-20 の結果のように取得するSQL文をつくることは可能でしょうか? 何がしたいかというと ・start_dtが新しい順に並べる。 ・3件のレコードを取得する。 ・start_dtが'2014/01/10'より古いレコードを取得する。 ・end_dtが'2014/01/10'より新しいレコードがある場合は、Nullのレコードより優先する。 どうかお助けください。

    • ベストアンサー
    • MySQL
  • MySQLで、日付最大のレコード抽出

    MySQLをJAVAで使っています。 指定キーの中で、一番日付の大きなレコード項目全てを 取り出したいのですが、 下記SQLだと、何も抽出されません。 (今朝、ここで教えて頂いたSQL文です) 何が間違っているのでしょうか? さらに、もっと簡単なSQL文はないでしょうか? SELECT * FROM food WHERE (food_id = 1) AND (food_name = 'みかん') AND (karute_id = (SELECT MAX(date) FROM food WHERE (food_id = 1) AND (food_name = 'みかん'))) 与える検索キー項目は、food_id=1, food_name=みかん foodテーブル例 food_id  food_name   date --------------------------------- 1     みかん    2015-01-01 1     みかん    2015-02-01 1     みかん    null 1     みかん    2015-04-01 2     きんめだい  2015-01-01 2     じんたん   2015-02-01 2     コロッケ   2015-02-01

    • ベストアンサー
    • MySQL