Comment obtenir le prochain / précédent record en MySQL?

dire que j'ai des enregistrements avec des ID 3,4,7,9 et je veux pouvoir aller de l'un à l'autre par la navigation via les liens suivants/précédents. Le problème est que je ne sais pas comment récupérer un enregistrement avec un identifiant supérieur le plus proche.

donc quand j'ai un enregistrement avec ID 4, je dois pouvoir récupérer le prochain enregistrement existant, qui serait 7. La requête ressemblerait probablement à quelque chose comme

SELECT * FROM foo WHERE id = 4 OFFSET 1

Comment puis-je récupérer suivant/précédent record sans extraction l'ensemble des résultats et itération manuelle?

J'utilise MySQL 5.

106
demandé sur Jordan 2009-09-19 01:01:05

20 réponses

suivant:

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

précédent:

select * from foo where id = (select max(id) from foo where id < 4)
204
répondu longneck 2012-07-10 10:53:09

en plus de solution de cemkalyoncu :

enregistrement suivant:

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

précédent record:

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

edit: depuis cette réponse a été d'obtenir quelques notes positives ces derniers temps, je veux vraiment souligner le commentaire que j'ai fait plus tôt au sujet de comprendre qu'un colum de la clé primaire n'est pas destiné comme une colonne pour trier par, parce que MySQL ne garantie que des valeurs plus élevées, auto incrémentées, sont nécessairement ajoutées à un moment ultérieur.

si vous ne vous souciez pas de cela, et avez simplement besoin de l'enregistrement avec un plus haut (ou plus bas) id alors cela suffira. Ne l'utilisez simplement pas comme un moyen de déterminer si un enregistrement est réellement ajouté plus tard (ou plus tôt). Au lieu de cela, envisagez d'utiliser une colonne datetime pour trier par, par exemple.

123
répondu Decent Dabbler 2017-05-23 12:34:41

toutes les solutions ci-dessus nécessitent deux appels de base de données. Le code sql ci-dessous combine deux instructions sql en une seule.

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)
      )    
49
répondu sudip 2013-04-13 21:58:12
SELECT * FROM foo WHERE id>4 ORDER BY id LIMIT 1
15
répondu Cem Kalyoncu 2009-09-18 21:26:37

j'essayais de faire quelque chose de similaire, mais j'avais besoin des résultats Classés par date car je ne peux pas me fier au champ ID comme colonne sortable. Voici la solution que j'ai trouvé.

nous trouvons d'Abord l'index de l'enregistrement souhaité dans la table, quand il est trié comme nous voulons:

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;

alors décrémentez le résultat par 2 Mettez-le dans la déclaration limite. Par exemple, le ci-dessus retourné 21 pour moi donc je cours:

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

vous donne votre enregistrement principal ainsi que les enregistrements suivants et précédents étant donné votre ordre indiqué.

j'ai essayé de le faire comme un simple appel de base de données, mais je n'ai pas pu obtenir l'instruction LIMIT pour prendre une variable comme un de ses paramètres.

9
répondu Dan 2012-10-30 10:05:03

essayez cet exemple.

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; 

Note: Si valeur n'est pas trouvé, alors il sera de retour null .

Dans l'exemple ci-dessus, précédente la valeur sera Raja et suivante la valeur sera nulle parce qu'il n'y a pas de valeur suivante.

5
répondu Ranga Reddy 2015-05-07 05:07:14

ligne suivante

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

ligne précédente

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

ligne d'échantillon suivante

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

ligne d'échantillon précédente

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
4
répondu IDALICIUS 2013-11-17 23:02:55

en utilisant L'approche de @Dan, vous pouvez créer des jointures. Il suffit d'utiliser une variable @différente pour chaque requête secondaire.

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)
4
répondu Eduardo Moralles 2018-04-25 13:14:03

J'ai eu le même problème que Dan, donc j'ai utilisé sa réponse et l'ai améliorée.

sélectionnez D'abord l'index des lignes, rien de différent ici.

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;

utilisez maintenant deux requêtes distinctes. Par exemple, si l'index des lignes est 21, la requête pour sélectionner l'enregistrement suivant sera:

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

