我有三个表:monthly_revenue,currencies和foreign_exchange.
|------------------------------------------------------|
| id | product_id | currency_id | value | month | year |
|------------------------------------------------------|
| 1 | 1 | 1 | 100 | 1 | 2015 |
| 2 | 1 | 2 | 125 | 1 | 2015 |
| 3 | 1 | 3 | 115 | 1 | 2015 |
| 4 | 1 | 1 | 100 | 2 | 2015 |
| 5 | 1 | 2 | 125 | 2 | 2015 |
| 6 | 1 | 3 | 115 | 2 | 2015 |
|------------------------------------------------------|
Run Code Online (Sandbox Code Playgroud)
|---------------------------------------|
| id | base | target | rate | rate_date |
|---------------------------------------|
| 1 | GBP | USD | 1.6 |2015-01-01 |
| 2 | GBP | USD | 1.62 |2015-01-15 |
| 3 | GBP | USD | 1.61 |2015-01-31 |
| 4 | EUR | USD | 1.2 |2015-01-01 |
| 5 | EUR | USD | 1.4 |2015-01-15 |
| 6 | EUR | USD | 1.4 |2015-01-31 |
| 7 | GBP | EUR | 1.4 |2015-01-01 |
| 8 | GBP | EUR | 1.45 |2015-01-15 |
| 9 | GBP | EUR | 1.44 |2015-01-31 |
|---------------------------------------|
Run Code Online (Sandbox Code Playgroud)
由此,我们可以看到平均fx率:
美元作为基础货币没有价格,2月没有价格.
|-----------|
| id | name |
|-----------|
| 1 | GBP |
| 2 | USD |
| 3 | EUR |
|-----------|
Run Code Online (Sandbox Code Playgroud)
monthly_revenue表中的每一行都可以有不同的currency_id,因为订单放置的是不同的货币.我想以一种共同货币查看给定月份的所有收入.因此,我不想一月份以英镑计算1月份的所有收入,而是单独查看1月份美元的所有收入,而是希望1月份所有收入都能获得一个值 - 转换为美元(例如).
这可以使用以下内容计算每一行(本例中使用1月):
收入价值x基准货币与目标货币之间1月份的平均汇率
如果我在1月份有5个订单,有4种不同的货币,这让我看到任何单一货币的所有收入.
这应该返回:
|------------------------------------------------------|
| id | product_id | currency_id | value | month | year |
|------------------------------------------------------|
| 1 | 1 | 1 | 100 | 1 | 2015 |
| 2 | 1 | 2 | 125 | 1 | 2015 |
| 3 | 1 | 3 | 115 | 1 | 2015 |
|------------------------------------------------------|
Run Code Online (Sandbox Code Playgroud)
但是,第1行和第3行不是美元(分别是GBP和EUR).
我想看到的是返回的每一行都有正在转换的平均汇率和一converted列.例如:
|-------------------------------------------------------------------------|
| id | prod_id | currency_id | value | month | year | fx_avg | converted |
|-------------------------------------------------------------------------|
| 1 | 1 | 1 | 100 | 1 | 2015 | 1.61 | 161 |
| 2 | 1 | 2 | 125 | 1 | 2015 | 1 | 125 |
| 3 | 1 | 3 | 115 | 1 | 2015 | 1.33 | 152.95 |
|-------------------------------------------------------------------------|
Run Code Online (Sandbox Code Playgroud)
我现在可以使用下面的查询完成基本计算,但缺少一些关键功能:
如果没有可用的外汇汇率(例如,对于未来日期当然没有外汇汇率),则忽略整行.在这个例子中我想要的是使用最近一个月的平均值.
如果在目标货币与基础货币相同的情况下执行计算,则忽略整行(因为FX表中没有基数等于目标的记录).在这种情况下,速率应该硬定义为1.
SELECT
r.value * IFNULL(AVG(fx.rate),1) as converted, AVG(fx.rate) as averageFx,
r.*, fx.*
FROM
foreign_exchange fx, monthly_revenue r, order_headers h
WHERE
fx.base IN (SELECT name FROM currencies WHERE id = r.currency_id) AND
r.order_header_id = h.id AND
fx.target = 'USD' AND
MONTH(fx.rate_date) = r.month AND
YEAR(fx.rate_date) = r.year AND
r.year = 2015
GROUP BY r.id
ORDER BY month ASC
Run Code Online (Sandbox Code Playgroud)
如果没有可用于FX的记录,则应该执行单独的子查询以获得最近一个月的平均费率.
任何输入将不胜感激.如果需要进一步的信息,请发表评论.
谢谢.
编辑 这是一个SQFiddle,它具有示例模式和突出问题的代码.
以下是计算特定货币和月初的交易所的函数的近似值:
DELIMITER //
CREATE FUNCTION MonthRate(IN _curr CHAR(3) CHARACTER SET ascii,
IN _date DATE)
RETURNS FLOAT
DETERMINISTIC
BEGIN
-- Note: _date must be the first of some month, such as '2015-02-01'
DECLARE _avg FLOAT;
DECLARE _prev FLOAT;
-- First, try to get the average for the month:
SELECT AVG(rate) INTO _avg FROM foreign_exchange
WHERE base = _curr
AND target = 'USD'
AND rate_date >= _date
AND rate_date < _date + INTERVAL 1 MONTH;
IF _avg IS NOT NULL THEN
RETURN _avg;
END;
-- Fall back onto the last rate before the month:
SELECT rate INTO _prev
FROM foreign_exchange
WHERE base = _curr
AND target = 'USD'
AND rate_date < _date
ORDER BY _date
LIMIT 1;
IF _prev IS NOT NULL THEN
RETURN _prev;
END;
SELECT "Could not get value -- ran off start of Rates table";
END;
DELIMITER ;
Run Code Online (Sandbox Code Playgroud)
可能存在语法错误等.但希望您可以使用它.
从其余代码调用函数应该很容易.
为了性能,这将是有益的:
INDEX(base, target, rate_date, rate)
Run Code Online (Sandbox Code Playgroud)
创建一个视图:
create view avg_rate as
select base, target, year(fx.rate_date) year, month(fx.rate_date) month,
avg(rate) avg_rate
from foreign_exchange group by base, target
Run Code Online (Sandbox Code Playgroud)
加入两次,一次是当前月份,一次是上个月
select r.id, r.month,
r.value * avg(coalesce(cr.avg_rate, pr.avg_rate, 1)) converted,
avg(coalesce(cr.avg_rate, pr.avg_rate), 0) rate
from monthly_revenue r, avg_rate cr, avg_rate pr, order_headers h
where
r.year = 2015 and
cr.year = r.year and cr.month = r.month and cr.target='USD' and
pr.year = r.year and pr.month = r.month - 1 and pr.target='USD' and
r.order_header_id = h.id
group by r.id
order by r.month
Run Code Online (Sandbox Code Playgroud)
另外,我个人不喜欢这种编写查询的方式,更喜欢使用显式联接,因为您可以对条件进行逻辑分组,并且不会在 where 子句中出现混乱。IE:
...
from monthly_revenue r
inner join order_headers h on r.order_header_id = h.id
left join avg_rate cr on cr.year = r.year and cr.month = r.month and cr.target='USD'
left join avg_rate pr on pr.year = r.year and pr.month = r.month - 1 and pr.target='USD'
where r.year = 2015
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
327 次 |
| 最近记录: |