Модераторы: skyboy, MoLeX, Aliance, ksnk

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Помогите грамотно составить запрос 
:(
    Опции темы
letsgo
Дата 24.3.2010, 10:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 42
Регистрация: 17.2.2009

Репутация: нет
Всего: нет



Проблема, описанная в этом посте решена, но теперь задача усложнилась и требуется ваша помощь (в этом же топике). Буду благодарен! Заранее всем спасибо! 

Есть таблица, которая содержит информацию о тарифах. 
Структура таблица
id - Порядковый номер записи
idtariff - ID тарифа
date_start - дата начала действия тарифа в UNIX формате
date_finish - дата окончания действия тарифа в UNIX формате
price - Величина тарифа в указанный период

К примеру есть следующие записи

Код

id | idtariff | date_start     | date_finish | price |
1  |     5    | 1272657600    |1273867200 | 20.00 |
2  |     5    | 1273953600    |1275249600 | 25.00 |


Т.е. с 01.05.2010 по 15.05.2010 величина тарифа с ID = 5 равняется 20 в день, а с 16.05.2010 по 31.05.2010 равняется 25 в день

Допустим, мне необходимо получить информацию о стоимости тарифа с 02.05.2010 по 07.05.2010. 
Здесь всё просто:
SELECT `price` FROM `table` WHERE `date_start` <= '1272744000' AND `date_finish` >= '1273176000'
Полученное значение умножаем на количество суток в нашем случае 5 и все довольны.

А что делать, когда нам необходимо подсчитать стоимость тарифа с 02.05.2010 по 25.05.2010.
Сейчас, я веду эти подсчёты с помощью цикла.
Т.е. беру первую дату 02.05.2010 (1272744000) и ищу стоимость по ней, затем беру следующую дату 03.05.2010 и прибавляю к предыдущей и так далее до даты равной 25.05.2010.
Получается на один подсчёт уходит более 20 запросок к БД. Считаю, что делаю очень неправильно, поэтому, хотелось бы проконсультироваться.

Спасибо.




Это сообщение отредактировал(а) letsgo - 27.7.2010, 13:08
PM MAIL   Вверх
azesmcar
Дата 24.3.2010, 10:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 1
Всего: 211



я не совсем понял задачу, у меня подозрение на неправильную архитектуру, но твоя задача (то, что описано) решается просто
date_finish - date_start = разница в секундах
date_finish - date_start / 60 / 60 / 24 = количество суток
в первом случае
(1273176000 - 1272744000) / 60 / 60 / 24 = 5
тоже самое во втором случае.
и к PHP вопрос не имеет никакого отношения.

а вообще есть куча функций для работы с датой и временем (типа date_diff), смотри в manual-ах своей СУБД.

Это сообщение отредактировал(а) azesmcar - 24.3.2010, 10:54
PM   Вверх
letsgo
Дата 24.3.2010, 11:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 42
Регистрация: 17.2.2009

Репутация: нет
Всего: нет



Цитата

я не совсем понял задачу,

Опишу может чуть подробнее.
В каждой строке таблицы хранится запись о величине тарифа в конкретном периоде. Т.е. в первой строке, указано, что с 1 мая по 15 мая тариф равняется 20 в день, во второй строке, что с 16 мая по 31 мая тариф == 25. Если мне нужно узнать стоимость тарифа со 2 мая по 7 мая. Я знаю, как это сделать одним запросом, потому что использоваться будет только одна строка.
Если же мне нужно узнать величину тарифа со 2 мая по 17 мая, я не могу это сделать одним запросом ( smile ), потому что величина тарифа с 01 мая по 15 мая хранится в одной строке, а данные для подсчёта тарифа с 16 по 17 уже в другой строке. И сейчас я эту проблему решаю с помощью цикла, что создаёт большую нагрузку на БД, так как запросов делается очень много.

Может с моей стороны будет наглостью,  но хотелось бы получить конкретный вид запроса, т.е.
сколько будет составлять тариф с 02.05.2010 (1272744000) по 17.05.2010 (1274126399). Сейчас я это делаю следующим образом

Код

$srok = 16; //Количество дней для подсчёта
$date_start = 1272744000;

for ($i=1; $i<=16; $i++) {
$res = mysql_query("SELECT `price` FROM `table` 
WHERE `date_start` <= '$date_start'
AND `date_finish` >= '$date_start'
 AND `idtariff` = '$idtariff'");
$row = mysql_fetch_array($res);
$allprice = $allprice + $row['price']; 
$date_start = $date_start+(24*60*60);
}




Цитата

и к PHP вопрос не имеет никакого отношения.

Да. Извиняюсь. Уже забыл, что здесь есть раздел для подобных вопросов.

Это сообщение отредактировал(а) letsgo - 24.3.2010, 11:44
PM MAIL   Вверх
azesmcar
Дата 24.3.2010, 11:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 1
Всего: 211



letsgo

Если там две строки, то и цены могут быть разные, в таком случае нужна итерация по каждой строке..или мне не совсем понятно. Если цена та же самая (тогда зачем нужны две идентичные строки?) - тогда группируй по idtariff.

Это сообщение отредактировал(а) azesmcar - 24.3.2010, 11:43
PM   Вверх
letsgo
Дата 24.3.2010, 11:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 42
Регистрация: 17.2.2009

Репутация: нет
Всего: нет



Цитата

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

Я отредактировал сообщение, добавил код, с помощью которого сейчас ведётся подсчет. Т.е., сейчас я выбираю величину тарифа для каждого дня. Если нам нужно подсчитать для 7 дней, делаем 6 запросов, нужно 17 дней делаем 16 запросов. И при каждом запросе увеличиваем переменную $date_start на 86400 секунд (т.е. на 1 сутки)

Цитата

Если там две строки, то и цены могут быть разные

Да. одна строка = один период = одна цена, следующая строка уже другой период и другая цена соответственно

Это сообщение отредактировал(а) letsgo - 24.3.2010, 11:50
PM MAIL   Вверх
azesmcar
Дата 24.3.2010, 11:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 1
Всего: 211



letsgo

ок. кажется понял.

Добавлено через 7 минут и 9 секунд
дай структуру таблицы и тестовые данные

Это сообщение отредактировал(а) azesmcar - 24.3.2010, 11:59
PM   Вверх
letsgo
Дата 24.3.2010, 12:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 42
Регистрация: 17.2.2009

Репутация: нет
Всего: нет



Код

CREATE TABLE `tariffs` (
  `idprice` int(18) NOT NULL auto_increment,
  `idtariff` int(9) NOT NULL,
  `date_start` int(12) NOT NULL,
 `date_finish` int(12) NOT NULL,
 `price` float(9,2) NOT NULL default '0.00',
 `valute` int(4) NOT NULL default '0',
  PRIMARY KEY  (`idprice`),
  KEY `idtariff` (`idtariff`)
) ENGINE=MyISAM  DEFAULT CHARSET=cp1251 AUTO_INCREMENT=1429072 ;


Это сообщение отредактировал(а) letsgo - 24.3.2010, 12:21
PM MAIL   Вверх
azesmcar
Дата 24.3.2010, 12:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 1
Всего: 211



а данные где?
PM   Вверх
letsgo
Дата 24.3.2010, 12:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 42
Регистрация: 17.2.2009

Репутация: нет
Всего: нет



Код

INSERT INTO `tariffs` (`idprice`, `idtariff`, `date_start`,`date_finish`,`price`,`valute`) VALUES
('', '1','1272657600','1273953599','24','840'),
('', '1','1272744000','1274039999','21','840'),
('', '1','1272830400','1274126399','20','840'),
('', '1','1272916800','1274212799','24','840'),
('', '1','1273003200','1274299199','21','840'),
('', '1','1273089600','1274385599','23','840'),
('', '1','1273176000','1274471999','21','840')


Цитата

а данные где?

Извиняюсь. Задержка вышла.
7 периодов по тарифу с ID=1, начиная с 01.05.2010. Все по 15 дней, но это случайно.
Период идёт в следующем виде:
НачалоПериода (01.05.2010 00:00) - КонецПериода (15.05.2010 23:59)


Это сообщение отредактировал(а) letsgo - 24.3.2010, 13:01
PM MAIL   Вверх
azesmcar
Дата 24.3.2010, 15:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 1
Всего: 211



letsgo

Сейчас времени нет долго ковыряться, написать можно с помощью SQL, предлагаю обойтись банальной оптимизацией цикла, т.е. сперва получить все тарифы для 16 дней а потом делать итерация по ним а не каждый раз запрашивать данные на 1 день.
PM   Вверх
Fortop
Дата 24.3.2010, 15:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2200
Регистрация: 13.11.2007
Где: Донецк

Репутация: 3
Всего: 42



Цитата(letsgo @  24.3.2010,  10:35 Найти цитируемый пост)
сколько будет составлять тариф с 02.05.2010 (1272744000) по 17.05.2010 (1274126399). 

Так чему же будет равен тариф, если до 15го было 20, а с 16го стало 25?

По какой формуле считается-то?




--------------------
Мир это Я.
Живее всех живых.
PM MAIL   Вверх
azesmcar
Дата 24.3.2010, 15:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 1
Всего: 211



Цитата(Fortop @  24.3.2010,  15:18 Найти цитируемый пост)
Так чему же будет равен тариф, если до 15го было 20, а с 16го стало 25?

насколько я смог понять будет считаться с 15 по 16 по цене 20 а потом по цене 25,
PM   Вверх
Fortop
Дата 24.3.2010, 15:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2200
Регистрация: 13.11.2007
Где: Донецк

Репутация: 3
Всего: 42



Тогда считается не тариф, а сумма оплаты.
А это элементарно

Код

SELECT price, CASE 
WHEN date_start < $datestart AND date_finish < $dateend 
    THEN date_finish - $datestart
... остальные 3 случая по аналогии
END as days FROM table
WHERE date_start BETWEEN $datestart AND $dateend OR date_finish BETWEEN $datestart AND $dateend


Все. В итоге у нас цена и число дней когда эта цена действовала. Можно там же в запросе их перемножить и просуммировать.


--------------------
Мир это Я.
Живее всех живых.
PM MAIL   Вверх
letsgo
Дата 24.3.2010, 16:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 42
Регистрация: 17.2.2009

Репутация: нет
Всего: нет



Цитата

остальные 3 случая по аналогии

Извиняюсь, а можно поподробнее, что это за "остальные 3 случая".
Буду благодарен
PM MAIL   Вверх
Fortop
Дата 24.3.2010, 16:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2200
Регистрация: 13.11.2007
Где: Донецк

Репутация: 3
Всего: 42



Цитата(letsgo @  24.3.2010,  15:30 Найти цитируемый пост)
а можно поподробнее, что это за "остальные 3 случая".

А логику применить?
Есть четыре варианта.
Период может попасть в промежуток дат 
  •  целиком
  •  концом
  •  началом
  • быть больше промежутка (т.е. промежуток сам находится в периоде).
Соответственно число дней, которые будут взяты из этого периода, будет разным.
Вариант когда период не попадает в промежуток дат отсеивается еще в WHERE (кстати там ошибка, его надо дополнить, чтобы брались данные и для 4го случая)


--------------------
Мир это Я.
Живее всех живых.
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Базы Данных | Следующая тема »


 




[ Время генерации скрипта: 0.1089 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.