два столбца даты и один диапазон дат, типичный запрос? - PullRequest
0 голосов
/ 16 февраля 2012

У меня есть таблица

tbl_charge

id hotel_id start_date  end_date    charge_per_day ( in $)  
1   6       2012-02-15  2010-02-15      20  
2   6       2012-02-16  2010-02-18      30  
4   6       2012-02-20  2010-02-25      50  

Примечание: если какой-либо даты нет в таблице, тогда мыустановите 25$ для каждого дня (то есть плата по умолчанию )

сейчас, если кто-то хочет забронировать отель с 2012-02-15 до 2012-02-22 , затем я хочу вычислить итоговые расходы за даты

Date   : 15+16+17+18+19+20+21+22
Charge : 20+30+30+30+25+50+50+50 = 285$

что я уже сделал:

этот запрос возвращает все строки успешно

SELECT * FROM `tbl_charge` WHERE 
start_date BETWEEN '2012-02-15' AND '2012-02-22' OR
end_date BETWEEN '2012-02-15' AND '2012-02-22' OR
( start_date <'2012-02-15' AND end_date > '2012-02-22')
HAVING property_id=6 

возвращает все необходимые строки, но как мне суммировать расходы ??

  • Есть ли способ подсчета дней между заданным диапазоном дат, например, последняя строка 20-25, но янужно только до 22, тогда он возвращает 3 дня, и мы умножаем расходы на 3
  • . Хорошо ли для этого создать процедуру или использовать простой запрос

Ответы [ 2 ]

4 голосов
/ 16 февраля 2012

Я думаю, что это поможет:

select sum(DayDifference * charge_per_day) + 
        (RealDayDifference - sum(DayDifference)) * 25 as TotalPerPeriod
from (
  select charge_per_day, datediff(
      least(end_date, '2012-02-22'),
      greatest(start_date, '2012-02-15')) + 1 as DayDifference,
      datediff('2012-02-22', '2012-02-15') + 1 as RealDayDifference
  from t1
  where
    ((start_date between '2012-02-15' and '2012-02-22') or
    (end_date between '2012-02-15' and '2012-02-22') or
    (start_date < '2012-02-15' and end_date > '2012-02-22'))
    and hotel_id=6
) S1
1 голос
/ 16 февраля 2012

Мне уже приходилось решать эту проблему ранее, и это забавно, но с тех пор я научился некоторым лучшим методам. В то время я полагаю, что создал процедуру или функцию для циклического выполнения запрошенных дат и возврата цены.

Чтобы вернуть необходимые строки, вы можете просто выбрать, используя верхний и нижний пределы. Вы можете указать дату в пределах критериев выбора, чтобы получить количество итераций для каждой из них.

Если все, что вы в конечном итоге ищете, это одна цена, я бы посоветовал объединить эту логику в функцию

Я предположил вторую таблицу, tbh_hotel с id (int PK == hotel_id) и default_charge (int) со строкой (id = 6, default_charge = 20)

Дальнейшие предположения заключаются в том, что когда ваши даты были "2010", вы подразумевали, что они были "2012", и что это для кого-то, кто регистрируется 15-го числа и выезжает 22-го (и поэтому нуждается в отеле для 15, 16, 17, 18, 19, 20, 21, 7 ночей). Я также предполагаю, что у вас есть логика, которая предотвращает перекрытие диапазонов дат, так что в tbl_charge нет двух строк, соответствующих дате 14 февраля 2012 (например)

Итак, чтобы начать это, запрос для выбора подходящих строк

SELECT 
    *
FROM tbl_charge AS c
WHERE 
(
  c.end_date >= '2012-02-15'
  OR
  c.start_date < '2012-02-22'
)

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

SET @StartDate = '2012-02-15';
SET @EndDate = SUBDATE('2012-02-22',1);

SELECT 
    c.id,
    c.start_date,
    c.end_date,
    c.charge_per_day,
    DATEDIFF(IF(c.end_date>@EndDate,@EndDate,c.end_date),SUBDATE(IF(c.start_date<@StartDate,@StartDate,c.start_date),1)) AS quantityOfThisRate
FROM tbl_charge AS c
WHERE c.end_date >=@StartDate OR c.start_date < @EndDate

Я ПОДТВЕРЖДАЮ дату окончания, потому что, если вы выезжаете 22-го, ваша последняя дата регистрации 21-го. Я СУБДАТИРУЮ дату начала каждого DATEDIFF, потому что, если вы остаетесь 15 - 16 числа, субдата END DATE делает это 15-15 числами, и поэтому эта SUBDATE заставляет 14-15 числа возвращать правильное значение 1. Вывод теперь выглядит примерно так

id  start_date  end_date    price   quantityAtThisRate
1   2012-02-10  2012-02-15  20  1
2   2012-02-16  2012-02-18  30  3
3   2012-02-20  2012-02-29  50  2

Продолжая, я помещу это в подзапрос и объединю tbl_hotel, чтобы получить плату по умолчанию

SET @StartDate = '2012-02-15';
SET @EndDate = SUBDATE('2012-02-22',1);
SET @NumberOfNights = DATEDIFF(ADDDATE(@EndDate,1),@StartDate);
SET @HotelID = 6;


SELECT 
    SUM(specificDates.charge_per_day*specificDates.quantityAtThisRate) AS specificCharges,
    @NumberOfNights-SUM(specificDates.quantityAtThisRate) AS daysAtDefault,
    h.default_charge * (@NumberOfNights-SUM(specificDates.quantityAtThisRate)) AS defaultCharges
FROM tbl_hotel AS h
INNER JOIN
(
    SELECT 
        c.charge_per_day,
        DATEDIFF(IF(c.end_date>@EndDate,@EndDate,c.end_date),SUBDATE(IF(c.start_date<@StartDate,@StartDate,c.start_date),1)) AS quantityAtThisRate
    FROM tbl_charge AS c
    WHERE (c.end_date >=@StartDate OR c.start_date < @EndDate) AND c.hotel_id = @HotelID
) AS specificDates

WHERE h.id = @HotelID

Реально, один запрос получится довольно .... сложным, поэтому я остановлюсь на хранимой процедуре, опираясь на логику выше (как если бы не было особых правил, вышеприведенный запрос вернул бы ноль из-за внутреннего соединения)

Надеюсь, это поможет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...