mysql按关系分组排名

时间:2016-07-22 15:12:43

标签: mysql mysql-variables

所以我在这样的表中有数据:

SELECT g1.admission_no
 , g1.total
 , g1.stream_id
 , COUNT(*) AS rn
 FROM ranktest   AS g1
   JOIN ranktest   AS g2
   ON (g2.total, g2.admission_no) >= (g1.total, g1.admission_no)
   AND g1.stream_id = g2.stream_id
   GROUP BY g1.admission_no
    , g1.stream_id
    , g1.total
   ORDER BY g1.stream_id
    , total ;

如何根据总数对每个组的ID进行排名,并在出现平局时给出相同的排名?

我在下面尝试过这个解决方案,但它没有处理关系。

id        total   group_id rank
1897      738      1        1
2489      716      2        1
2325      715      3        1
1788      702      2        2 
1707      699      3        2
2400      688      3        3
2668      682      2        3
1373      666      1        2
1494      666      1        2
1564      660      1        3
2699      659      1        4
1307      648      4        1
1720      645      4        2
2176      644      1        4
1454      644      4        3
2385      639      3        4
1001      634      2        4
2099      634      4        4
1006      632      1        5
2587      630      3        5
1955      624      3        6
1827      624      4        5
2505      623      4        6
2062      621      3        6
1003      618      1        6
2286      615      4        7 
2722      609      4        8 

预期

var datos_contrato = ["1","2"];
$.post("<?=Zend_Registry::get('base_action')?>insert.php", {
            pos: a_pos, cre: a_cre, cep: a_cep, 'ddc': datos_contrato
......

3 个答案:

答案 0 :(得分:2)

如果原始订单不是很重要,您可以从:

开始

http://sqlfiddle.com/#!9/a15a2/10

SELECT
    ranktest.*,
    IF(@rank IS NULL,@rank:=1, IF(@prev!=group_id,@rank:=1,@rank:=@rank+1) ) rank,
     @prev:=group_id
FROM ranktest
ORDER BY group_id, total

但请记住,从性能角度来看,这不是一个非常有效的查询。

答案 1 :(得分:1)

来自名为User-Defined Variables的MySQL手册页:

  

在以下声明中,您   可能会认为MySQL会首先评估@a然后做一个   第二个任务:

SELECT @a, @a:=@a+1, ...;
     

但是,涉及用户的表达式的评估顺序   变量未定义。

这就是为什么这么少的人正确而安全地写下这些答案的原因。对象不是要达到预期的结果,而是要在真实世界的环境中一次又一次地使用最佳实践和保证结果。

如果您没有阅读Obligatory Doc并执行它,则无法保证您的结果。没有懒惰的方法可以做到这一点,甚至不应该打扰:p

select id,total,group_id,rank 
from 
(   select id,total,group_id, 
    @rn:=if(  group_id!=@curr_grp, greatest(@grp_rank:=1,0), 
        if(total=@prev_grp_total,@grp_rank,greatest(@grp_rank:=@grp_rank+1,0) ) ) as rank, 
    @curr_grp:=group_id, 
    @prev_grp_total:=total 
    from trans01 
    cross join (select @grp_rank:=0,@curr_grp:=0,@prev_grp_total:=-1) xParams 
    order by group_id,total desc 
)xDerived; 

+------+-------+----------+------+
| id   | total | group_id | rank |
+------+-------+----------+------+
| 1897 |   738 |        1 | 1    |
| 1373 |   666 |        1 | 2    |
| 1494 |   666 |        1 | 2    |
| 1564 |   660 |        1 | 3    |
| 2699 |   659 |        1 | 4    |
| 2176 |   644 |        1 | 5    |
| 1006 |   632 |        1 | 6    |
| 1003 |   618 |        1 | 7    |

| 2489 |   716 |        2 | 1    |
| 1788 |   702 |        2 | 2    |
| 2668 |   682 |        2 | 3    |
| 1001 |   634 |        2 | 4    |

| 2325 |   715 |        3 | 1    |
| 1707 |   699 |        3 | 2    |
| 2400 |   688 |        3 | 3    |
| 2385 |   639 |        3 | 4    |
| 2587 |   630 |        3 | 5    |
| 1955 |   624 |        3 | 6    |
| 2062 |   621 |        3 | 7    |

| 1307 |   648 |        4 | 1    |
| 1720 |   645 |        4 | 2    |
| 1454 |   644 |        4 | 3    |
| 2099 |   634 |        4 | 4    |
| 1827 |   624 |        4 | 5    |
| 2505 |   623 |        4 | 6    |
| 2286 |   615 |        4 | 7    |
| 2722 |   609 |        4 | 8    |
+------+-------+----------+------+

答案 2 :(得分:0)

谷歌搜索后得到了这个答案。不确定它是最好的,但它适用于我的情况:

 SELECT id, group_id, total,
   @std:=CASE WHEN @grp <> group_id THEN  concat(left(@grp:=group_id, 0), 1) ELSE if(@prev=total,@std,@std+1) END AS rn,@prev:=total 
FROM
    (SELECT @std:= -1) s,
 (SELECT @grp:= -1,@prev:=null) c,
 (SELECT *
  FROM table
  ORDER BY group_id, total desc
) s