Приветствую! Вопрос такой- Есть объекты аренды, цена на которые меняется несколько раз в году. Бронировать объекты можно в любое время. Цена при этом ставится из того периода, на который создается бронь. На данный момент все реализовано по месяцам. Человек выбирает период дат, на который ему нужен объект. Например ему нужно с 4 апреля по 2 мая. У каждого объекта есть строка в таблице, в котором указано 12 цен, по количеству месяцев. Подставляя значение месяца из разложенной на атомы даты, я получаю цену за этот месяц, а специальный алгоритм, вычисляя сколько в выбранном периоде дат дней в одном месяце, а сколько в другом - собирает финальную цену. Ну все работает как часы, аллилуйя. И тут - гром с неба... Цены теперь меняются не по месяцам, а... как угодно менеджеру. То есть, например, до 14 февраля одна цена, после 14го - другая. И наступил вселенский пук Добавлено спустя 6 минут 3 секунды: Часть 2: Извините, пишу с телефона, не туда тыкнул... Быстрое решение пришло такого рода - при забивке цен на объект, менеджер указывает, если месяц состоит из двух ценников. Тогда он вводит в отдельной открывшейся форме цену за каждый день такого месяца. И эти данные заносятся в отдельную таблицу, где у каждой строки 30 столбцов цены, по количеству дней в месяце. При выборке проверяется, "сложный" месяц или простой. Если простой - берется месячная цена. Если сложный - берется из новой таблице сумма столбцов по количеству дней в это месяце. И вот вопрос - а как подсчитать эту сумму? К примеру имея столбцы формата названия price_day01, как сложить между собой 26 таких столбцов? Заранее спасибо. Синтаксис SUM понимаю для суммы значений столбца в куче строк, но не суммы значений кучи столбцов у одной строки
Сделать 30 столбцов это ппц какой гибельный путь. ))) Не надо смотреть на базу SQL как на таблицу Excel! Все данные одного вида должны быть в одной колонке. Надо отдельно рассматривать дни? 30 дней = 30 строк в таблице дней. Надо получать быстро без суммирования общую сумму? Хранишь сумму одной строкой в другой таблице. Это не альтернативы, а взаимодополняющие варианты. Уж как тебе удобнее покажется - в одной или в двух таблицах. Добавлено спустя 4 минуты 39 секунд: Раскладывать данные по колонкам нормально в отчетах — т.н. кросс-таблицах. Но не хранить их в таком виде. Просто за*бешся работать с такой структурой, поверь.
Спасибо за советы! Вообще я подсчитал - как-то напрягся. 70 объектов аренды, 8 разновидной каждого, для каждого по 30 строк - сходу 16800 строк, а ведь это еще "леди даже не разделась". не надо злоупотреблять цитированием. ты отвечаешь на конкретную фразу — её и цитируй. — модераторъ
MySQL без проблем работает с миллионами записей. Добавлено спустя 16 минут 13 секунд: А вообще для проверки пересечения временных диапазонов достаточно иметь запись буквально "с - по". Незачем для каждого дня отдельную запись. Предположим имеется прейскурант с записями (object_id, date_from, date_to, price) и допустим у нас в скрипте есть массив id объектов, подходящих по критериям выборки, неважно какой. Просто мы что-то вычислили предварительно. d1, d2 - интересующий нас период, ids - айдишники интересующих нас объектов Хотим узнать все цены: Код (Text): SELECT * FROM prices WHERE ( object_id IN(:ids) ) AND ( date_from <= :d2 AND :d1 <= date_to ) Аналогично можно организовать таблицу броней и искать какие из желаемых номеров уже заняты. См. про оптимальную выборку за период, подстановка массива в запрос
Изначально план был именно такой. период 'n' - datestart / datefinish / price. И уже все накатал, проверка с помощью between правда, а не операторами сравнения, может я неправ... Но я уперся лбищем в проблему - человек может приехать в один период и уехать в другой. И вот котовасия с расчетом сколько дней в каком периоде он провел... Я понимаю, что докумекать можно, но у меня сроки - вчера, как говорится. Потом я допилю как угодно, но шеф уже просто кожу лоскутами с меня снимает, хочу сделать костыль быстрый.
Может мы с тобой на разных языках говорим. Внесем ясность. Период это две даты: «дата С» и «дата ПО». Про дату, которая больше или равна С и меньше или равна ПО говорят что «дата попадает в период». Про два периода говорят что «периоды пересекаются» если хотябы один день у них общий. Длина пересечения периодов вычисляется так: min($end1, $end2) - max($begin1, $begin2) Может быть воот такое выражение на MySQL поможет тебе врубиться? Код (Text): SET @beg1 = DATE('2015-04-01'); SET @end1 = DATE('2015-04-14'); SET @beg2 = DATE('2015-03-25'); SET @end2 = DATE('2015-04-05'); SELECT DATEDIFF(LEAST(@end1,@end2), GREATEST(@beg1, @beg2));
Ну вот есть номер. У него цена - периодами. Период 1 - с 13.04.2015 по 25.05.2015, цена 2000 Период 2 - с 26.05.2015 по 16.09.2015, цена 3000 и так далее. Пользователь задает - приеду с 23.05.2015 по 14.06.2015. Получается он попадает и на период 1 и на период 2. Схема ж верная? Или его заданные даты въезда-выезда рассматривать как условный период 3?
все верно. клиентский период пересекается с двумя периодами цен. как их найти средствами SQL я уже показал. надо просчитывать все найденные периоды. псевдокод для вычисления итоговой стоимости брони Код (PHP): $sum = 0; while ($row = mysqli_fetch_assoc($result)) { $days = intersect_period($raw['date_from'], $raw['date_to'], $d1, $d2); $price = $row['price']; $sum += $price * $days; }
Проверьте меня в теории, пожалуйста. То бишь я сначала снимаю информацию, не в одном ли ценовом периоде весь период юзера. Это я могу сделать так: Код (Text): SELECT * WHERE дата въезда => periodstart AND дата выезда =< periodfinish Если num вернется один, то период один и ценник очевиден. Если num вернется не один, то начинаются пляски... У меня есть два периода, полученных из запроса. Код (Text): SELECT DATEDIFF(LEAST(@дата выезда,@end1), GREATEST(@дата въезда, @beg1)); = количество дней, заказанных юзером из первого периода. Код (Text): SELECT DATEDIFF(LEAST(@дата выезда,@end2), GREATEST(@дата въезда, @beg2)); = количество дней, заказанных юзером из второго периода. ТАК?
когда непонятно — смотри на рисунок и попробуй представить что это ТВОИ периоды. "… WHERE дата въезда… " ты написал неправильно. перечитай и попробуй понять прежде чем копировать. не надо условий "если num один". просто всегда считай в цикле, будь готов что строк будет сколько угодно: от одной до дофига. примером с datediff я показал как считать пересечение на стороне mysql. но только придется переменные заменить на реальные поля и значения, это понятно? или напиши функцию на php которая будет считать то же самое.
Разбираю пример с картинки по вашей статье. min(21.07, 01.07) - max(25.06, 22.06) = 01.07 - 25.06 = 7 суток min(21.07, 16.07) - max(25.06, 02.07) = 16.07 - 02.07 = 15 суток min(21.07, 01.08) - max(25.06, 17.07) = 21.07 - 17.07 = 5 суток Всего выходит: 27суток Ручками проверяю по календарю - выбранный период - 27 суток. Добавлено спустя 35 минут 9 секунд: В принципе дальнейший путь более-менее ясен, но не могу уже сообразить (вы мне сегодня порядком мозг порушили, если честно, тема жутко интересная!), как получить id всех периодов, которые затронуты выбором юзера. Вот такая тестовая конструкция отлично выбирает один период, но если затронуты два и более - результат пуст... Код (Text): $datein = '2015-04-24'; $dateout = '2015-05-18'; $connect = connectDB(); { $query="SELECT * FROM periods WHERE ( periodfrom <= '$datein' AND '$dateout' <= periodto )"; $query_res=mysql_query($query); } closeDB ($connect); $periods = mysql_result($query_res,0,period_id); echo '<br><br>'.$query.'<br><br>'; echo '<br><br>'.$periods.'<br><br>'; Массив IDшников пытался и через mysql_fetch_array и через mysql_fetch_row выводить...
вот и прекрасно. если всё делать аккуратно, успех гарантирован! Добавлено спустя 3 минуты 12 секунд: вернись к моей формуле с поиском периодов и еще раз внимательно посмотри где начало, где конец.
Я перепутал точку входа и выхода. Верно так? Код (Text): $query="SELECT * FROM periods WHERE ( periodfrom <= '$dateout' AND '$datein' <= periodto )"; Но тогда он фигню выдает. Задаешь числа охватывающие три периода, а он выдает только один.
я этой теме отдал уже достаточно времени, дальше сам. если захочешь чтобы тебе помогли с SQL-запросом, не поленись создать песочницу на http://sqlfiddle.com с кучкой правдоподобных данных, помошники обязательно найдутся.
Я стормозил просто. Запрос заработал, а вывод остался одного значения... Да, огромное спасибо! Огромнейшее! Одно уточнение, если можно... Код (Text): $days = min($periodout, $dateout) - max($periodin, $datein); вычисляться не хочет никак. Эхом проверяю - все переменные не пустые и формата даты. Кавычки не помогают (((
Прошу помощи в этом, сил уже нет, начитываю работу с датами, понимаю, что не числовые же значения... Пробовал перегнать в секунды - не то. Подскажите, пожалуйста, как формулу запустить, уже сил от этого проекта никаких :-(
Да потому что не по уровню задачку себе нашел, прямо скажем. Что в твоих переменных, из которых ты days вычисляешь? "Формат даты" это текст чтоли? Так почитай про даты в PHP и как с ними работать. viewtopic.php?f=20&t=50838
Спорить не буду, у меня вообще другой профиль работы, но больше некому, пришлось изучать Добавлено спустя 15 минут 10 секунд: Работает, большое спасибо!
Все работает отлично, но считает сутки, а не ночи, как принято в отелях.То есть последние сутки в выбранном диапазоне считать как бы не нужно. Игры с прибавлением/убавлением 86400 секунд рушат всю систему подсчета, в сетке дней появляются бреши на стыках периодов и начинается жесть. На уровне формулы, можно ли отцепить один день с конца? Добавлено спустя 39 минут 40 секунд: Очень прошу помощи, завтра директорша будет мне зарплату резать за то, что я делать вообще не обязан. Что-то я уже на грани нервного срыва из-за всей этой хрени.
http://www.youtube.com/watch?v=T_CrevdjExM С самим периодом не должно быть проблем. Если бронируем на одну ночь 15 апреля, то это период ('2014-04-15' .. '2014-04-15') - по 15е, а не по 16е! Если бронируем на 17 ночей, начиная с 1 июля, то это период ('2015-07-01' .. '2015-07-17') Видимо надо поправить вычисление длины периода: Код (Text): N = дата_конца - дата_начала + 1 Проверка формулы на PHP: Код (PHP): echo (strtotime('2015-07-17') - strtotime('2015-07-01')) / (24*60*60) + 1; // 17 Чистый SQL: http://sqlfiddle.com/#!9/fab4bf/3 дает в сумме 17 ночей