如何在MySQL中获取下一个/上一个记录?

时间:2009-09-18 21:01:05

标签: sql mysql

假设我有ID 3,4,7,9的记录,我希望能够通过下一个/上一个链接导航从一个到另一个。问题是,我不知道如何获取最近的更高ID的记录。

因此,当我有一个ID为4的记录时,我需要能够获取下一个现有记录,即7。查询可能看起来像

SELECT * FROM foo WHERE id = 4 OFFSET 1

如何在不提取整个结果集并手动迭代的情况下获取下一条/上一条记录?

我正在使用MySQL 5.

22 个答案:

答案 0 :(得分:230)

下:

select * from foo where id = (select min(id) from foo where id > 4)

前面的:

select * from foo where id = (select max(id) from foo where id < 4)

答案 1 :(得分:131)

除了cemkalyoncu's解决方案:

下一条记录:

SELECT * FROM foo WHERE id > 4 ORDER BY id LIMIT 1;

之前的记录:

SELECT * FROM foo WHERE id < 4 ORDER BY id DESC LIMIT 1;

编辑:由于这个答案最近得到了一些支持,我真的想强调comment I made之前关于理解主键列不是要排序的列因为MySQL不保证更高的自动递增值必须在以后添加。

如果您不关心这一点,只需要更高(或更低)id的记录,那么这就足够了。只是不要将其用作确定记录是否实际在以后(或更早)添加的方法。相反,请考虑使用datetime列进行排序,例如。

答案 2 :(得分:54)

以上所有解决方案都需要两次数据库调用。下面的sql代码将两个sql语句合并为一个。

select * from foo 
where ( 
        id = IFNULL((select min(id) from foo where id > 4),0) 
        or  id = IFNULL((select max(id) from foo where id < 4),0)
      )    

答案 3 :(得分:19)

SELECT * FROM foo WHERE id>4 ORDER BY id LIMIT 1

答案 4 :(得分:11)

我试图做类似的事情,但我需要按日期排序的结果,因为我不能依赖ID字段作为可排序的列。这是我提出的解决方案。

首先我们找到表中所需记录的索引,当它按照我们的要求排序时:

SELECT row
FROM 
(SELECT @rownum:=@rownum+1 row, a.* 
FROM articles a, (SELECT @rownum:=0) r
ORDER BY date, id) as article_with_rows
WHERE id = 50;

然后将结果减2,将其放入限制语句中。例如,以上为我返回21,所以我运行:

SELECT * 
FROM articles
ORDER BY date, id
LIMIT 19, 3

根据您所声明的订单,为您提供主要记录以及下一个和之前的记录。

我尝试将其作为单个数据库调用来执行,但无法获取LIMIT语句将变量作为其中一个参数。

答案 5 :(得分:7)

使用@Dan的方法,您可以创建JOIN。只需为每个子查询使用不同的@variable。

SELECT current_row.row, current_row.id, previous_row.row, previous_row.id
FROM (
  SELECT @rownum:=@rownum+1 row, a.* 
  FROM articles a, (SELECT @rownum:=0) r
  ORDER BY date, id
) as current_row
LEFT JOIN (
  SELECT @rownum2:=@rownum2+1 row, a.* 
  FROM articles a, (SELECT @rownum2:=0) r
  ORDER BY date, id
) as previous_row ON
  (current_row.id = previous_row.id) AND (current_row.row = previous_row.row - 1)

答案 6 :(得分:7)

试试这个例子。

create table student(id int, name varchar(30), age int);

insert into student values
(1 ,'Ranga', 27),
(2 ,'Reddy', 26),
(3 ,'Vasu',  50),
(5 ,'Manoj', 10),
(6 ,'Raja',  52),
(7 ,'Vinod', 27);

SELECT name,
       (SELECT name FROM student s1
        WHERE s1.id < s.id
        ORDER BY id DESC LIMIT 1) as previous_name,
       (SELECT name FROM student s2
        WHERE s2.id > s.id
        ORDER BY id ASC LIMIT 1) as next_name
FROM student s
    WHERE id = 7; 

注意:如果找不到,则会返回 null

在上面的例子中, 上一个值将 Raja 下一个值将 null ,因为没有下一个值。

答案 7 :(得分:5)

下一行

SELECT * FROM `foo` LIMIT number++ , 1

上一行

SELECT * FROM `foo` LIMIT number-- , 1

下一行示例

SELECT * FROM `foo` LIMIT 1 , 1
SELECT * FROM `foo` LIMIT 2 , 1
SELECT * FROM `foo` LIMIT 3 , 1

示例上一行

SELECT * FROM `foo` LIMIT -1 , 1
SELECT * FROM `foo` LIMIT -2 , 1
SELECT * FROM `foo` LIMIT -3 , 1

SELECT * FROM `foo` LIMIT 3 , 1
SELECT * FROM `foo` LIMIT 2 , 1
SELECT * FROM `foo` LIMIT 1 , 1

答案 8 :(得分:4)

我和Dan有同样的问题,所以我用他的答案进行了改进。