pour sélectionner l'enregistrement précédent, utilisez cette requête:

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

gardez à l'esprit que pour la première rangée (l'indice de rangée est 1), la limite passera à -1 et vous obtiendrez une erreur MySQL. Vous pouvez utiliser une instruction if-pour empêcher cela. Il suffit de ne pas sélectionner quoi que ce soit, car il n'y a pas d'enregistrement précédent de toute façon. Dans le cas du dernier enregistrement, il y aura la ligne suivante et à cet effet il n'y aura aucun résultat.

gardez également à l'esprit que si vous utilisez DESC pour la commande, au lieu de ASC, vos requêtes pour sélectionner les lignes suivantes et précédentes sont toujours les mêmes, mais commutés.

3
répondu magnetronnie 2013-12-15 15:51:38

c'est la solution universelle pour des conditions avec des résultats plus semblables.

<?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
?>
2
répondu asdf2017 2016-11-17 01:13:50

Comment obtenir l'enregistrement suivant / précédent dans MySQL & PHP?

Mon exemple est d'obtenir l'id seulement

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;
  }
}
1
répondu Purvesh Tejani 2015-08-19 04:18:29

ici, nous avons un moyen de récupérer les enregistrements précédents et suivants en utilisant une seule requête MySQL. Où 5 est l'id de l'enregistrement actuel.

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) )
1
répondu Jaskaran Singh 2018-05-01 11:22:10

il y a une autre astuce que vous pouvez utiliser pour afficher les colonnes des lignes précédentes, en utilisant n'importe quel ordre que vous voulez, en utilisant une variable similaire à l'astuce @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

apparemment, les colonnes select sont évaluées dans l'ordre, donc cela va d'abord sélectionner les variables sauvegardées, puis mettre à jour les variables à la nouvelle rangée (les sélectionner dans le processus).

NB: Je ne suis pas sûr que ce soit un comportement défini, mais je l'ai utilisé et cela fonctionne.

0
répondu Willem M. 2015-01-07 14:49:52

Si vous voulez nourrir plus d'un id à votre requête et obtenir next_id pour tous...

Assigner cur_id dans votre champ de sélection, puis de le nourrir à la sous-requête next_id à l'intérieur de sélectionner un champ. Et puis sélectionnez juste next_id .

utilisant la réponse de 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;
0
répondu Romeno 2015-05-23 11:24:02
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
0
répondu Piotr Kos 2016-02-02 23:44:38

si vous avez une colonne index, dites id, vous pouvez retourner l'id précédent et le suivant dans une requête sql. Remplacer :id avec votre valeur

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
0
répondu user3820597 2017-05-05 06:41:34

optimiser L'approche @Don pour n'utiliser qu'une seule requête

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

modifier le numéro D'identification de L'article courant comme

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
0
répondu Zeeshan Anjum 2017-09-18 09:57:38

Ma solution pour obtenir le prochain et les aperçus d'enregistrement aussi pour revenir au premier disque si je suis par le dernier et vice versa

je ne suis pas à l'aide de l'id, je suis en utilisant le titre pour nice url

j'utilise 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;
    }     
}
-1
répondu toiglicher 2017-05-18 03:00:04

sélectionner le top 1 * de foo où id > 4 ordre par id asc

-2
répondu Gratzy 2009-09-18 21:03:00

je pense que pour avoir la ligne réelle suivante ou précédente dans la table SQL nous avons besoin de la valeur réelle avec égale, (< ou >) retourner plus d'une si vous avez besoin de changer la position de la ligne dans une table de commande.

nous avons besoin de la valeur $position pour rechercher la ligne neighbours Dans mon tableau j'ai créé une colonne 'position'

et Requête SQL pour obtenir la ligne nécessaire est:

pour le suivant:

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

pour la précédente:

 SELECT * 
 FROM my_table 
 WHERE id = (SELECT (id) 
             FROM my_table 
             WHERE `position` = ($position-1)) 
 LIMIT 1
-2
répondu Roussos 2015-07-14 14:44:34