web-dev-qa-db-fra.com

Pagination avec MySQL LIMIT, OFFSET

J'ai un code qui limite les données pour afficher seulement 4 éléments par page. La colonne que j'utilise contient environ 20 à 30 éléments. Je dois donc les répartir sur plusieurs pages. 

Sur la première page, j'ai:

    $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>

Vous remarquerez vers le bas de la page que ma balise d'ancrage dans la liste répertorie la deuxième page, "itempage2.php". Dans la page 2 de l’item, j’ai le même code, sauf que mon instruction select indique le décalage de 4.

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

Cela fonctionne de cette façon lorsqu'il y a un nombre prédéterminé d'éléments dans ma base de données. Mais ce n'est pas si bon. J'ai besoin de créer une nouvelle page uniquement s'il y a plus d'éléments, et non pas codés en dur comme c'est le cas maintenant. 

Comment puis-je créer plusieurs pages sans avoir à coder en dur chaque nouvelle page, et offset?

26
ValleyDigital

Tout d’abord, n’avez pas de script de serveur distinct pour chaque page, c’est de la folie. La plupart des applications implémentent la pagination via l'utilisation d'un paramètre de pagination dans l'URL. Quelque chose comme:

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

Vous pouvez accéder au numéro de page demandé via $_GET['page'].

Cela rend votre formulation SQL très facile:

// 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;

Ainsi, par exemple, si la saisie ici était page=2, avec 4 lignes par page, votre requête serait "

SELECT * FROM menuitem LIMIT 4,4

Voilà donc le problème fondamental de la pagination. Vous devez maintenant comprendre le nombre total de pages (pour pouvoir déterminer si "PAGE SUIVANTE" doit être affiché ou si vous souhaitez autoriser un accès direct à la page X via un lien).

Pour ce faire, vous devez comprendre le nombre de lignes de la table.

Vous pouvez simplement faire cela avec un appel à une base de données avant d'essayer de renvoyer votre jeu d'enregistrements limité réel (je dis AVANT, car vous voulez évidemment valider que la page demandée existe).

C'est en fait assez simple:

$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

Utilisez .. LIMIT :pageSize OFFSET :pageStart

:pageStart est lié à the_page_index (0. pour la première page) * number_of_items_per_pages (par exemple 4) et :pageSize est lié à number_of_items_per_pages.

Pour détecter "a plus de pages", utilisez SQL_CALC_FOUND_ROWS ou utilisez .. LIMIT :pageSize OFFSET :pageStart + 1 et détectez un dernier enregistrement manquant (pageSize + 1). Inutile de dire que pour les pages avec un index> 0, il existe une page précédente.

Si la valeur d'index de page est incorporée à l'URL (par exemple, dans les liens "page précédente" et "page suivante"), vous pouvez l'obtenir via l'élément $_GET approprié.

4
user2864740

Si vous voulez garder les choses simples, allez-y et essayez ceci.

$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];

Le reste est à vous ... Si vous avez un résultat provenant de deux tableaux, je vous suggère d'essayer une approche différente. 

3
Peter Gruppelaar

Une douzaine de pages n’est pas un gros problème lorsque vous utilisez OFFSET. Mais lorsque vous avez des centaines de pages, vous constaterez que OFFSET est mauvais pour la performance. En effet, toutes les lignes ignorées doivent être lues à chaque fois.

Il est préférable de vous rappeler où vous vous êtes arrêté .

0
Rick James