英文:
convert prices with exchangerates from other table SUM and get AVG
问题
我的想法是:
服务器:使用最新的MariaDB的Ubuntu
这是一个投资组合算法,用户可以用美元之类的货币购买股票,但他的投资组合可以以欧元计价,因此需要将价值转换。
- 我需要一个接近创建日期的汇率,如果没有,则使用之前的日期的汇率。
- 将剩余金额乘以转换为我想要的货币的价格求和(在这种情况下,为了更容易理解,它将是1的汇率,目标货币将通过查询提供,在这种情况下是2)。
- 结果应该除以剩余金额的总和,以获得正确的购买价格,即平均价格。
我已经更新了数据,以使测试更简单,例如,源货币现在与目标货币相同,因此计算是1:1的。
SQL Fiddle在这里:http://sqlfiddle.com/#!9/8c7fc59/11
运行针对我的数据库的查询的结果:
前两个结果是我想要的,第三个来自jmvcollaborator,其中平均买入价格是正确的,但金额加倍了。
具有更多数据的SQL导出:
更新的问题:
子查询的解决方案有效,但性能不是最佳的,所以我目前正在寻找一个没有子查询的解决方案。
在我的信息分区之后,应该有一个解决方案,但这不是我的专业知识,所以也许有人可以在这里帮助我。
英文:
What my idea is:
Server: Ubuntu with latest MariaDB
It's a portfolio algo, the user can buy stocks in a currency like USD but his portfolio can be in EURO, so the values must be converted.
- I need a exchange rate near the created date, if not use a rate from date before.
- SUM the amounts_lefts * price converted to currency i want (in this case for easier understand it will be a rate of 1, the target currency will submit over query in this case 2.
- the result should be divides though the sum of amounts_left to get the correct buyIN aka AVG price.
Ive updated the data to make things more simple for test, like currency of source is now the same as target, so the calculation is 1:1
SQL Fiddle is here: http://sqlfiddle.com/#!9/8c7fc59/11
Results running against my DB with querys
https://pastebin.com/pSerHN0j
the first 2 results are what i want, the 3. one is from jmvcollaborator where the AVG BuyIN is correct but the amounts are doubled
SQL Export with more Data
https://pastebin.com/d1aVX2wm
Updated Question:
The solution over Subquery is working, but this Method is not the best in performance, so im currently looking for a solution without this.
After my Information partitions over should be here a solution, but this is not my kind of knowledge, so maybe anyone can help me here.
答案1
得分: 1
以下是您要翻译的内容:
我会在这里写一些发现,首先我想要双重确认你的第一个查询是否有效,请确认:
SELECT SUM(amounts_left*price)/SUM(amounts_left) as eBuyIN
FROM transactions as t
WHERE 1 GROUP BY currency_id,broker_id,portfolio_id,instrument_id;
如果不起作用,那么让我分享一些有关我们已经使其工作的查询的发现:
SELECT
SUM(price)/SUM(mleft)
FROM(
SELECT
`instrument_id`,
amounts_left AS mleft,
amounts_left * price * (
SELECT `rate`
FROM `currency_exchanges`
WHERE `from_currency_id` = t.currency_id
AND `to_currency_id` = 2
AND `date` <= t.created
ORDER BY `date` DESC LIMIT 1
) AS price
FROM `transactions` AS `t`
WHERE `action` = 1
AND `portfolio_id` = 128
) a
查询成本为2.72,因为它执行了全表扫描,由于嵌套查询。我尝试了一种不同的方法,使用CTE和OVER PARTITION BY,查询成本为0.35,由于分区内的列是非唯一键查找,因此比以前的查询要快得多,下面是CTE代码:
WITH
cte AS (
SELECT ROW_NUMBER() OVER(PARTITION BY t.currency_id,t.broker_id,t.portfolio_id,t.instrument_id ORDER BY amounts_left DESC
) AS rowNumber,
SUM(amounts_left) OVER(PARTITION BY t.currency_id,t.broker_id,t.portfolio_id,t.instrument_id
ORDER BY amounts_left DESC ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) AS amountsleftT,
SUM(amounts_left*price) OVER(PARTITION BY t.currency_id,t.broker_id,t.portfolio_id,t.instrument_id
ORDER BY amounts_left DESC ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) AS priceT
FROM currency_exchanges AS ce
JOIN transactions AS t
ON from_currency_id = t.currency_id
AND to_currency_id = 2
AND ce.date <= t.created
AND action = 1 and portfolio_id = 128
)
Select priceT/amountsleftT as Total from cte where rowNumber = 1;
我建议添加更多数据,以便可以测试许多不同的情况,您可以继续在fiddle上工作并分享链接。
希望我有些帮助。
**更新** 使用Over Partition By的查询已更新,因为聚合错误。**重要提示**:性能仍然优于其他方法。以下是有效的查询:
WITH cte AS
(
select
instrument_id,
ROW_NUMBER() OVER(PARTITION BY t.currency_id,t.broker_id,t.portfolio_id,t.instrument_id) AS rowNumber,
Sum(amounts_left* price *ce.rate) OVER(PARTITION BY t.currency_id,t.broker_id,t.portfolio_id,t.instrument_id) AS priceSum,
Sum(amounts_left) OVER(PARTITION BY t.currency_id,t.broker_id,t.portfolio_id,t.instrument_id) amountsleftSum
from transactions t left join
(select ce.*, row_number() over (partition by from_currency_id order by date desc) as seqnum
from currency_exchanges ce
where
to_currency_id = 2
order by ce.date desc
) ce
on ce.from_currency_id = t.currency_id and seqnum = 1
WHERE
ce.date <= t.created
AND action = 1 AND amounts_left > 0 AND portfolio_id = 128
)
SELECT
priceSum/amountsleftSum as eBuyIN,
amountsleftSum AS amounts_left,
instrument_id
FROM cte
WHERE rownumber = 1;
希望这有所帮助。
英文:
I will write some findings here, first i would like to double check that your very first query works, please confirm:
SELECT SUM(amounts_left*price)/SUM(amounts_left) as eBuyIN
FROM transactions as t
WHERE 1 GROUP BY currency_id,broker_id,portfolio_id,instrument_id;
If it does not work then let me share some findings with regards of the query we got working which is:
SELECT
SUM(price)/SUM(mleft)
FROM(
SELECT
`instrument_id`,
amounts_left AS mleft,
amounts_left * price * (
SELECT `rate`
FROM `currency_exchanges`
WHERE `from_currency_id` = t.currency_id
AND `to_currency_id` = 2
AND `date` <= t.created
ORDER BY `date` DESC LIMIT 1
) AS price
FROM `transactions` AS `t`
WHERE `action` = 1
AND `portfolio_id` = 128
) a
The query cost is 2.72 since it perform a full table scan due the nested query. I took the freedom to try a different approach using CTE and OVER PARTITION BY and the query cost is 0.35 a non unique key look up due the columns inside the partition thus much faster that the previous query, here is the CTE code:
WITH
cte AS (
SELECT ROW_NUMBER() OVER(PARTITION BY t.currency_id,t.broker_id,t.portfolio_id,t.instrument_id ORDER BY amounts_left DESC
) AS rowNumber,
SUM(amounts_left) OVER(PARTITION BY t.currency_id,t.broker_id,t.portfolio_id,t.instrument_id
ORDER BY amounts_left DESC ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) AS amountsleftT,
SUM(amounts_left*price) OVER(PARTITION BY t.currency_id,t.broker_id,t.portfolio_id,t.instrument_id
ORDER BY amounts_left DESC ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) AS priceT
FROM currency_exchanges AS ce
JOIN transactions AS t
ON from_currency_id = t.currency_id
AND to_currency_id = 2
AND ce.date <= t.created
AND action = 1 and portfolio_id = 128
)
Select priceT/amountsleftT as Total from cte where rowNumber = 1;
I would suggest to add more data so many different cases can be tested you can keep working on the fiddle and share the link.
Hopefully i have helped somehow.
UPDATE query with Over Partition By was updated cause the aggregates were wrong. IMPORTANT: still the performance is better than the other approaches.
Here is the working query:
WITH cte AS
(
select
instrument_id,
ROW_NUMBER() OVER(PARTITION BY t.currency_id,t.broker_id,t.portfolio_id,t.instrument_id) AS rowNumber,
Sum(amounts_left* price *ce.rate) OVER(PARTITION BY t.currency_id,t.broker_id,t.portfolio_id,t.instrument_id) AS priceSum,
Sum(amounts_left) OVER(PARTITION BY t.currency_id,t.broker_id,t.portfolio_id,t.instrument_id) amountsleftSum
from transactions t left join
(select ce.*, row_number() over (partition by from_currency_id order by date desc) as seqnum
from currency_exchanges ce
where
to_currency_id = 2
order by ce.date desc
) ce
on ce.from_currency_id = t.currency_id and seqnum = 1
WHERE
ce.date <= t.created
AND action = 1 AND amounts_left > 0 AND portfolio_id = 128
)
SELECT
priceSum/amountsleftSum as eBuyIN,
amountsleftSum AS amounts_left,
instrument_id
FROM cte
WHERE rownumber = 1;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论