【问题标题】:Select surrounding rows php/mysql选择周围的行 php/mysql
【发布时间】:2009-12-03 10:40:44
【问题描述】:

我想在条件匹配的行周围选择一组行,即选择一行,然后返回它之前和之后的5条记录。

根据要求提供更多信息(抱歉!)

好的,所以表格记录了比赛的单圈时间。圈数与用户相关(用户有很多圈数)。我想找到用户的最佳单圈时间,然后 x 来自唯一用户的最佳单圈数,高于和低于所需用户的最佳单圈。

这可能吗?

【问题讨论】:

  • 请发布您的查询和表结构(或示例数据)。
  • 前后行是否必须满足原始SELECT 条件,或者只是在原始表中SELECTed 行的前后?
  • 请同时说明“之前”和“之后”的确切含义(排序标准)。
  • 其他用户的单圈时间是否可能与所需用户的完全相同?如果是这样,它们应该包含在“上方”列表还是“下方”列表中,还是根本不包含?

标签: php mysql select neighbours


【解决方案1】:

这实际上只是对 PHP-Steven 答案的更正,但我没有足够的代表发表评论。

SELECT `lap_time`, `uid` 
FROM `table` t1
WHERE `lap_time` =< 120
AND NOT EXISTS (SELECT 1 FROM `table`
                 WHERE `uid` = t1.`uid` AND `lap_time` > t1.`lap_time` AND `lap_time` < 120)
ORDER BY `lap_time` DESC
LIMIT 5

SELECT `lap_time`, `uid` 
FROM `table` t1
WHERE `lap_time` > 120
AND NOT EXISTS (SELECT 1 FROM `table`
                 WHERE `uid` = t1.`uid` AND `lap_time` < t1.`lap_time` AND `lap_time` > 120)
ORDER BY `lap_time` DESC
LIMIT 5

唯一的区别是NOT EXISTS 子句用于消除同一用户的第二圈时间。否则,您将获得下一个最慢和最快的 lap_times,而不是下一个最慢/最快的唯一用户。

【讨论】:

    【解决方案2】:

    这需要相当多的黑客攻击,但它似乎对我有用。

    SELECT * FROM `lap_times` WHERE `id` IN ( SELECT * FROM ( SELECT lt1.id FROM `lap_times` lt1 WHERE lt1.time = (SELECT MIN(lt2.time) FROM `lap_times` lt2 WHERE lt2.user_id = lt1.user_id) AND lt1.time &lt= (SELECT MIN(lt3.time) FROM `lap_times` lt3 WHERE lt3.user_id = 2) AND lt1.user_id != 2 ORDER BY lt1.time ASC LIMIT 5 ) AS `tbl1` ) OR `id` = ( SELECT `id` FROM `lap_times` WHERE `user_id` = 2 ORDER BY `time` ASC LIMIT 1 ) OR `id` IN ( SELECT * FROM ( SELECT lt1.id FROM `lap_times` lt1 WHERE lt1.time = (SELECT MIN(lt2.time) FROM `lap_times` lt2 WHERE lt2.user_id = lt1.user_id) AND lt1.time >= (SELECT MIN(lt3.time) FROM `lap_times` lt3 WHERE lt3.user_id = 2) AND lt1.user_id != 2 ORDER BY lt1.time ASC LIMIT 5 ) AS `tbl2` ) ORDER BY `time` ASC;

    【讨论】:

      【解决方案3】:

      应该是这样的:

      lap_time = column with lap times (assumed to be an int or numeric)
      laps = table containing lap times
      CURRENT_LAP_TIME = the lap time in question
      

      然后

      SELECT lap_time FROM laps
      WHERE lap_time < CURRENT_LAP_TIME
      ORDER BY lap_time DESC LIMIT 5
      UNION
      SELECT lap_time FROM laps
      WHERE lap_time >= CURRENT_LAP_TIME
      ORDER BY lap_time LIMIT 6
      

      您可以将整个内容包装在另一个 SELECT 语句中,如果您希望它按特定顺序执行 ORDER BY。 (我认为有更好的方法来反转第一个 SELECT 语句,但我想不出它。)

      【讨论】:

        【解决方案4】:

        所以我假设你想按圈数排序。

        
        SELECT `lap_time`, `uid` 
        FROM `table`
        WHERE `uid` = x AND `lapnum` = y
        

        这将获得最后一圈的行数。可以说它存储为 INT 并且以秒为单位。结果是 120。

        现在可以更快地选择所有单圈时间。

        
        SELECT `lap_time`, `uid` 
        FROM `table`
        WHERE `laptime` =< 120
        GROUP BY `uid`
        ORDER BY `laptime` DESC
        LIMIT 5 
        

        最后选择所有较慢的单圈时间。

        
        SELECT `lap_time`, `uid` 
        FROM `table`
        WHERE `laptime` >= 120
        GROUP BY `uid`
        ORDER BY `laptime` ASC
        LIMIT 5 
        

        这将为您提供所需的全部 11 行!

        【讨论】:

        • 这可能会为单个用户返回多圈记录。要求是返回具有最佳单圈时间的唯一用户列表。
        • 谢谢@vincebowdren。我添加了一个 GROUP BY 来解决这个问题。
        【解决方案5】:

        鉴于数据非常稀疏,我只能提供一个非常通用的解决方案。将其视为灵感:

        SELECT
            id,
            fieldX,
            ABS(id - <id-to-select>) AS distance
        FROM
            table
        WHERE
            ABS(id - <id-to-select>) < 5
        ORDER BY
            distance DESC
        

        但是,此方法保证返回带有id = &lt;id-to-select&gt; 的行。它只是将“最近”的行返回到此 ID。

        同样,这只是作为灵感的来源。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-07-14
          • 1970-01-01
          相关资源
          最近更新 更多