SQL - найти следующую и предыдущую строки по заданному предложению WHERE - PullRequest
9 голосов
/ 14 марта 2009

У меня есть таблица MySQL с именем bb_posts, используемая форумом bbPress. В нем есть поле автоинкремента topid_id и другое поле topic_poster.

Я пытаюсь написать функцию, которая находит «следующее сообщение того же автора». Так, например, скажем, пользователь находится на определенной странице, которая отображает тему 123. Если вы выполняете запрос SQL:

SELECT *
FROM `bb_topics`
WHERE `topic_poster` = 5
ORDER BY `topic_id` ASC

Это может вернуть следующие строки:

topic_id    topic_poster
6           5
50          5
123         5
199         5
2039        5

Я хотел бы написать SQL-запрос, который возвращает эти две строки:

topic_id    topic_poster
50          5
199         5

Это будет строка PRIOR для строки с topic_id, равной 123, и строка ПОСЛЕ этой строки.

Если это слишком сложно сделать в одном запросе, то, безусловно, можно разбить его на два запроса ...

Я бы хотел избежать выполнения всего SQL-запроса («SELECT * FROM bb_topics WHERE topic_poster = 5») и циклического просмотра результатов, поскольку набор результатов иногда огромен.

Возможно ли это? : -)

Ответы [ 4 ]

14 голосов
/ 14 марта 2009

Следующий:

SELECT * FROM `bb_topics` 
      WHERE `topic_id` = 
      (select min(`topic_id`) FROM `bb_topics` where `topic_id` > 123
         and `topic_poster` = 5)

Предыдущий:

SELECT * FROM `bb_topics` 
      WHERE `topic_id` = 
      (select max(`topic_id`) FROM `bb_topics` where `topic_id` < 123
         and `topic_poster` = 5)

Оба:

SELECT * FROM `bb_topics` 
      WHERE `topic_id` = 
      (select min(`topic_id`) FROM `bb_topics` where `topic_id` > 123
                     and `topic_poster` = 5)
      or `topic_id` = 
      (select max(`topic_id`) FROM `bb_topics` where `topic_id` < 123
                        and `topic_poster` = 5)
2 голосов
/ 14 марта 2009

Посмотрите и на этот старый вопрос .

Я предполагаю, что UNION с LIMIT 1 работает лучше, чем агрегаты в моем ответе.

0 голосов
/ 14 марта 2009

Вот тонкий, но эффективный способ сделать это, и он работает даже на старых версиях MySQL, которые не поддерживают подзапросы -

SELECT *    
FROM bb_topics AS bb1    
LEFT JOIN bb_topics AS bb2    
    ON bb1.topic_poster = bb2.topic_poster    
    AND bb2.topic_id > bb1.topic_id    
LEFT JOIN bb_topics AS bb3  
    ON bb1.topic_poster = bb3.topic_poster    
    AND bb3.topic_id > bb1.topic_id    
    AND bb3.topic_id < bb2.topic_id  
WHERE bb1.topic_poster = 5  
    AND bb3.topic_id IS NULL  

Получается следующий соседний пост. Я могу заполнить симметричные пункты для следующего предыдущего поста, если это не очевидно.

РЕДАКТИРОВАТЬ - незначительное исправление alii.

0 голосов
/ 14 марта 2009

ПРИМЕЧАНИЕ: Перед голосованием, пожалуйста, прочитайте комментарий и первую версию вопроса; -)

По определению данные в таблице СУБД не упорядочены . Это означает, что при выполнении запроса, если вы не укажете предложение ORDER BY, порядок может отличаться от одного запроса к другому. Кроме того, вы должны учитывать, что следующий запрос будет (или, по крайней мере, может) возвращать другой заказ .

Предположим, что другой пользователь в базе данных вставляет новую запись, и СУБД рассматривает возможность поместить ее между рассматриваемыми строками. Либо администратор баз данных перемещает таблицу на другую в режиме онлайн (например, в Oracle это возможно), в этом случае данные могут быть изменены по любому вопросу.

Для вашего вопроса вы должны создать своего рода кэш результатов запроса , чтобы определить предыдущие и следующие строки в запросах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...