使用来自其他表的汇率将价格转换为总和并计算平均值。

huangapple go评论67阅读模式
英文:

convert prices with exchangerates from other table SUM and get AVG

问题

我的想法是:

服务器:使用最新的MariaDB的Ubuntu

这是一个投资组合算法,用户可以用美元之类的货币购买股票,但他的投资组合可以以欧元计价,因此需要将价值转换。

  1. 我需要一个接近创建日期的汇率,如果没有,则使用之前的日期的汇率。
  2. 将剩余金额乘以转换为我想要的货币的价格求和(在这种情况下,为了更容易理解,它将是1的汇率,目标货币将通过查询提供,在这种情况下是2)。
  3. 结果应该除以剩余金额的总和,以获得正确的购买价格,即平均价格。

我已经更新了数据,以使测试更简单,例如,源货币现在与目标货币相同,因此计算是1:1的。

SQL Fiddle在这里:http://sqlfiddle.com/#!9/8c7fc59/11
运行针对我的数据库的查询的结果:

https://pastebin.com/pSerHN0j

前两个结果是我想要的,第三个来自jmvcollaborator,其中平均买入价格是正确的,但金额加倍了。

具有更多数据的SQL导出:

https://pastebin.com/d1aVX2wm

更新的问题:

子查询的解决方案有效,但性能不是最佳的,所以我目前正在寻找一个没有子查询的解决方案。

在我的信息分区之后,应该有一个解决方案,但这不是我的专业知识,所以也许有人可以在这里帮助我。

英文:

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.

  1. I need a exchange rate near the created date, if not use a rate from date before.
  2. 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.
  3. 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; 

huangapple
  • 本文由 发表于 2023年5月28日 23:22:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76352194.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定