2014-01-25 2 views
2

Как определить, на какой странице находится определенная запись?Определить на какой странице запись

Скажем, я отображать 5 записей на странице, используя запрос, как это:

SELECT * FROM posts ORDER BY date DESC LIMIT 0,5 
SELECT * FROM posts ORDER BY date DESC LIMIT 5,5 
SELECT * FROM posts ORDER BY date DESC LIMIT 10,5 

Образец данных:

id | name | date 
----------------------------------------------------- 
1 | a | 2013-11-07 08:19    page 1 
2 | b | 2013-12-02 12:32 
3 | c | 2013-12-14 14:11 
4 | d | 2013-12-21 09:26 
5 | e | 2013-12-22 18:52  _________ 
6 | f | 2014-01-04 11:20    page 2 
7 | g | 2014-01-07 21:09 
8 | h | 2014-01-08 13:39 
9 | i | 2014-01-08 16:41 
10 | j | 2014-01-09 07:45  _________ 
11 | k | 2014-01-14 22:05    page 3 
12 | l | 2014-01-21 17:21 

Кто-то может редактировать запись, скажем, с id = 7, или вставить новый запись (id = 13). Как определить, на какой странице находится эта запись? Причина в том, что я хочу отобразить страницу, содержащую только что отредактированную или добавленную запись.

ok Я думаю, я мог бы просто отобразить одну и ту же страницу, если запись будет отредактирована. Но проблема в том, когда запись добавляется. Список можно заказать по имени и новая запись может быть размещена в любом месте :(

Есть ли какой-то способ, которым я мог бы сделать запрос как SELECT offset WHERE id = 13 ORDER BY date LIMIT 5, который возвращает 10?

+0

Что делает запись «date»? Это ** ужасное название для столбца - это только описательный тип, а не то, что важно - содержащаяся информация. Например, если это действительно «updatedAt», я бы предположил, что страница будет «страница 1» .... (если частота обновлений слишком быстрая, в этом случае у вас проблемы с разбивкой по страницам). В противном случае вы должны заказать все страницы (на основе чего-либо), присвоить ранг (место на странице), а затем найти, какой ранг (и, следовательно, страница) указанная запись включена. Если ваш набор записей большой, это может быть дорогостоящим ... OLAP-функции/CTEs помогают, но ... –

+0

это 'createdAt', а не' updatedAt'. Я не понимаю, как помочь рангам, если мне все равно нужно получить весь набор: s – Alex

+0

Я говорю о функциях OLAP, таких как 'ROW_NUMBER()', что называется «функцией оконной обработки» (SQLite doesn ' t, похоже, имеет эту функцию). Функция присваивает добавочное число на основе указанного порядка, который затем может использоваться для возврата смещений и т. Д. Хотя, думая об этом, здесь есть другое решение ... написать ответ ... –

ответ

1

Ради этого примера, давайте предположим, что запись 7 только что был добавлен (и что может быть дублирующие имена) - первое, что вам нужно сделать, это найти, сколько записей приходят до того, что один (на основе name), таким образом:

SELECT COUNT(*) 
FROM Posts 
WHERE name <= 'g' 
     AND id < 7 

Здесь id используется как столбец «тай-брейкер», чтобы обеспечить стабильный вид. поэтому, полагая, что мы знаем значение id, тоже - учитывая, что неключевые данные могут быть дублирующими, вам необходимо эта функциональность.
В любом случае это дает нам количество строк, предшествующих этому (6). С некоторого целого деления арифметики (на основе LIMIT), теперь мы можем получить соответствующую информацию:

(int) ((6 - 1)/5) = 1 

... это для 0-индексируемой страницы, хотя (т.е. записи 1 - 5 появится на странице "0"); однако в этом случае это работает в нашу пользу. Обратите внимание, что мы должны вычесть 1 из начального счета, потому что первый равен 1, не 0 - в противном случае запись 5 появится на второй странице, а не первой.
Теперь у нас есть индекс страница, но нам нужно превратить его в индекс . Некоторые простое умножение делает это для нас:

(1 * 5) + 1 = 6 

(игнорировать, что это совпадает с кол - это совпадение в данном случае).
Это дает нам индекс первой записи на странице, значение для OFFSET.
Теперь мы можем написать запрос: (! Имейте в виду, что мы требуютid, чтобы гарантировать стабильную сортировку для данных, если мы предположим, что name может быть дубликатом)

SELECT id, name, date 
FROM Posts 
ORDER BY name, id 
LIMIT 5 OFFSET 6 

.
Это две поездки в базу данных.Удивительно, но SQLite позволяет LIMIT/значениям быть результатом подзапросов SQL (имейте в виду, что не все RDBMS позволяют им даже быть переменными хоста, что означает, что он может быть изменен только с помощью динамического SQL. Хотя по крайней мере в одном случае, у db было ROW_NUMBER(), чтобы компенсировать это ...). Однако я не смог избавиться от повторения подзапросов.

SELECT Posts.id, Posts.name, Posts.date, Pages.pageCount 
FROM Posts 
CROSS JOIN (SELECT ((COUNT(*) - 1)/5) + 1 as pageCount 
     FROM Posts 
     WHERE name <= 'g' 
      AND id < 7) Pages 
ORDER BY name 
LIMIT 5, (SELECT ((COUNT(*) - 1)/5) * 5 + 1 as entryCount 
     FROM Posts 
     WHERE name <= 'g' 
      AND id < 7); 

(и рабочий SQL Fiddle example).

Смежные вопросы