按多个动态条件排序SQL结果

时间:2016-03-12 11:52:23

标签: php mysql

我有一个查询,根据某些条件选择一些用户(即,在drivers_standings表的单元格中具有相同的值,以点表示),并根据它们的最低值({{ 1}})在另一个表(position)中。

results

但是,我的情况是两者具有相同的值且最低$superquer = " SELECT SD.driver, MIN(R.position) AS highest_position FROM standings_drivers SD INNER JOIN results R ON R.driverId = SD.driver WHERE R.compId='$compId' AND R.eventID>='$firstevent' AND R.eventID<='$lastevent' AND R.eventSession NOT IN ('T', 'P', 'Q', 'Q1', 'Q2', 'QA') AND SD.season = '42' AND SD.points='$points_pos' GROUP BY SD.driver ORDER BY MIN(R.position)"; 。我想要实现的是找到一种方法让它看下一个最低值,然后是下一个,然后是下一个,直到找到差异。

例如,我现在拥有的是:

position

但是,我也有这样的案例:

User A: 56 points, best result 9th
User B: 56 points, best result 6th
User C: 56 points, best result 7th

---> User B, User C, User A

在这种情况下,用户A和用户C将按其第二好结果排序,如果是:

User A: 56 points, best result 4th
User B: 56 points, best result 6th
User C: 56 points, best result 4th

我们会这样订购:

User A: 56 points, best result 4th, second best 5th
User B: 56 points, best result 6th, second best 9th
User C: 56 points, best result 4th, second best 4th

注意:第二个最佳结果可能与最佳结果相同 - 所有用户都参与了多个活动,并且没有什么能阻止他们在多个活动中达到相同的排名。

当然,因为我使用的是sql MIN函数,所以我不知道如何对它进行编码,以便它能找到下一个最佳结果,并且仅适用于那些最佳结果相同的人。

3 个答案:

答案 0 :(得分:1)

一种可能性是使用单独的子查询来查询每个用户的第一个和第二个最佳结果。

select SD.driver,  

    coalesce((select R.Position from results R 
     where R.driverId = SD.driver and R.compId='$compId' 
     and R.eventID>='$firstevent' and R.eventID<='$lastevent' 
     and R.eventSession not in ('T', 'P', 'Q', 'Q1', 'Q2', 'QA') 
     order by R.Position 
     limit 1 offset 0), 999999) as best_position,

    coalesce((select R2.Position from results R2 
     where R2.driverId = SD.driver and R2.compId='$compId' 
     and R2.eventID>='$firstevent' and R2.eventID<='$lastevent' 
     and R2.eventSession not in ('T', 'P', 'Q', 'Q1', 'Q2', 'QA') 
     order by R2.Position 
     limit 1 offset 1), 999999) as second_best_position

from standings_drivers SD 
where SD.season = '42' and SD.points='$points_pos' 
order by best_position, second_best_position;

未经测试,因此可能包含一些语法错误。

我们使用两个子查询来查找每个驱动程序的所有结果,按位置对结果进行排序,然后使用limit子句分别仅获取第一行或第二行。

我们对子查询的返回结果使用coalesce(),这样当子查询返回NULL(这意味着用户没有进一步的结果)时,该位置将返回为999999。

通过这种方式,我们可以获得一组驱动程序,这些驱动程序的最佳和次佳结果为单独的列,并且可以通过这些列轻松排序。

答案 1 :(得分:1)

以下是使用group_concat的解决方案。它以每个驱动程序的升序连接位置值,将每个位置格式化为3位数。然后它会在排序时向其附加一个z,这样结果较少的驱动程序最终会达到平局:

select   driverId, score
from
          (select   driverId, 
                    group_concat(
                        lpad(position, 3, '0')
                        order by position) AS score
          from      results
          group by  driverId) as drivers
order by  score || 'z'

fiddle

这个解决方案在精度方面没有实际限制,因为它是基于字符串的:一千个位置的系列没有问题。只需确保每个位置使用的位数(3)设置正确。我认为这不是关于数百名司机的比赛,我猜3应该是正确的。

使用一个子查询(如上所述)执行此操作将比每个种族(会话)的子查询具有更高的性能。

另请注意,在MySql中,FROM子句中连接的最大表数为limited to 61,这意味着纯粹的基于连接的解决方案只能在运行之前查看那么多事件(会话)成为例外。

答案 2 :(得分:0)

管理以这种方式为最大数量的事件进行查询循环:

        $orderbit = "ORDER BY position1";
        $superquer = "SELECT SD.driver, 

             COALESCE((SELECT R.position FROM results R 
             WHERE R.driverId = SD.driver AND R.compId='$compId' 
             AND R.eventID>='$firstevent' AND R.eventID<='$lastevent' 
             AND R.eventSession NOT IN ('T', 'P', 'Q', 'Q1', 'Q2', 'QA') 
             ORDER BY R.position 
             LIMIT 1 OFFSET 0), 999) AS position1";

             $i=2;
             $max = $totalsessions+1;

            while ($i<$max) {

                $superquer .= ", COALESCE((SELECT R$i.position FROM results R$i 
             WHERE R$i.driverId = SD.driver AND R$i.compId='$compId' 
             AND R$i.eventID>='$firstevent' AND R$i.eventID<='$lastevent' 
             AND R$i.eventSession NOT IN ('T', 'P', 'Q', 'Q1', 'Q2', 'QA') 
             ORDER BY R$i.position 
             LIMIT 1 OFFSET $i), 999) AS position$i";

                $orderbit .= ", position$i";

                $i++;
            }                

        $superquer .= " FROM standings_drivers SD 
        WHERE SD.season = '42' AND SD.points='$points_pos'";

        $orderbit .= ";";

        $querytotl = "$superquer $orderbit";

这是@ NineBerry代码的演变,所以感谢您的所有贡献!