web-dev-qa-db-de.com

Wie bekomme ich einen nächsten/vorherigen Datensatz in MySQL?

Angenommen, ich habe Datensätze mit IDs 3, 4, 7, 9 und möchte durch Navigieren über nächste/vorherige Links von einem zum anderen wechseln können. Das Problem ist, dass ich nicht weiß, wie man einen Datensatz mit der nächst höheren ID abruft.

Wenn ich also einen Datensatz mit der ID 4 habe, muss ich in der Lage sein, den nächsten vorhandenen Datensatz abzurufen. Dies wäre 7. Die Abfrage würde wahrscheinlich so aussehen

SELECT * FROM foo WHERE id = 4 OFFSET 1

Wie kann ich den nächsten/vorherigen Datensatz abrufen, ohne die gesamte Ergebnismenge abzurufen und manuell zu iterieren?

Ich verwende MySQL 5.

115
Jakub Arnold

nächster:

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

bisherige:

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

Zusätzlich zu cemkalyoncu's Lösung:

nächster Datensatz:

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

bisherigen Rekord:

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

edit: Da diese Antwort in letzter Zeit einige positive Bewertungen erhalten hat, möchte ich wirklich den Kommentar, den ich gemacht habe betonen, der besagt, dass eine Primärschlüssel-Spalte nicht als Spalte zum Sortieren gedacht ist. Da MySQL nicht garantiert, dass höhere, automatisch inkrementierte Werte zu einem späteren Zeitpunkt unbedingt hinzugefügt werden.

Wenn Sie sich nicht darum kümmern und einfach den Datensatz mit einer höheren (oder niedrigeren) id benötigen, reicht dies aus. Verwenden Sie dies nicht als Mittel, um festzustellen, ob ein Datensatz tatsächlich (oder früher) hinzugefügt wird. Erwägen Sie stattdessen die Verwendung einer datetime-Spalte, um beispielsweise nach zu sortieren.

132
Decent Dabbler

Alle oben genannten Lösungen erfordern zwei Datenbankaufrufe. Der folgende SQL-Code kombiniert zwei SQL-Anweisungen in einer.

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)
      )    
53
sudip
SELECT * FROM foo WHERE id>4 ORDER BY id LIMIT 1
19
Cem Kalyoncu

Ich habe versucht, etwas Ähnliches zu tun, brauchte aber die Ergebnisse nach Datum geordnet, da ich mich nicht auf das Feld ID als sortierbare Spalte verlassen kann. Hier ist die Lösung, die ich gefunden habe.

Zuerst ermitteln wir den Index des gewünschten Datensatzes in der Tabelle, wenn er nach Wunsch sortiert ist:

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

Verringern Sie dann das Ergebnis um 2 und setzen Sie es in die Limit-Anweisung. Zum Beispiel hat das oben genannte 21 für mich zurückgegeben, also renne ich:

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

Gibt Ihnen Ihren Primärdatensatz zusammen mit dem nächsten und den vorherigen Datensätzen in der angegebenen Reihenfolge.

Ich habe versucht, es als einen einzelnen Datenbankaufruf auszuführen, konnte die LIMIT-Anweisung jedoch nicht dazu bringen, eine Variable als einen ihrer Parameter zu verwenden.

11
Dan

Versuchen Sie es mit diesem Beispiel. 

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; 

Hinweis: Wenn value nicht gefunden wird, wird null zurückgegeben.

Im obigen Beispiel ist Previous value Raja und Next Value ist null , da kein nächster Wert vorhanden ist.

7
Ranga Reddy

Mit dem Ansatz von @Dan können Sie JOINs erstellen. Verwenden Sie einfach eine andere @ -Variable für jede Unterabfrage.

