![]() |
Задавайте вопросы, мы ответим
Вы не зашли.
Имеется следующая таблица:
Период использования транспортного средства: Коэффициент 3 месяца 0,4 4 месяца 0,5 5 месяцев 0,6 6 месяцев 0,7 7 месяцев 0,8 8 месяцев 0,9 9 месяцев 0,95 10 месяцев и более 1
В БД я представил её так:
ins_koefs_ks
а.) k PERIOD_USE - период использования ТС в месяцах.
б.) KS - значение коэффициента.
Мне нужно получить значение коэффициента, в зависимости от периода использования.
Для получения значения коэффициента, я пробовал следующий запрос:
select KS, if(@tmp = min(PERIOD_USE) is NULL, max(PERIOD_USE), @tmp)
from ins_koefs_ks
where
:period <= PERIOD_USE
Всё бы хорошо, но при значении параметра period > 10, ничего не выбирается,
поэтому условие не работает и возвращает NULL.
Возможно ли сделать такую выборку одним запросом?
Неактивен
SELECT coeff FROM tablename WHERE period < :period ORDER BY period DESC LIMIT 1;
Неактивен
o.O И всё? Спасибо. :-)
Неактивен
Не то немного... Если период меньше, чем 3, то ничего не вернёт... :-(
Неактивен
И, если, 3.5 месяца, например, он вернёт 3, а не 4...
Неактивен
Артём Н. написал:
Не то немного... Если период меньше, чем 3, то ничего не вернёт... :-(
А в базе есть данные за период меньше, чем три месяца?
Артём Н. написал:
И, если, 3.5 месяца, например, он вернёт 3, а не 4...(
Если вы подразумеваете, что при вводе периода за 3.5 месяца вы хотите получить данные за 4 месяца, то используйте period <= round(PERIOD_USE)
А лучше проводите обработку на клиенте до формирования запроса, чтобы PERIOD_USE имел не дробный вид, а округленный в нужную вам сторону.
Неактивен
А в базе есть данные за период меньше, чем три месяца?
Это "период сезонного использования". Например, ТС используется 3 месяца в году или менее.
К тому же, это только пример. Там сходных запросов несколько.
А лучше проводите обработку на клиенте до формирования запроса, чтобы PERIOD_USE имел не дробный вид, а округленный в нужную вам сторону.
Это, конечно, возможно... Но я, в принципе, не могу знать куда округлять...
Например, запрос для коэффициента мощности очень похожий.
К примеру, коэффициент один для многих ТС с двигателями, мощность, которых свыше 50, но менее 70 л.с. включительно.
В идеале, жёстко зашивать границы в клиент не следует, поскольку, теоретически они могут поменяться. А round() использовать тут не получится... :-(
Отредактированно Артём Н. (30.03.2010 00:46:03)
Неактивен
Артём Н. написал:
А в базе есть данные за период меньше, чем три месяца?
Это "период сезонного использования". Например, ТС используется 3 месяца в году или менее.
К тому же, это только пример. Там сходных запросов несколько.
Не понял. Если ТС используется менее 3 месяцев, то как выглядит запись о ней в базе?
Неактивен
Еcть договор в своей таблице. В таблицу договоров заносятся значения коэффициентов.
Значения выбираются из справочника, но условия выборки расчитываются, исходя из условий договора. К примеру, есть дата начала страхования и дата окончания.
Разность - период. По периоду из справочника выбирается значение коэффициента, которое заносится в договор, используется при расчёте и т.д..
Неактивен
В первом случае, он ничего не выбирал, если значение превышает максимум в таблице.
В вашем запросе (в запросе от paulus) не выбирает, если значение меньше минимума.
Конечно, возможно два запроса использовать, но, наверное, имеется возможность сделать одним запросом?
Отредактированно Артём Н. (30.03.2010 10:06:40)
Неактивен
Вы не ответили на главный вопрос — какой коэффициент должен быть,
если, например, 2 месяца? Если 0.4, то замените первую строку на
0 месяцев — 0.4. Это будет логично, а, раз логично, то и запрос работать
будет.
Неактивен
Да, если 2 месяца, то коэффициент должен быть 0,4. Если 11 месяцев, то 1.
Т.е., при меньшем/большем значениях периода - крайние коэффициенты.
Хм... В принципе, логично.
Но, что нехорошо. Ведь справочники возможно править. Если там будет стоять 0 в периоде использования... Неочевидно для пользователя.
Это первое.
Второе, и более важное - это то, что, в таком случае, при значении периода, к примеру, 3.5 он должен вернуть 0,5. Но он вернёт 0,4.
Конечно, двумя запросами сделать возможно. Но такое подозрение, что это возможно сделать как-то проще...
Отредактированно Артём Н. (31.03.2010 00:28:18)
Неактивен
Попробуйте сделать из «маркетинговой» таблички «реальную». Если
в табличке написано, что 0.5 наступает *после* четырех месяцев, то
это именно так. А у Вас 0.5 наступает после *трех* месяцев.
Нужно делать так, как оно на самом деле есть, а не так, как лучше
надурить людей К слову сказать, если в маркетинговой табличке
написать словами «больше трех месяцев» — это будет понятно и от-
крыто. Возможно, больше клиентов привлечете простой честностью.
Ну и, когда люди честны с собой, у них и запросы пишутся проще
Неактивен
paulus написал:
Попробуйте сделать из «маркетинговой» таблички «реальную». Если
в табличке написано, что 0.5 наступает *после* четырех месяцев, то
это именно так. А у Вас 0.5 наступает после *трех* месяцев.
Уф, это я погорячился, наверное. %-)
Нужно делать так, как оно на самом деле есть, а не так, как лучше
надурить людей :)
Так коэффициенты в законе определены. Тут я просто, похоже, ошибся.
Спрошу ещё...
Хм... Но идея хорошая. ;-)
К слову сказать, если в маркетинговой табличке
написать словами «больше трех месяцев» — это будет понятно и от-
крыто. Возможно, больше клиентов привлечете простой честностью.
Ну и, когда люди честны с собой, у них и запросы пишутся проще ;)
Да эту табличку будет видеть только администратор, и то - редко. :-)
Когда меняются коэффициенты и нужно изменить их в справочнике. Это нечасто бывает.
Администратор меняет их через интерфейс, естественно, а не через запрос UPDATE в клиенте mysql. :-)
Представьте лёгкое удивление, когда вместо ожидаемых двух месяцев там будет стоять ноль...
Плюс ещё, охота сделать, чтобы число периодов тоже возможно было менять.
Зачем на практике - не знаю. Ради универсальности.
P.S.: Спасибо, что заметили ошибку с коэффициентами. Буду ещё перепроверять.
Может, где ещё напортачил. :-\
Неактивен
Поэтому, хочется просто из таблиц в БД коэффициенты скопировать, чтобы на клиенте не мудрить...
Неактивен
Хм... Нет, я не ошибся. Действительно, если 3.5 месяца, то коэффициент уже 0.5.
Не знаю так/не так, но как мне сказали, так я и делаю.
Так что запрос не проходит. Ничего в голову не идёт, да и запарился уже порядком...
Может, всё-таки, возможно одним запросом сделать?
Неактивен
Напишите на бумажке преобразования из маркетинговой таблички в ту, по
которой можно что-то посчитать, потом запрограммируйте их и используйте,
когда нужно будет менять маркетинговую табличку.
Очень жаль, что Вам не нравится идея честности
Неактивен
Очень жаль, что Вам не нравится идея честности
Идея хорошая, но меня тут не спрашивают. :-) По идее, если ТС страхуется на период более 3-х месяцев, то считается, что оно страхуется на 4 месяца. Потому и коэффициент такой берётся. Вы меня слегка смутили, я посмотрел закон.
Не нашёл где об этом говорится. Наверное, смотрел плохо. Но делать-то мне, по-любому, придётся, как говорят.
paulus написал:
Напишите на бумажке преобразования из маркетинговой таблички в ту, по
которой можно что-то посчитать, потом запрограммируйте их и используйте,
когда нужно будет менять маркетинговую табличку.
Вот и вопрос. А без этого возможно сделать?
Неактивен
Компьютеры работают по тому алгоритму, которому их научили. Вы можете
научить их врать, но каждое правило вранья надо описывать отдельно. Ну
и в MySQL не предусмотрено варианта быстрого вранья, поэтому прийдется
описывать через IF. Или сделать так, как я сказал раньше, — описать все
вранье в одном модуле, сделать честную табличку, а с честными данными
уже работать быстро
Неактивен
Компьютеры работают по тому алгоритму, которому их научили. Вы можете
научить их врать, но каждое правило вранья надо описывать отдельно. Ну
и в MySQL не предусмотрено варианта быстрого вранья, поэтому прийдется
описывать через IF. Или сделать так, как я сказал раньше, — описать все
вранье в одном модуле, сделать честную табличку, а с честными данными
уже работать быстро
Ну, если вы будете вдаваться в филосософию... С точки зрения диалектического материализма... %-)
Помните анекдот:
Как-то спросил (после пятой) Чапаев у Фурманова о том что же такое философия.
Отвечает ему Фурманов:
- Ну как бы тебе объяснить, Василий Иваныч... Вот например: два мужика, один чистый, другой грязный, какой в баню пойдёт?
- Ну конечно грязный.
- Эээ, нет, Василий Иваныч.
Вот чему нас учит диалектика: грязный - он как есть по жизни грязный, ему в баню не хочется. А вот чистый - он так и будет к чистоте стремиться, значит он в баню пойдёт
- Надо же.. Вот люди-то умные какие. Так что же такое философия-то?
- Ну вот опять: два мужика, чистый и грязный, какой в баню пойдёт?
- Ну сам же сказал - чистый пойдёт.
- А вот логика нас учит: чистый - он и так чистый, зачем ему в баню? А вот грязному - мыться надо, он в баню пойдёт.
- Ох, и правда, наука, понимаешь. Ну, дальше что?
- Ну вот опять: два мужика, чистый и грязный, какой в баню пойдёт?
- Эх, совсем ты меня запутал. Хрен его знает!
- Вот, Василий Иваныч, вот это и есть - философия!
Даже геометрий совсем "честных" не существует, а вы говорите... ;-)
Что же касается меня. Для меня - это не враньё. Мне это надо сделать.
Поскольку:
1.) Есть люди, которые требуют именно это.
2.) Есть закон, который об этом говорит. Но утверждать я этого не могу, поскольку я не юрист, а сам лично не увидел. :-)
не предусмотрено варианта быстрого вранья, поэтому прийдется
описывать через IF.
IF возможно применять только в хранимых процедурах? :-(
Или сделать так, как я сказал раньше, — описать все
вранье в одном модуле, сделать честную табличку, а с честными данными
уже работать быстро
Вот представьте себе: штук двадцать справочников. Не так много. Но хватает.
Отображаются эти справочники в DBGrid'е. Одна форма на все.
Мне проще сделать через два запроса и функцию, чем для некоторых справочников делать отдельную обработку, а, тем более, интерфейс.
К тому же, времени нет. А лени много. :-)
Неактивен
Ну, мой подход никак не конфликтует с тем, что Вы написали (а главное — с тем,
что надо сделать). Пусть у Вас есть табличка в DBGrid, в которой люди забивают
нелогичную информацию. После того, как они нажали «сохранить», вы делаете
хитрую подпольную операцию: сохраняете эти данные, как есть *и* переписыва-
ете честную табличку так, чтобы по ней можно было делать выборки. А людям,
которые не любят честное, ее не показываете. В результате достигаются следую-
щие цели:
- Люди считают, что Вы пишете хорошие быстрые программы, даже если они
внаглую врут во входных данных;
- Вам не надо врать себе, что данные хорошие — Вы для себя умеете отличать
хорошие данные от плохих;
- Запросы строятся на базе хороших данных, а потому они простые и понятные.
Ну, и работают быстро, конечно
Неактивен
После того, как они нажали «сохранить», вы делаете
хитрую подпольную операцию: сохраняете эти данные, как есть *и* переписыва-
ете честную табличку так, чтобы по ней можно было делать выборки.
Теоретически, конечно, подход неплохой... Но как я буду делать "хитрую подпольную операцию"?
Во-первых, я не вижу очевидных путей для этого.
Во-вторых, мне сложно самому будет, "вручную" разбираться где какой период.
В-третьих, но самое важное, чтобы делать преобразование нужны ещё какие-то данные.
К примеру, если я поставлю 0, вместо 2-х, откуда я буду знать, что там период 2, а не 1, например? Опять же: надо где-то хранить... Менять структуру таблицы.
А хочется, чтобы таблица максимум соответствовала "бумажной".
В данном случае, это вполне возможно и оправданно (всего-то два столбца).
Я думаю, что лучше так:
1.) Получить коэф. для минимума (ну или максимума).
2.) Получить коэф.
3.) Если NULL, то использовать коэф., полученный в (1).
Причём, есть возможность сделать это на базе процедуры. На скорость выполнения, думаю, это не сильно повлияет.
Ну, в общем, я разобрался.
Спасибо.
P.S.:
- Люди считают, что Вы пишете хорошие быстрые программы, даже если они
внаглую врут во входных данных;
Ага, и кроют меня матом за то, что программа считает себя умнее их. :-\
Отредактированно Артём Н. (03.04.2010 10:47:05)
Неактивен
О, ееее!
Я попытался написать процедуру, но так и не въехал, как в процедуре вернуть результат запроса, чтобы использовать с IF, в дальнейшем, в той же процедуре. (Кстати, весьма интересно узнать, как?).
Но, тем не менее, я нашёл "механизм быстрого вранья".
select KS, ifnull(min(if(PERIOD_USE >= :period), PERIOD_USE, NULL), max(PERIOD_USE)) from ins_koefs_ks;
Отредактированно Артём Н. (03.04.2010 13:16:49)
Неактивен
По крайней мере, возвращает нужный ID. :-\
Мда... Придётся подзапросом, всё равно, делать.
Примерно так:
select KS from ins_koefs_ks where PERIOD_USE = (select ifnull(min(if(PERIOD_USE >= :period), PERIOD_USE, NULL), max(PERIOD_USE)) from ins_koefs_ks);
Отредактированно Артём Н. (03.04.2010 13:20:56)
Неактивен
Плохо, что с JOIN Не работает:
select KS from ins_koefs_ks ik1 join ins_koefs_ks iks on ik1.PERIOD_USE = (ifnull(min(if(iks.PERIOD_USE >= :period), iks.PERIOD_USE, NULL), max(iks.PERIOD_USE)));
Возможно ли такое для JOIN переделать?
Отредактированно Артём Н. (03.04.2010 13:27:46)
Неактивен