У меня есть около миллиарда строк данных в таблице с именем и целым числом в диапазоне 1-288. Для данного имени каждое int уникально, и не каждое возможное целое число в диапазоне присутствует - поэтому есть пробелы.
Этот запрос генерирует пример случая:
--what I have:
SELECT *
FROM ( VALUES ('foo', 2),
('foo', 3),
('foo', 4),
('foo', 10),
('foo', 11),
('foo', 13),
('bar', 1),
('bar', 2),
('bar', 3)
) AS baz ("name", "int")
Я хотел бы создать таблицу поиска со строкой для каждого имени и последовательности непрерывных целых чисел. Каждая такая строка будет содержать:
Имя - значение имени столбца
начала - первое целое число в пределах последовательности
конца - конечное значение в непрерывной последовательности
диапазона - конец - старт + 1
Этот запрос генерирует пример вывода для приведенного выше примера:
--what I need:
SELECT *
FROM ( VALUES ('foo', 2, 4, 3),
('foo', 10, 11, 2),
('foo', 13, 13, 1),
('bar', 1, 3, 3)
) AS contiguous_ranges ("name", "start", "end", span)
Потому что у меня так много строк, чем эффективнее, тем лучше. Тем не менее, я должен выполнить этот запрос только один раз, так что это не является абсолютным требованием.
Заранее спасибо!
Редактировать:
Я должен добавить, что решения PL / pgSQL приветствуются (пожалуйста, объясните любые хитрые уловки - я все еще новичок в PL / pgSQL).
источник
Ответы:
Как насчет использования
with recursive
тестовый вид:
запрос:
результат:
Мне было бы интересно узнать, как это работает с вашей таблицей миллиардов строк.
источник
Вы можете сделать это с помощью оконных функций. Основная идея заключается в том, чтобы использовать
lead
иlag
оконную функцию тянуть строки впереди и позади текущей строки. Тогда мы можем вычислить, если у нас есть начало или конец последовательности:(Я использовал представление, чтобы ниже было легче следовать логике.) Теперь мы знаем, является ли строка началом или концом. Мы должны свернуть это в ряд:
Выглядит правильно для меня :)
источник
Другое решение оконной функции. Понятия не имею об эффективности, я добавил план выполнения в конце (хотя с таким небольшим количеством строк он, вероятно, не имеет большого значения). Если вы хотите поиграть: тест SQL-Fiddle
Таблица и данные:
Запрос:
План запроса
источник
На SQL Server я бы добавил еще один столбец с именем previousInt:
Я бы использовал ограничение CHECK, чтобы убедиться, что previousInt <int, и ограничение FK (name, previousInt) ссылаются на (name, int) и еще пару ограничений для обеспечения непроницаемости данных. Это сделано, выбор пробелов тривиально:
Чтобы ускорить это, я мог бы создать фильтрованный индекс, который будет включать только пробелы. Это означает, что все ваши пропуски предварительно вычисляются, поэтому выбор выполняется очень быстро, а ограничения обеспечивают целостность ваших предварительно вычисленных данных. Я часто использую такие решения, они во всей моей системе.
источник
Вы можете посмотреть на метод Табибитозан:
В принципе:
Я думаю, что это представление лучше:
источник
примерный план:
Повторяйте от 2. до тех пор, пока больше не произойдет обновление. Оттуда это становится сложным, Гордианом, с группировкой по максимуму мин и мин максимум. Я думаю, я бы пошел на язык программирования.
PS: Хорошая таблица примеров с несколькими значениями выборок была бы хороша, которая могла бы использоваться всеми, поэтому не каждый создает свои тестовые данные с нуля.
источник
Это решение основано на ответе nate c с использованием оконных функций и предложения OVER. Интересно, что этот ответ возвращается к подзапросам с внешними ссылками. Можно завершить консолидацию строк, используя другой уровень функций управления окнами. Это может выглядеть не слишком красиво, но я предполагаю, что это более эффективно, поскольку оно использует встроенную логику мощных оконных функций.
Из решения Нейта я понял, что начальный набор строк уже содержит необходимые флаги для 1) выбора значений начального и конечного диапазона И 2) для устранения лишних строк между ними. Запрос имеет вложенные два подзапроса только из-за ограничений оконных функций, которые ограничивают использование псевдонимов столбцов. Логически я мог бы получить результаты только с одним вложенным подзапросом.
Несколько других замечаний : Ниже приведен код для SQLite3. Диалект SQLite является производным от postgresql, поэтому он очень похож и может даже работать без изменений. Я добавил ограничение на кадрирование в предложения OVER, поскольку функции
lag()
иlead()
нужны только в одном окне, до и после соответственно (поэтому не нужно было сохранять набор по умолчанию для всех предыдущих строк). Я также выбрал именаfirst
иlast
так как словоend
зарезервировано.Результаты так же, как и другие ответы, как и ожидалось:
источник