Постраничный вывод данных MySQL



Простая и универсальная функция для постраничного вывода данных из таблиц MySQL.

Чтобы рассмотреть данный пример, нам понадобится простенькая таблица, например, "articles" в базе данных, например, "datadb". Структура таблицы данных пусть будет такая:

idarticle
1Статья один
2Два статья
3Три
4Четвертая
5Статья № 5

Для постраничного вывода нам понадобится общее число записей в таблице. Здесь есть простор для творчества: можно организовать сложный запрос в базу данных, который выдаст нам сразу общее число записей и сами данные с такого по такое. Но, имхо, будет проще и правильнее сделать два запроса. Итак, приступим:

Создадим файл "a.php":

<?
// Будем выводить по 2 записи на листе:
$number = 2;
// Читаем сдвиг из GET-массива:
$offset = isset($_GET['offset']) ? (int)$_GET['offset'] : 0;
// Коннект до базы данных
$link = mysql_connect('localhost', $dbuser, $dbpass);
if (!$link) die('Не могу соединиться с базой данных');
// Выбираем базу данных
mysql_select_db('datadb', $link);
// Выполняем запрос 'посчитать число записей'
$result = mysql_query("SELECT COUNT(*) FROM `articles`", $link);
// Теперь в переменной $total общее число записей
$total = mysql_result($result, 0);
$menu = getMenuofPages($total, $number, $offset);
?>

Теперь нужно написать саму функцию getMenuofPages, получающую на входе общее число записей, число записей для вывода на странице и сдвиг (т. е. начиная с какой записи показывать). Например вот так:

<?
function getMenuofPages($total, $number, $offset) {
   // Подфункция определяет есть ли уже в текущем url get-данные
   // и дописывает соответственно нужный offset:
   function getGoodUrl($url, $cur) {
      if ($_SERVER['QUERY_STRING'] == "") {
         return $url."?offset=".$cur;
      }else {
         if (substr_count($_SERVER['QUERY_STRING'], "offset=") > 0) {
            $url = preg_replace("/offset=\d+/i", "offset=".$cur, $url);
            return $url;
         }else {
            return $url."&offset=".$cur;
         }
      }
   }
   // Если общее число меньше числа записей, которые мы должны вывести на
   // странице, то ничего не делаем:
   if ($total <= $number) {
      return;
   }
   $url = $_SERVER['REQUEST_URI'];
   $int = intval($total / $number); // Целая часть от деления
   $rest = $total % $number; // Остаток от деления
   $menu = "";
   // Сначала перебираем целые части
   for ($i = 0; $i < $int; $i++) {
      $cur = $i * $number;
      if ($cur == $offset) { // Проверка на текущую страницу
         $menu .= " | ".($cur + 1)."-".($cur + $number);
      }else {
         $menu .= " | <a href=\"".getGoodUrl($url, $cur)."\">".
                  ($cur + 1)."-".($cur + $number)."</a>";
      }
   }
   // Потом остаток (если есть)
   if ($rest > 0) {
      $cur += $number;
      if ($cur == $offset) { // Проверка на текущую страницу
         if ($rest == 1) {
            $menu .= " | ".($cur + 1)." |";
         }else {
            $menu .= " | ".($cur + 1)."-".($cur + $rest)." |";
         }
      }else {
         if ($rest == 1) {
            $menu .= " | <a href=\"".getGoodUrl($url, $cur)."\">".($cur + 1)."</a> |";
         }else {
            $menu .= " | <a href=\"".getGoodUrl($url, $cur)."\">".
                     ($cur + 1)."-".($cur + $rest)."</a> |";
         }
      }
   }else {
      $menu .= " |";
   }
   return $menu;
}
?>

Меню готово, теперь осталось читать из базы данные в соответствии с offset и number. Так:

<?
// Читаем из базы $number записей начиная с $offset:
$result = mysql_query("SELECT * FROM `articles` LIMIT $offset, $number", $link);
// Распечатываем результат:
echo $menu;
while ($row = mysql_fetch_array($result)) {
   echo '<div>'.$row['id'].' : '.$row['article'].'</div>';
}
?>

Если вы все сделали правильно, у вас должно получиться примерно это:

Постраничный вывод php+mysql

Естественно можно функцию getMenuofPages усовершенствовать, например, подавая ей в аргументах шаблон для вывода ссылок. Можно также дописать ссылки вида "назад" и "вперед". Дерзайте!

Комментарии

У меня почему-то не выводятся ссылки, только данные из базы

Понятно почему - потому что я опечатался, вернее недопечатался :) Вобщем нужно еще распечатать переменную $menu перед циклом while. Исправил в тексте статьи.

Этот подход генерит страшный загруз БД. И чем больше данных -тем больше COUNT(*) будет жрать ресурсов. Решение в лоб заключается в использовании limit $offset, $countItems , но этот подход тоже оставляет желать лучшего при более чем 1к записей. Как правило при значительных объёмах отказываются от постраничной навигации в пользу "вперёд-назад" кнопок или, если постраничка таки нужна, используют решения по типу yahoo, google и подобных (слайдинг количества страниц)

Отправить комментарий

Содержание этого поля является приватным и не предназначено к показу.
  • Разрешаю теги: <a> <em> <strong> <pre> <ul> <ol> <li>
  • Строки и параграфы переносятся автоматически.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.

Подробнее о форматировании

Image CAPTCHA
Регистр символов учитывается.