WHAT'S NEW?
Loading...
ラベル ランキング の投稿を表示しています。 すべての投稿を表示
ラベル ランキング の投稿を表示しています。 すべての投稿を表示
実に7ヶ月ぶりにこのシリーズを再開することにした。
前回なにをやったのか、というと、率直にリンク先を見ていただければ良いと思う。
SQLでちゃんとしたランキングを作る【1/3】

つまりseletしてorderしてlimitするだけでは正しいランキングがでない、ということだ。

幸いにも識者の方から色々アドバイスをもらい、俺なりに試してみた結果を書いてみようと思う。

まず、識者、つまりDupont氏から引用してもらったSQLがこれだ。
select (select count(distinct b.sal) from emp b where b.sal <= a.sal) as rnk, a.sal from emp a
個人的にSQLは改行を入れて見やすくする主義なので、以下のように適宜変更してみる。
select
  (
    select
      count(distinct b.sal)
    from
      emp b
    where
      b.sal <= a.sal
  ) as rnk, a.sal
from
  emp a
コードというものは、改行やインデントで適切にフォーマットしておくべきだと思っている。

しかしSQLに関してはまだ拘りはないので、だいたいいつもフォーマットは違う。統一しておいたほうが良い場合と、統一しないでも良い場合があるのだが、SQLは俺にとってまだ後者の方だ。

SQLを使ってランキングを表示させるなんてことをやったことがある人もいるだろう。
たとえばメンバー(訪問者という意味でのユーザは2種類あって、登録ユーザをメンバー、非登録ユーザをビジターと呼んでいる)にポイント属性が設定されていて、そのポイントを毎日集計する、そしてその結果、上位から10件取り出せば、ランキングデータが1位までそろう、というものだ。

ちょっと待て!!
それたぶん、インチキ!!

MySQLであれば、
select * from histories
order by point desc
limit 10
と吐けば、pointが高い順に上から10件の結果を得ることはできるが、ただ10件取得するだけで、ランキングとして正しいかどうかは別問題だ。

というのも、同位の場合があるからだ。

ある2人のユーザが同ポイントだった場合、内部ではpointではなくidや登録日などの順で順位が変わってしまうということになる。正直これは不本意だ。

というわけで、いくつかパターンを考えてみる。以下は、3位が二人いる場合を例にとってみた。

順位シーケンシャル 順位スキップ
10件まで 1 2 3 3 4 5 6 7 8 9 1 2 3 3 5 6 7 8 9 10
10位まで 1 2 3 3 4 5 6 7 8 9 10 1 2 3 3 5 6 7 8 9 10

これだと、右下の「順位スキップ」+「10位まで」がよさそうだが、実はそうじゃない。
さらに以下は、3位が二人、8位が3人いる場合になる。