选择下一个项目

时间:2013-12-21 13:02:39

标签: php mysql sql

我有一张这样的桌子:
table

并且我想在某个playerID之后选择下一行,其中state = 1并且如果在第一行开始播放器ID之后它找不到任何内容

预期结果:

playerID=8 => playerID 13
playerID=15 => playerID 8

现在我正在使用子查询和第二次查询,如果结果为null:

function getTargetID($killerID)
{
    $result= $this->db->fetchSingle("
        SELECT playerID FROM targets WHERE state=1 AND 
        ID>(SELECT ID FROM targets WHERE playerID=%u)
        ORDER BY state DESC,ID LIMIT 1",$killerID);
    if(!$result)
    {
        $result= $this->db->fetchSingle("
            SELECT playerID FROM targets WHERE state=1 AND 
            ID>0 ORDER BY state DESC,ID LIMIT 1");
    }
    return $result;
}

但我认为这段代码非常丑陋且未经过优化

4 个答案:

答案 0 :(得分:1)

SELECT playerID FROM targets
WHERE state=1 
  AND ID > (SELECT ID FROM targets 
            WHERE playerID=8)
ORDER BY ID ASC
LIMIT 1

答案 1 :(得分:1)

当然,这可以在一个查询中完成:

SELECT Origin.id,
       COALESCE(MIN(CASE WHEN Targets.id > Origin.id 
                         THEN Targets.playerId END), -- "after" 
                MIN(CASE WHEN Targets.id < Origin.id 
                         THEN Targets.playerId END)  -- "before"
                ) as nextPlayer
FROM Targets 
JOIN (SELECT id, playerId 
      FROM Targets
      WHERE playerId = %playerId) Origin      
  ON Origin.playerId <> Targets.playerId
WHERE state = 1
GROUP BY Origin.id

genuine SQL Fiddle example!
如果你得到一个空值,那就意味着没有一个有效的选择(“没人在这里,弹出!”)。

请注意,您的要求主要是扫描整个表/索引。虽然窗口函数LAG() / MIN()和一个好的优化器可能会有所帮助,但我不确定我是否有一个很好的方法可以在任何 db中避免这种情况。哦,这个版本将安全地处理表中给定playerId的多个实例。

除此之外,使用“桌子的顺序”是什么?这没有任何保证,并且显式创建了SQL来忽略这些事情(出于性能原因而被破坏,但概念就是这种情况)。


编辑:

根据下一个顺序playerId的要求,这是我之前提出的一个版本:

SELECT COALESCE(MIN(CASE WHEN playerId > %playerId 
                         THEN playerId END), -- "after" 
                MIN(CASE WHEN playerId < %playerId 
                         THEN playerId END)  -- "before"
                ) as nextPlayer
FROM Targets 
WHERE state = 1

(和working fiddle

答案 2 :(得分:1)

我建议使用嵌套选择:

select t.*,
       coalesce((select playerID
                 from targets t2
                 where t2.state = t.state and
                       t2.id > t.id
                 order by t2.id
                 limit 1
                ),
                (select PlayerId from targets t2 where t2.state = t.state order by id limit 1)
               ) as nextPlayerId
from targets t;

您应该在targets(state, id, PlayerId)上建立索引。该索引应该将子查询减少为索引查找 - 关于解析此查询的最快方法。

答案 3 :(得分:0)

SELECT 
    * 
FROM mytable 
WHERE id > (
            SELECT 
                ID 
            FROM mytable 
            WHERE player_id = 8 
)
AND state = 1
ORDER BY ID ASC
LIMIT 1 

SQL Fiddle Demo

或者

SELECT
  MIN(id),
  player_id,
  state
FROM targets
WHERE state = 1
    and id > (SELECT
                ID
              FROM targets
              WHERE player_id = 8)

SQL Fiddle Demo