MySQL запрос - до и после строки пользовательских упорядоченных результатов - PullRequest
2 голосов
/ 26 января 2011

Я видел другие подобные вопросы в StackOverflow, но все они основаны на идентификаторе автоинкремента, но у меня его нет.

У меня есть запрос вроде:

  SELECT field_a, 
         field_b 
    from table
   where field_m = '100' 
     and field_n = '200'
order by field_x

Это приводит к этому

field_a    field_b
-------------------
john       12     
marty      7     
peter      2     
carl       9     
mark       11     
bob        10     
neil       1     
louis      14     

Итак, я хочу завершить исходный запрос и с помощью ONE QUERY взять запись ДО и ПОСЛЕ одного из них ... скажем, «Карл», но важно, что в каждом случае разные, я имею в виду, другие времена потребуются до и после "боб" ...

Итак, скажем, "carl" ... Мне нужно создать ТОЛЬКО SQL-запрос, в котором я использую описанный порядок по field_x и взять строки до и после, когда field_a = 'carl'

Ответы [ 2 ]

1 голос
/ 26 января 2011

Это было бы довольно тяжело для больших таблиц, но вы можете использовать ранжирование и объединиться дважды, чтобы получить предыдущую и следующую запись, а затем просто использовать место для ее фильтрации.

SET @rank_prev = 0;
SET @rank_cur = 0; 
SET @rank_next = 0;
SELECT
    prev.field_a as prev_a,
    prev.field_b as prev_b,
    next.field_a as next_a,
    next.field_b as next_b
FROM
 (  
  SELECT
      @rank_cur:=@rank_cur+1 AS rank,
      field_a, 
      field_b  
  FROM dd
  WHERE field_m = '100' 
    AND field_n = '200'
  ORDER BY field_x
 ) as cur
INNER JOIN
 (
  SELECT
      @rank_prev:=@rank_prev+1 AS rank,
      field_a, 
      field_b  
  FROM dd
  WHERE field_m = '100' 
    AND field_n = '200'
  ORDER BY field_x
 ) as prev
 ON prev.rank + 1 = cur.rank
INNER JOIN
 (
  SELECT
      @rank_next:=@rank_next+1 AS rank,
      field_a, 
      field_b  
  FROM dd
  WHERE field_m = '100' 
    AND field_n = '200'
  ORDER BY field_x
 ) as next
 ON cur.rank+1 = next.rank
 WHERE cur.field_a = 'carl';

Работает на MySQL

0 голосов
/ 26 января 2011

Вы можете использовать один запрос, но вам нужно ОБЪЕДИНИТЬ между двумя наборами, чтобы объединить результаты

SELECT * FROM
(
SELECT b.*
from tbl a
inner join tbl b on
      b.field_m = '100'
  and b.field_n = '200'
where a.field_m = '100'
  and a.field_n = '200'
  and a.field_a = 'carl'
  and b.field_x <= a.field_x  # comes before a sorted on x
order by b.field_x DESC
limit 2
) A
UNION
SELECT * FROM
(
SELECT b.*
from tbl a
inner join tbl b on
      b.field_m = '100'
  and b.field_n = '200'
where a.field_m = '100'
  and a.field_n = '200'
  and a.field_a = 'carl'
  and b.field_x >= a.field_x  # comes after a sorted on x
order by b.field_x ASC
limit 2
) B

Примечание: Сюда входит и сам «carl».UNION позаботится об удалении второго 'carl'.

Performance - индекс должен быть создан как минимум на (field_m, field_n), лучше, если он равен (field_m, field_n, field_x), чтобы этот запрос выполнялся разумно.Пока field_m + field_n сокращает таблицу до размера, производительность составляет

(size after filter m/n) x (size after filter m/n)  // triangular
x2

Способ, которым это работает , заключается в том, что он пересекает набор к самому себе, где точка привязана к "carl "и b сохраняют только те строки, которые позиционно расположены до (набор 1) или после (набор 2).Если вы упорядочите их правильно, то взяв LIMIT 2, вы включите 'carl' и еще одного (если это не также 'carl', если разрешены дубликаты).

...