首先选择行索引,这里没什么不同。

SELECT row
FROM 
(SELECT @rownum:=@rownum+1 row, a.* 
FROM articles a, (SELECT @rownum:=0) r
ORDER BY date, id) as article_with_rows
WHERE id = 50;

现在使用两个单独的查询。例如,如果行索引为21,则选择下一条记录的查询将为:

SELECT * 
FROM articles
ORDER BY date, id
LIMIT 21, 1

要选择上一条记录,请使用此查询:

SELECT * 
FROM articles
ORDER BY date, id
LIMIT 19, 1

请记住,对于第一行(行索引为1),限制将变为-1,您将收到MySQL错误。您可以使用if语句来防止这种情况。只是不要选择任何东西,因为无论如何都没有以前的记录。在最后一条记录的情况下,将会有下一行,因此没有结果。

另请注意,如果使用DESC进行排序,而不是ASC,则查询选择下一行和前一行仍然相同,但是已切换。

答案 9 :(得分:3)

这是具有更多相同结果的条件的通用解决方案。

<?php
$your_name1_finded="somethnig searched"; //$your_name1_finded must be finded in previous select

$result = db_query("SELECT your_name1 FROM your_table WHERE your_name=your_condition ORDER BY your_name1, your_name2"); //Get all our ids

$i=0;
while($row = db_fetch_assoc($result)) { //Loop through our rows
    $i++;
    $current_row[$i]=$row['your_name1'];// field with results
    if($row['your_name1'] == $your_name1_finded) {//If we haven't hit our current row yet
        $yid=$i;
    }
}
//buttons
if ($current_row[$yid-1]) $out_button.= "<a  class='button' href='/$your_url/".$current_row[$yid-1]."'>BUTTON_PREVIOUS</a>";
if ($current_row[$yid+1]) $out_button.= "<a  class='button' href='/$your_url/".$current_row[$yid+1]."'>BUTTON_NEXT</a>";

echo $out_button;//display buttons
?>

答案 10 :(得分:2)

如何在MySQL&amp;中获得下一个/上一个记录PHP?

我的例子是只获取id

function btn_prev(){

  $id = $_POST['ids'];
  $re = mysql_query("SELECT * FROM table_name WHERE your_id < '$id'  ORDER BY your_id DESC LIMIT 1");

  if(mysql_num_rows($re) == 1)
  {
    $r = mysql_fetch_array($re);
    $ids = $r['your_id'];
    if($ids == "" || $ids == 0)
    {
        echo 0;
    }
    else
    {
        echo $ids;
    }
  }
  else
  {
    echo 0;
  }
}



function btn_next(){

  $id = $_POST['ids'];
  $re = mysql_query("SELECT * FROM table_name WHERE your_id > '$id'  ORDER BY your_id ASC LIMIT 1");

  if(mysql_num_rows($re) == 1)
  {
    $r = mysql_fetch_array($re);
    $ids = $r['your_id'];
    if($ids == "" || $ids == 0)
    {
        echo 0;
    }
    else
    {
        echo $ids;
    }
  }
  else
  {
    echo 0;
  }
}

答案 11 :(得分:2)

这里我们有一种方法可以使用单个MySQL查询来获取上一个和下一个记录。 其中5是当前记录的id。

select * from story where catagory=100 and  (
    id =(select max(id) from story where id < 5 and catagory=100 and order by created_at desc) 
    OR 
    id=(select min(id) from story where id > 5 and catagory=100 order by created_at desc) )

答案 12 :(得分:2)

优化@Don方法仅使用一个查询

SELECT * from (
  SELECT 
     @rownum:=@rownum+1 row,
     CASE a.id WHEN 'CurrentArticleID' THEN @currentrow:=@rownum ELSE NULL END as 'current_row',
     a.*  
  FROM articles a,
     (SELECT @currentrow:=0) c,  
     (SELECT @rownum:=0) r
   ORDER BY `date`, id  DESC
 ) as article_with_row
 where row > @currentrow - 2
 limit 3

使用当前文章ID更改CurrentArticleID,如

SELECT * from (
  SELECT 
     @rownum:=@rownum+1 row,
     CASE a.id WHEN '100' THEN @currentrow:=@rownum ELSE NULL END as 'current_row',
     a.*  
  FROM articles a,
     (SELECT @currentrow:=0) c,  
     (SELECT @rownum:=0) r
   ORDER BY `date`, id  DESC
 ) as article_with_row
 where row > @currentrow - 2
 limit 3

答案 13 :(得分:1)

CREATE PROCEDURE `pobierz_posty`(IN iduser bigint(20), IN size int, IN page int)
BEGIN
 DECLARE start_element int DEFAULT 0;
 SET start_element:= size * page;
 SELECT DISTINCT * FROM post WHERE id_users .... 
 ORDER BY data_postu DESC LIMIT size OFFSET start_element
END

答案 14 :(得分:1)

如果你有一个索引列,比如id,你可以在一个sql请求中返回上一个和下一个id。 用您的值替换:id

