Взять id следующей и предыдущей записи

trent

Developer
Взять id следующей и предыдущей записи

есть таблица:

test
---------
id int(10),
category_id int(10),
number double (9,5),
created timestamp(14),
primary key id


select * from test where category_id = x order by number desc, created

делаю из нее выборку 10 записей c limit получаю список все нормально
теперь вопрос: переходим на эту запись и берем данные из test по id, какие есть варианты это реализовать, price может быть одинаков

на данный момент придумал такую схему

делаю insert select в другую таблицу при вставке сортирую по price
test2
-----------
category_id int(10),
position int(10) auto_increment,
test_id int(10),
primary key (category_id,position)


список беру таким образом
[sql]select t.* from from test2 t1, test t where category_id =x order by t1.position limit x,y[/sql]

а саму запись таким образом

[sql]select t.*,t2.test_id as prev_id, t3.test_id as next_id from test2 t1, test t left join test2 t2 on (t1.potiton = t2.position -1) left join test2 t3 on (t1.potiton=t3.position +1) where t.id= t1.test_id and t1.category_id =x and t1.test_id = x limit 3[/sql]

какие у вас будут предложения? :)
может я заблуждаюсь и подготавливать данные по крону в другую таблицу не надо, а можно сделать более простым способом? :)
 

Falc

Новичок
trent
Как вариант упрощения можно просто добавить в первую таблицу поле potiton и пересчитывать его по крону.
 

Макс

Старожил PHPClub
озвучу свои идеи (с trent-ом уже обсуждал):
запрос
[sql]select COUNT(*) from test
where category_id = x AND number >= $number AND created < $created[/sql] вернет кол-во записей, стоящих при заданной сортировке перед нашей записью. То есть получаем позицию нашего элемента в отсортированной выборке.

Тогда запрос :
[sql]select * from test where category_id = x order by number desc, created LIMIT $position-1, 1[/sql] вернет нам предыдущую запись

[sql]select * from test where category_id = x order by number desc, created LIMIT $position+1, 1[/sql] вернет нам следущую запись

ЗЫ
где-нибудь мог ошибиться со знаком, где-то возможно надо добавить плюс/минус единицу, но если идея ясна, эти мелочи можно экспериментально найти.
 

chira

Новичок
вариант:
значение id в примере для которого берём предыдущую и следующую запись = 93
Код:
mysql> select * from d;
+------------+---------------------+------+
| dt         | dtime               | id   |
+------------+---------------------+------+
| 1990-10-01 | NULL                | NULL |
| 2000-01-01 | NULL                | NULL |
| 2003-06-19 | NULL                | NULL |
| 0000-00-00 | NULL                | NULL |
| 0000-00-01 | NULL                | NULL |
| 2001-01-01 | NULL                | NULL |
| 1966-09-01 | NULL                | NULL |
| 1669-04-23 | 2003-06-19 19:30:16 | NULL |
| 1990-01-02 | 2003-06-19 19:30:49 | NULL |
| 1993-03-18 | NULL                | NULL |
| 1965-03-21 | NULL                | NULL |
| 1996-07-23 | NULL                | NULL |
| 1957-06-17 | NULL                | NULL |
| 1970-05-29 | NULL                | NULL |
| 1967-05-23 | NULL                | NULL |
| 2003-03-02 | 2003-06-19 19:31:39 | NULL |
| 2003-01-15 | 2003-06-19 19:31:27 | NULL |
| 2003-08-02 | 2003-08-02 12:22:11 | NULL |
| 2003-08-13 | NULL                | 1268 |
| 2003-08-13 | NULL                | 1269 |
| 2003-08-13 | NULL                | 1270 |
| 2003-08-13 | NULL                | 1271 |
| 1999-04-19 | NULL                |  102 |
| 1999-03-15 | NULL                |   94 |
| 1999-02-22 | NULL                |   93 |
| 1999-02-15 | NULL                |  101 |
+------------+---------------------+------+
26 rows in set (0.00 sec)

mysql> set @prev:=0;
Query OK, 0 rows affected (0.00 sec)

mysql> create temporary table dd as select if(@prev=93,id,if(id=93,@prev,0)) indc,@prev:=id from d order by dt desc;
Query OK, 26 rows affected (0.01 sec)
Records: 26  Duplicates: 0  Warnings: 0

mysql> select * from dd;
+------+-----------+
| indc | @prev:=id |
+------+-----------+
|    0 |      1268 |
|    0 |      1269 |
|    0 |      1270 |
|    0 |      1271 |
|    0 |      NULL |
|    0 |      NULL |
|    0 |      NULL |
|    0 |      NULL |
|    0 |      NULL |
|    0 |      NULL |
|    0 |       102 |
|    0 |        94 |
|   94 |        93 |
|  101 |       101 |
|    0 |      NULL |
|    0 |      NULL |
|    0 |      NULL |
|    0 |      NULL |
|    0 |      NULL |
|    0 |      NULL |
|    0 |      NULL |
|    0 |      NULL |
|    0 |      NULL |
|    0 |      NULL |
|    0 |      NULL |
|    0 |      NULL |
+------+-----------+
26 rows in set (0.00 sec)

mysql> select d.id, d.dt from d LEFT JOIN dd ON d.id = dd.indc AND dd.indc > 0 WHERE dd.indc IS NOT NULL OR (dd.indc IS
NULL AND d.id = 93);
+------+------------+
| id   | dt         |
+------+------------+
|   94 | 1999-03-15 |
|   93 | 1999-02-22 |
|  101 | 1999-02-15 |
+------+------------+
3 rows in set (0.00 sec)

mysql>
для самого первого и последнего id будет выведено 2 записи ...
 

Фанат

oncle terrible
Команда форума
а что - вариант с созданием временной таблицы всерёз рассматривается?
 

chira

Новичок
вариант Макс не плохой ...
для выборки можно использовать один селект, подправив немного в лимите
Код:
SELECT *
FROM test
WHERE category_id = x
ORDER BY number DESC , created
LIMIT $position - 2, 3
 

trent

Developer
[sql]SELECT COUNT( * )
FROM test
WHERE category_id = x AND number >= $number AND created < $created[/sql]

вот только одна проблема, получаются не очень хорошие ссылки, так как надо передавать все три параметра или даже 4: id записи, id категории, number и created
или делать предварительный get по id
и опять же number может смениться, если человек долго не обновлял список, то в итоге получит не совсем актуальные данные..
 

chira

Новичок
trent
тогда посмотри мой вариант ...
или придётся делать дополнительный селект для определения number & created полей
 
Сверху