Как построить запрос, выводящий список сумм платежей в базовой валюте по курсу на дату платежа?
У меня получается так:
SELECT amount *
(
SELECT rate FROM rates WHERE rates.currency=payments.currency AND rates.date=
(
SELECT MAX(date) FROM rates WHERE rates.currency=payments.currency AND rates.date<=payments.date
)
)
FROM payments
Получается два вложенных селекта, что (zope'ой чувствую) напряжет БД (как минимум FireBird) до изнеможения на большом наборе данных. Можно ли как-то решить этот вопрос проще?
При этом:
* Результат должен работать одновременно на SQLite и FireBird, поэтому желательно было бы получить ответ для SQL "вообще", а не для какого-то конкретного диалекта.
* По той же причине не хочется пользоваться хранимыми процеДурами.
* По условиям задачи решить ее надо именно на уровне SQL; как решать ее на уровне клиента, я понимаю
* Вопросы NULL'ов, неправильных наименований полей (название поля "date" может оказаться ключевым словом в каком-нибудь диалекте SQL) и т.п. мы опускаем для упрощения.
Здравствуйте, sushko, Вы писали:
S>Как построить запрос, выводящий список сумм платежей в базовой валюте по курсу на дату платежа?
C SQLite ты ничего больше не придумаешь, ИМХО. Это сразу сужает способы решения задачи. Да и Firebird
не гигант в плане SQL...
Если только перестроишь таблицу rates так, чтобы у неё не было пропусков, тогда сможешь джойнить по дате платежа
без второго подзапроса.
Здравствуйте, _ABC_, Вы писали:
_AB>Если только перестроишь таблицу rates так, чтобы у неё не было пропусков, тогда сможешь джойнить по дате платежа
ИМХО, интересная идея. В году всего 365 дней — количество не гигантское. Можно построить индекс по дате и валюте, что еще ускорит выполнение.
Здравствуйте, Mihas, Вы писали:
M>ИМХО, интересная идея. В году всего 365 дней — количество не гигантское. Можно построить индекс по дате и валюте, что еще ускорит выполнение.
Ничего не получится: в день может быть несколько изменений курса. В моем примере поле DATE правильнее было бы назвать DATE_AND_TIME
Здравствуйте, sushko, Вы писали:
S>Ничего не получится: в день может быть несколько изменений курса. В моем примере поле DATE правильнее было бы назвать DATE_AND_TIME
Тогда остается только твой вариант, т.к. SQLite с Firebird не скрестишь.
По отдельности вопрос решается, но несовместимыми средствами.
Здравствуйте, sushko, Вы писали:
S>Здравствуйте, Mihas, Вы писали:
M>>ИМХО, интересная идея. В году всего 365 дней — количество не гигантское. Можно построить индекс по дате и валюте, что еще ускорит выполнение.
S>Ничего не получится: в день может быть несколько изменений курса. В моем примере поле DATE правильнее было бы назвать DATE_AND_TIME
Я бы предложил добавить в таблицу Rates таймстемп закрытия курса и выставлять его по дате нового курса. Тогда можно будет просто использовать условие payments.date >= rates.dateopen and payments.date < rates.dateclose.
Здравствуйте, Jester, Вы писали:
J>Я бы предложил добавить в таблицу Rates таймстемп закрытия курса и выставлять его по дате нового курса. Тогда можно будет просто использовать условие payments.date >= rates.dateopen and payments.date < rates.dateclose.
Rates.dateclose is null для действующего курса?
Если да, то для него платежи возвращаться не будут, нужно добавить проверку на этот факт тоже.
Но, вообще, решение вполне себе неплохое в условиях заданных ограничений.
Здравствуйте, _ABC_, Вы писали:
_AB>Rates.dateclose is null для действующего курса?
Для действующего курса dateclose — константа из далекого будущего.
_AB>Но, вообще, решение вполне себе неплохое в условиях заданных ограничений.
В системах с большими объемами данных обычно используется этот подход. Серьезный минус — в необходимости поддерживать целостность на прикладном уровне, так как декларативно и триггерами это не опишешь (уж в Firebird точно). Но если производительность на первом месте, это оправдано.
Здравствуйте, wildwind, Вы писали:
W>В системах с большими объемами данных обычно используется этот подход.
В системах с большими объемами данных используются обычно нормальные РСУБД, которые имеют
мощный синтаксис, а приложения заточены под конкретную РСУБД. Там способов решения проблем
несколько и оптимальный зависит от конкретных данных.
Здравствуйте, _ABC_, Вы писали:
_AB>Здравствуйте, Jester, Вы писали:
J>>Я бы предложил добавить в таблицу Rates таймстемп закрытия курса и выставлять его по дате нового курса. Тогда можно будет просто использовать условие payments.date >= rates.dateopen and payments.date < rates.dateclose. _AB>Rates.dateclose is null для действующего курса?
Можно и по-другому: "условная бесконечность", например, 01.01.2500.
Здравствуйте, Jester, Вы писали:
J>Можно и по-другому: "условная бесконечность", например, 01.01.2500.
Можно, конечно, вопросов нет.
Правда вон Сбербанк таким образом по нижней границе насчитал чего-то там с начала 20-го века.
В общем, нужно это искуственное ограничение учитывать в приложении.