SELECT
 IFNULL((SELECT id FROM table WHERE id < :id ORDER BY id DESC LIMIT 1),0) as previous,
 IFNULL((SELECT id FROM table WHERE id > :id ORDER BY id ASC LIMIT 1),0) as next

答案 15 :(得分:1)

如果您想向您的查询提供多个id ,并为所有这些提取next_id ...

在您的选择字段中分配cur_id,然后将其提供给在查询字段中获取next_id的子查询。然后只选择next_id

使用longneck回答calc next_id

select next_id
from (
    select id as cur_id, (select min(id) from `foo` where id>cur_id) as next_id 
    from `foo` 
) as tmp
where next_id is not null;

答案 16 :(得分:1)

使用类似于@row技巧的变量,您可以使用另一个技巧来显示前一行中的列,使用您想要的任何顺序:

SELECT @prev_col_a, @prev_col_b, @prev_col_c,
   @prev_col_a := col_a AS col_a,
   @prev_col_b := col_b AS col_b,
   @prev_col_c := col_c AS col_c
FROM table, (SELECT @prev_col_a := NULL, @prev_col_b := NULL, @prev_col_c := NULL) prv
ORDER BY whatever

显然,select列按顺序进行计算,因此首先选择保存的变量,然后将变量更新为新行(在过程中选择它们)。

注意:我不确定这是定义的行为,但我已经使用过它并且有效。

答案 17 :(得分:0)

我的解决方案是获取下一张和预览记录 如果我是最后一个,那么也要回到第一个记录,反之亦然

我没有使用我正在使用标题的好网址

我正在使用Codeigniter HMVC

$id = $this->_get_id_from_url($url);

//get the next id
$next_sql = $this->_custom_query("select * from projects where id = (select min(id) from projects where id > $id)");
foreach ($next_sql->result() as $row) {
    $next_id = $row->url;
}

if (!empty($next_id)) {
    $next_id = $next_id;
} else {
    $first_id = $this->_custom_query("select * from projects where id = (SELECT MIN(id) FROM projects)");
    foreach ($first_id->result() as $row) {
        $next_id = $row->url;
    }
}

//get the prev id
$prev_sql = $this->_custom_query("select * from projects where id = (select max(id) from projects where id < $id)");
foreach ($prev_sql->result() as $row) {
    $prev_id = $row->url;
}

if (!empty($prev_id)) {
    $prev_id = $prev_id;
} else {
    $last_id = $this->_custom_query("select * from projects where id = (SELECT MAX(id) FROM projects)");
    foreach ($last_id->result() as $row) {
        $prev_id = $row->url;
    }     
}

答案 18 :(得分:0)

这是我的答案。我从“ 体面的流浪汉”中提取了一个想法,并添加了用于检查 id 是否在min(id)和max(id)之间的部分。这是创建我的表的部分。

CREATE TABLE Users (
UserID int NOT NULL auto_increment,
UserName varchar(45),
UserNameID varchar(45),
PRIMARY KEY (UserID)

);

下一步是创建一个存储过程,该过程负责获取先前的ID。

    CREATE DEFINER=`root`@`localhost` PROCEDURE `printPreviousIDbySelectedIDUser`(
IN ID int,
IN search_name varchar(45)
)
BEGIN
SELECT CONCAT(ns.UserID) AS 'Previous ID' from Users ns
 where ns.UserName=search_name AND ns.UserID IN (select min(ns.UserID) from Users ns where ns.UserID > ID 
 union select max(ns.UserID) from Users ns where  ns.UserID < ID) LIMIT 1 ;
END

如果索引已排序,但没有排序,则第一种方法很好。例如,如果您有索引:1、2、7,则需要以这种方式获得更好的索引号2,以使用另一种方法。

    CREATE DEFINER=`root`@`localhost` PROCEDURE `getPreviousUserID`(
IN ID int,
IN search_name varchar(45)
)
BEGIN
SELECT CONCAT(ns.UserID) AS 'Previous ID' from Users ns
  WHERE ns.UserName=search_name AND  ns.UserID < ID   ORDER BY ns.UserID DESC LIMIT 1;
END

答案 19 :(得分:-1)

我认为如果需要在排序表中更改行的位置,我们需要在SQL表中使用实际的下一行或前一行,并且需要使用相等的实数值,(&lt;或&gt;)返回多个行。

我们需要值$position来搜索neighbours行 在我的表格中,我创建了一个列“位置”

和获取所需行的SQL查询是:

代表下一个:

SELECT * 
FROM `my_table` 
WHERE id = (SELECT (id) 
            FROM my_table 
            WHERE position = ($position+1)) 
LIMIT 1

以前:

 SELECT * 
 FROM my_table 
 WHERE id = (SELECT (id) 
             FROM my_table 
             WHERE `position` = ($position-1)) 
 LIMIT 1

答案 20 :(得分:-1)

100%工作

SELECT * FROM `table` where table_id < 3 ORDER BY `table_id` DESC limit 1

答案 21 :(得分:-2)

从foo中选择前1 *,其中id&gt; 4 id by asc