Мой опыт работы с БД не намного больше, чем простое хранение + извлечение данных в стиле CMS - так что это может быть глупый вопрос, я не знаю!
У меня есть проблема, из-за которой мне нужно искать или рассчитывать отпускные цены для определенного размера группы и определенного количества дней в течение определенного периода времени. Например:
Сколько стоит номер в гостинице для 2 человек на 4 ночи в любое время в январе?
У меня есть данные о ценах и наличии, скажем, 5000 отелей, которые хранятся примерно так:
Hotel ID | Date | Spaces | Price PP
-----------------------------------
123 | Jan1 | 5 | 100
123 | Jan2 | 7 | 100
123 | Jan3 | 5 | 100
123 | Jan4 | 3 | 100
123 | Jan5 | 5 | 100
123 | Jan6 | 7 | 110
456 | Jan1 | 5 | 120
456 | Jan2 | 1 | 120
456 | Jan3 | 4 | 130
456 | Jan4 | 3 | 110
456 | Jan5 | 5 | 100
456 | Jan6 | 7 | 90
С помощью этой таблицы я могу сделать запрос следующим образом:
SELECT hotel_id, sum(price_pp)
FROM hotel_data
WHERE
date >= Jan1 and date <= Jan4
and spaces >= 2
GROUP BY hotel_id
HAVING count(*) = 4;
Результаты
hotel_id | sum
----------------
123 | 400
HAVING
Пункт здесь убеждается , что есть запись для каждого дня между моей датой , которая имеет пространство доступно. то есть. В отеле 456 было 1 место, доступное 2 января, предложение HAVING вернуло бы 3, поэтому мы не получаем результат для отеля 456.
Все идет нормально.
Тем не менее, есть ли способ узнать все 4 ночи в январе, где есть свободное место? Мы могли бы повторить запрос 27 раз - увеличивая даты каждый раз, что кажется немного неловким. Или другой путь может заключаться в том, чтобы хранить все возможные комбинации в таблице поиска следующим образом:
Hotel ID | total price pp | num_people | num_nights | start_date
----------------------------------------------------------------
123 | 400 | 2 | 4 | Jan1
123 | 400 | 2 | 4 | Jan2
123 | 400 | 2 | 4 | Jan3
123 | 400 | 3 | 4 | Jan1
123 | 400 | 3 | 4 | Jan2
123 | 400 | 3 | 4 | Jan3
И так далее. Нам нужно ограничить максимальное количество ночей и максимальное количество людей, которых мы будем искать - например, максимальное количество ночей = 28, максимальное количество людей = 10 (ограничено количеством мест, доступных для этого установленного периода, начинающегося с этой даты).
Для одного отеля это может дать нам 28 * 10 * 365 = 102000 результатов в год. 5000 отелей = 500м результатов!
Но у нас был бы очень простой запрос, чтобы найти самый дешевый 4 ночи в январе для 2 человек:
SELECT
hotel_id, start_date, price
from hotel_lookup
where num_people=2
and num_nights=4
and start_date >= Jan1
and start_date <= Jan27
order by price
limit 1;
Есть ли способ выполнить этот запрос к исходной таблице, не создавая таблицу поиска строк длиной 500 м !? например, сгенерировать 27 возможных результатов во временной таблице или какую-то другую магию внутренних запросов?
В настоящий момент все данные хранятся в БД Postgres - если для этого потребуется, мы можем переместить данные в другое, более подходящее место? Не уверен, что этот тип запроса соответствует шаблонам карты / сокращения для БД в стиле NoSQL ...
источник
Еще один способ, используя
LAG()
функцию:Тест в: SQL-Fiddle
источник
(spaces, day)
, может быть, даже с индексом покрытия(spaces, day, hotel_id, price)
.должен получить результат, который вы ищете, без необходимости в дополнительных структурах, хотя в зависимости от размера входных данных, структуры вашего индекса и яркости планировщика запросов внутренний запрос может привести к спулингу на диск. Вы можете найти это достаточно эффективным, хотя. Предостережение: мой опыт работы с MS SQL Server и возможностями его планировщика запросов,
поэтому приведенному выше синтаксису могут потребоваться твики, если только в именах функций(ypercube изменил синтаксис, так что теперь он предположительно совместим с postgres, см. Историю ответов для варианта TSQL) .Вышеуказанные находки начнутся в январе, но продолжатся в феврале. Добавление дополнительного условия к тесту даты (или корректировка значения конечной даты) легко справится с этим, если это нежелательно.
источник
Независимо от HotelID, вы можете использовать таблицу суммирования с вычисляемым столбцом, например:
В этой таблице нет первичных или внешних ключей, так как она используется только для быстрого расчета нескольких комбинаций значений. Если вам нужно или требуется более одного рассчитанного значения, создайте новое представление с новым именем представления для каждого из значений месяца в сочетании с каждым из значений PP People и Price:
ПРИМЕР КОДА PSEUDO
SummedColumn = 2400
Наконец, присоедините вид к идентификатору отеля. Для этого вам нужно будет сохранить список всех идентификаторов отелей в SummingTable (я это делал в приведенной выше таблице), даже если HotelID не используется для расчета в представлении. Вот так:
БОЛЬШЕ КОДА ПСЕВДО
источник