SELECT current_row.row, current_row.id, previous_row.row, previous_row.id
FROM (
  SELECT @rownum:[email protected]+1 row, a.* 
  FROM articles a, (SELECT @rownum:=0) r
  ORDER BY date, id
) as current_row
LEFT JOIN (
  SELECT @rownum2:[email protected]+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

Nächste Reihe

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

Vorherige Zeile

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

probe nächste Zeile

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

beispiel vorherige Zeile

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
5
IDALICIUS

Ich hatte das gleiche Problem wie Dan, also nutzte ich seine Antwort und verbesserte sie.

Wählen Sie zuerst den Zeilenindex aus, hier nichts anderes.

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

Verwenden Sie jetzt zwei separate Abfragen. Wenn der Zeilenindex beispielsweise 21 ist, lautet die Abfrage zum Auswählen des nächsten Datensatzes:

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

Um den vorherigen Datensatz auszuwählen, verwenden Sie diese Abfrage:

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

Beachten Sie, dass für die erste Zeile (Zeilenindex 1) der Grenzwert -1 ist und Sie einen MySQL-Fehler erhalten. Sie können eine if-Anweisung verwenden, um dies zu verhindern. Wählen Sie einfach nichts aus, da es ohnehin keinen vorherigen Datensatz gibt. Im Falle des letzten Datensatzes gibt es die nächste Zeile und daher kein Ergebnis.

Denken Sie auch daran, dass Sie, wenn Sie DESC für die Bestellung verwenden, anstelle von ASC Abfragen zur Auswahl der nächsten und der vorherigen Zeilen immer noch gleich sind, jedoch umgestellt werden.

4
magnetronnie

Dies ist eine universelle Lösung für Bedingungen mit mehr gleichen Ergebnissen.

<?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
?>
3
asdf2017

Wie bekomme ich den nächsten/vorherigen Datensatz in MySQL & PHP?

Mein Beispiel ist, nur die ID zu erhalten

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;
  }
}
2
Purvesh Tejani

Hier haben wir eine Möglichkeit, vorherige und nächste Datensätze mithilfe einer einzigen MySQL-Abfrage abzurufen .__, wobei 5 die ID des aktuellen Datensatzes ist.

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) )
2
Jaskaran Singh

Optimieren des @ Don-Ansatzes, um nur eine Abfrage zu verwenden 

SELECT * from (
  SELECT 
     @rownum:[email protected]+1 row,
     CASE a.id WHEN 'CurrentArticleID' THEN @currentrow:[email protected] 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

Ändern Sie CurrentArticleID mit der aktuellen Artikel-ID wie 

SELECT * from (
  SELECT 
     @rownum:[email protected]+1 row,
     CASE a.id WHEN '100' THEN @currentrow:[email protected] 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
2
Zeeshan Anjum

Wenn Sie mehr als eine idin Ihre Abfrage einspeisen möchten, erhalten Sie next_id für alle ...

Weisen Sie cur_id in Ihrem Auswahlfeld zu, und führen Sie es dann einer Unterabfrage zu, die next_id im Auswahlfeld abruft. Und dann einfach next_id auswählen.

Longneck answer verwenden, um next_id zu berechnen:

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;
1
Romeno

Wenn Sie über eine Indexspalte verfügen, z. B. eine ID, können Sie die vorherige und die nächste ID in einer SQL-Anforderung zurückgeben. Ersetzen Sie: ID durch Ihren Wert

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
1
Patrice Flao

Es gibt noch einen weiteren Trick, mit dem Sie Spalten aus vorherigen Zeilen in beliebiger Reihenfolge anzeigen können, indem Sie eine Variable verwenden, die dem @ row-Trick ähnelt:

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

Offensichtlich werden die Auswahlspalten der Reihe nach ausgewertet, daher werden zuerst die gespeicherten Variablen ausgewählt und dann die Variablen in der neuen Zeile aktualisiert (indem sie im Prozess ausgewählt werden).

NB: Ich bin nicht sicher, ob dies ein definiertes Verhalten ist, aber ich habe es verwendet und es funktioniert.

1
Willem M.
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
1
Piotr Kos

Meine Lösung, um die nächste Aufnahme und die Vorschaubilder zu bekommen Auch um wieder auf die erste Platte zu kommen, wenn ich bei der letzten bin und umgekehrt

Ich benutze nicht die ID, die ich für Nice URLs benutze

Ich verwende 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;
    }     
}
0
toiglicher

Hier ist meine Antwort. Ich nehme eine Idee von ' Decent Dabbler ' und füge den Teil hinzu, der überprüft, ob id zwischen min (id) und max (id) liegt. Hier ist der Teil zum Erstellen meiner Tabelle.

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

);

Im nächsten Schritt erstellen Sie eine gespeicherte Prozedur, die für das Abrufen der vorherigen ID verantwortlich ist.

    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

Die erste Methode ist gut, wenn die Indizes sortiert sind, aber nicht. Wenn Sie beispielsweise über Indizes verfügen: 1, 2, 7, und Sie müssen Index 2 auf diese Art und Weise erhalten, um einen anderen Ansatz zu verwenden. 

    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
0
Dennis