Вы можете использовать один запрос, но вам нужно ОБЪЕДИНИТЬ между двумя наборами, чтобы объединить результаты
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', если разрешены дубликаты).