web-dev-qa-db-de.com

Paginierung mit MySQL LIMIT, OFFSET

Ich habe einen Code, der Daten begrenzt, um nur 4 Elemente pro Seite anzuzeigen. Die Kolumne, die ich verwende, umfasst etwa 20 bis 30 Elemente, daher muss ich diese über die Seiten verteilen. 

Auf der ersten Seite habe ich:

    $result = mysqli_query($con,"SELECT * FROM menuitem LIMIT 4");
{
  echo "<tr>";
  echo "<td align='center'><img src=\"" . $row['picturepath'] . "\" /></td>";
  echo "<td align='center'>" . $row['name'] . "</td> <td align='center'> <input type='button' value='More Info'; onclick=\"window.location='more_info.php?';\"> </td>";
  echo "<td align='center'>" . $row['price'] . "</td> <td align='center'> <input type='button' value='Add to Order' onclick=''> </td>";
  echo "</tr>";
 }
echo "</table>";

mysqli_close($con);

    ?> 

    <table width="1024" align="center" >
        <tr height="50"></tr>
            <tr>
                <td width="80%" align="right">
                    <a href="itempage2.php">NEXT</a>
                </td>
                <td width="20%" align="right">
                    <a href="">MAIN MENU</a>
                </td>
            </tr>
    </table>

Sie werden am unteren Rand der Seite feststellen, dass mein Ankertag in der zweiten Seite "itempage2.php" aufgeführt ist. Auf Artikelseite 2 habe ich denselben Code, außer dass meine select-Anweisung den Versatz von 4 aufführt.

$result = mysqli_query($con,"SELECT * FROM menuitem LIMIT 4 offset 4");

Dies funktioniert auf diese Weise, wenn eine bestimmte Anzahl von Elementen in meiner Datenbank vorhanden ist. Aber es ist nicht so gut. Ich muss nur dann eine neue Seite erstellen, wenn mehr Elemente vorhanden sind, die nicht so fest codiert sind wie jetzt. 

Wie kann ich mehrere Seiten erstellen, ohne jede neue Seite und keinen Versatz hart codieren zu müssen?

26
ValleyDigital

Zunächst einmal, haben Sie kein separates Server-Skript für jede Seite, das ist einfach Wahnsinn. Die meisten Anwendungen implementieren die Paginierung über die Verwendung eines Paginierungsparameters in der URL. So etwas wie:

http://yoursite.com/itempage.php?page=2

Sie können die angeforderte Seitennummer über $_GET['page'] aufrufen.

Dies macht Ihre SQL-Formulierung sehr einfach:

// determine page number from $_GET
$page = 1;
if(!empty($_GET['page'])) {
    $page = filter_input(INPUT_GET, 'page', FILTER_VALIDATE_INT);
    if(false === $page) {
        $page = 1;
    }
}

// set the number of items to display per page
$items_per_page = 4;

// build query
$offset = ($page - 1) * $items_per_page;
$sql = "SELECT * FROM menuitem LIMIT " . $offset . "," . $items_per_page;

Wenn zum Beispiel die Eingabe hier page=2 wäre, mit 4 Zeilen pro Seite wäre Ihre Abfrage "

SELECT * FROM menuitem LIMIT 4,4

Das ist also das Grundproblem der Paginierung. Sie haben nun die zusätzliche Anforderung, dass Sie die Gesamtzahl der Seiten verstehen möchten (damit Sie bestimmen können, ob "NEXT PAGE" angezeigt wird oder ob Sie den direkten Zugriff auf Seite X über einen Link zulassen möchten).

Dazu müssen Sie die Anzahl der Zeilen in der Tabelle verstehen.

Sie können dies einfach mit einem DB-Aufruf tun, bevor Sie versuchen, Ihren tatsächlichen begrenzten Datensatz zurückzugeben (ich sage VOR, da Sie offensichtlich bestätigen möchten, dass die angeforderte Seite vorhanden ist).

Das ist eigentlich ganz einfach:

$sql = "SELECT your_primary_key_field FROM menuitem";
$result = mysqli_query($con, $sql);
if(false === $result) {
   throw new Exception('Query failed with: ' . mysqli_error());
} else {
   $row_count = mysqli_num_rows($result);
   // free the result set as you don't need it anymore
   mysqli_free_result($result);
}

$page_count = 0;
if (0 === $row_count) {  
    // maybe show some error since there is nothing in your table
} else {
   // determine page_count
   $page_count = (int)ceil($row_count / $items_per_page);
   // double check that request page is in range
   if($page > $page_count) {
        // error to user, maybe set page to 1
        $page = 1;
   }
}

// make your LIMIT query here as shown above


// later when outputting page, you can simply work with $page and $page_count to output links
// for example
for ($i = 1; $i <= $page_count; $i++) {
   if ($i === $page) { // this is current page
       echo 'Page ' . $i . '<br>';
   } else { // show link to other page   
       echo '<a href="/menuitem.php?page=' . $i . '">Page ' . $i . '</a><br>';
   }
}
77
Mike Brant

Verwenden Sie .. LIMIT :pageSize OFFSET :pageStart

Dabei ist :pageStart an den Seitenindex (d. H. 0 für die erste Seite) * number_of_items_per_pages (z. B. 4) und :pageSize an number_of_items_per_pages gebunden.

Um nach "hat mehr Seiten" zu suchen, verwenden Sie entweder SQL_CALC_FOUND_ROWS oder verwenden Sie .. LIMIT :pageSize OFFSET :pageStart + 1 und ermitteln Sie einen letzten Datensatz (pageSize + 1). Es ist unnötig zu erwähnen, dass für Seiten mit einem Index> 0 eine vorherige Seite vorhanden ist.

Wenn der Seitenindexwert in die URL eingebettet ist (z. B. in den Links "vorherige Seite" und "nächste Seite"), kann er über den entsprechenden $_GET-Eintrag abgerufen werden.

4
user2864740

Wenn Sie es einfach halten möchten, probieren Sie es aus.

$page_number = mysqli_escape_string($con, $_GET['page']);
$count_per_page = 20;
$next_offset = $page_number * $count_per_page;
$cat =mysqli_query($con, "SELECT * FROM categories LIMIT $count_per_page OFFSET $next_offset");
while ($row = mysqli_fetch_array($cat))
        $count = $row[0];

Der Rest liegt bei Ihnen. Wenn Sie ein Ergebnis von zwei Tabellen haben, schlagen Sie einen anderen Ansatz vor. 

3

Ein Dutzend Seiten ist bei der Verwendung von OFFSET keine große Sache. Wenn Sie jedoch Hunderte von Seiten haben, werden Sie feststellen, dass OFFSET für die Leistung schlecht ist. Dies liegt daran, dass alle übersprungenen Zeilen jedes Mal gelesen werden müssen.

Es ist besser, sich an zu erinnern, wo Sie aufgehört haben.

0
Rick James