Pull to refresh

Выбираем предыдущую и следующую запись зная id

Reading time3 min
Views20K
Столкнулся недавно с задачей показа кнопок [ВПЕРЕД] [НАЗАД] на странице просмотра. Но сложность задачи в том, что сортировка может быть по произвольному полю таблицы.

Постановка задачи:

CREATE TABLE `contacts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name_prefix` varchar(50) DEFAULT NULL,
`name` varchar(100) DEFAULT NULL,
`infix` varchar(100) DEFAULT NULL,
`surname` varchar(100) NOT NULL,
`primary_email` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

Для наглядности объясню где это все работает:
есть две страницы, работающие с этой таблицей:
— index, на ней отображаются все записи из таблицы contacts, есть фильтр и есть сортировка по столбцам
— view, просмотр текущей записи из таблицы contacts. На это странице есть кнопки [ВПЕРЕД] [НАЗАД], с учетом фильтра и сортировки заданной на странице index;
Трудность возникла в этих двух кнопках.

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

Если бы была сортировка по id — было бы все понятно, с фиксированной сортировкой вопрос тоже вроде бы решен http://habrahabr.ru/blogs/mysql/85945/

Для простоты и лакончиности покажу решение используя PHP.
Решение:
/* Определяем условия поиска и условия сортировки.*/
$sqlConditions = " WHERE name ='test' ";
$sqlOrder   = " ORDER BY name, surname";
$curId     = 33; //ID текущей записи

/*Формируем основной запрос, который возвращает порядковый номер записи в отсортированном и отфильрованном наборе, и id записи*/
$sql = "SELECT rownumb,id FROM (
          SELECT
          @rownumb := @rownumb+1 AS rownumb,  
          `Contact`.`id` FROM `contacts` AS `Contact`          
          ,(SELECT @rownumb := 0) al
          $sqlConditions $sqlOrder
          ) AS src "
;

/*Получем порядковый номер текущей записи в выборке */          
$rowNumber = $this->query($sql." WHERE src.id = $curId");

/*Обрабатываем результат запроса */
if (!empty($rowNumber[0]['src']['rownumb'])) {
  $rowNumber = $rowNumber[0]['src']['rownumb'];
} else{
  return false;
}

if ($rowNumber > 1) {/* Если $rowNumber > 1 значит есть как минимум предыдущая запись (текущая не в начале)*/
  /*Выбираем предыдущую и последующую записи относительно текущей по rownumb*/
  $res = $this->query($sql." WHERE id <> $curId LIMIT ".($rowNumber - 2)." ,2");  
  /* Первая запись будет prevId*/
  if(!empty($res[0]['src']['id'])){
    $result['prevId'] = $res[0]['src']['id'];  
  }
  /*Если вторая запись существует то она будет NextId либо текущая запись последняя в наборе*/
  if(!empty($res[1]['src']['id'])){
    $result['nextId'] = $res[1]['src']['id'];  
  }        
} else { /* Если $rowNumber == 1 значит есть текущая запись стоит в начале набора данных и есть только следующая запись*/
  /* Выбираем последующую запись относительно текущей*/
  $res = $this->query($sql." WHERE rownumb > $rowNumber LIMIT 1");  
  /*Она и будет NextId*/
  if(!empty($res[0]['src']['id'])){
    $result['nextId'] = $res[0]['src']['id'];  
  }
}


* This source code was highlighted with Source Code Highlighter.


Ну вот собственно и все. Если у кого есть более элегантное решение WELCOME!
Tags:
Hubs:
Total votes 25: ↑14 and ↓11+3
Comments39

Articles