Как получить соседние записи? - PullRequest
3 голосов
/ 01 июня 2011

Не уверен, что это возможно (или стоит сделать) в чистом SQL, но я все равно спрошу.

Допустим, у меня есть куча пронумерованных записей в моей базе данных (дополнительные пробелы для ясности):

2 3 4     10 11 12 13     55 56 57  91     106 107

Теперь, учитывая число, такое как «11», как я могу получить «10, 11, 12, 13»? все соседние записи без пробелов (все числа должны быть +/- 1 друг от друга).

Это возможно? Если да, то как?

Ответы [ 4 ]

3 голосов
/ 01 июня 2011

Это должно сработать. @target_id - ваше целевое значение (11 в данном примере).

  • Найти нижнюю границу желаемого диапазона & mdash; наибольшее значение меньше или равно вашей цели, где value-1 не существует.
  • Найти верхнюю границу желаемого диапазона & mdash; наименьшее значение больше или равно вашей цели, где value+1 не существует.
  • возвращает строки так, что нижняя граница <= x <= верхняя граница </em>.

Легко!

select *
from foo t
where t.id >= ( select max(id)
                from foo x
                where x.id <= @target_id
                  and not exists ( select *
                                   from foo x1
                                   where x1.id = x.id - 1
                                 )
              )
  and t.id <= ( select min(id)
                from foo y
                where y.id >= @target_id
                  and not exists ( select *
                                   from foo y1
                                   where y1.id = y.id + 1
                                 )
              )

Индексируйте свой столбец id / порядковый номер, и я считаю, что производительность должна быть довольно хорошей.

1 голос
/ 01 июня 2011

Не зная контекста, я не могу комментировать, стоит ли это того или нет (я бы предположил, пока не доказано обратное), но все возможно !! Сначала я пойду с псевдокодом одного метода ...

Создать хранимую процедуру, которая принимает идентификатор начальной строки, который:

Создать временную таблицу идентификаторов.
Вставить запрос выбора в эту временную таблицу из основной таблицы, соответствующей идентификатору строки.
Число только что выполненных вставок равно 0:
Вставить запрос выбора, соединяющий временную таблицу с основной таблицей
где абсолютное значение вычитания идентификатора равно
к 1, и где идентификатор еще не находится во временной таблице
Выберите результаты из временной таблицы, присоединенной к основной таблице по идентификатору.

Учитывая пример 11, первая вставка вставит # 11, цикл начнется, а вторая вставит # 10 и # 12, третья вставка только добавит # 13, а четвертая вставка вставит 0 записей, заканчивая цикл Тогда вы получите выбор из главной таблицы ID 10, 11, 12, 13.

Если бы процедура была запущена с несуществующим номером, таким как # 14, цикл никогда не запустился бы, и вы бы получили пустой набор результатов.

Как вы думаете, сможете ли вы выполнить это, или мне следует написать?

1 голос
/ 01 июня 2011

Я не могу думать ни о чем. Но если важна скорость чтения, вы можете добавить поле, представляющее «кластер». Для 2, 3 и 4 кластер будет 2. Для 10, 11, 12 и 13 кластер будет 10 и т. Д.

Недостатком является то, что вы должны обновлять кластер всякий раз, когда вы что-либо обновляете. Хорошей частью является то, что арифметика, вероятно, очень легко.

0 голосов
/ 01 июня 2011

Предполагая, что все записи различны, и мы находимся в БД, которая поддерживает управление окнами и CTE,

WITH t1 AS
( SELECT id, id-row_number() OVER (ORDER BY id) AS discrepancy FROM t )
SELECT id FROM t1 WHERE t1.discrepancy = 
  (SELECT discrepancy FROM t1 WHERE id=?);

Я думаю, что это не так быстро, как код Николаса, но это может стоить эксперимента (если ваша БД способна на этот запрос вообще).

...