【问题标题】:How to join on multiple column with a groupby in Django/Postgres如何在 Django/Postgres 中使用 group by 加入多个列
【发布时间】:2021-11-15 07:57:12
【问题描述】:

我有以下表格需要加入日期和货币:

class Transaction(models.Model):
    description = models.CharField(max_length=100)
    date = models.DateField()
    amount = models.FloatField()
    currency = models.ForeignKey(Currency, on_delete=models.PROTECT)


class ExchangeRate(models):
    currency = models.ForeignKey(Currency, on_delete=models.PROTECT)
    rate = models.FloatField()
    date = models.DateField()   

我需要同时加入日期和货币列,将汇率和金额相乘得到“converted_amount”。然后我需要按日历月对所有交易进行分组并总结“converted_amount”。

这可以使用 Django ORM 还是我需要直接使用 SQL?如果是这样,我该如何在 Postgres 中执行此操作?

【问题讨论】:

  • 你可以在这里添加模型吗???
  • “获取不同货币的总价值”是什么意思?什么的总价值:一笔交易,几笔交易?
  • @MohamedBeltagy 我添加了更多细节

标签: django postgresql


【解决方案1】:

假设"Exchange rates"表中的Dates独立于Transactions表中的dates,那么对于每一个Transaction,对应的"Exchange rates".Date是最晚的日期,小于等于Transactions.Date,你可以在 Postgres 中试试这个:

在 Postgres 中:

SELECT t.Currency
     , date_trunc('month', t.Date) AS period_of_time
     , sum(t.amount * er.Rate) AS sum_by_currency_by_period_of_time
  FROM Transactions AS t
 CROSS JOIN LATERAL
     ( SELECT DISTINCT ON (er.Currency) er.Rate
         FROM "Exchange rates" AS er
        WHERE er.Currency = t.Currency
          AND er.Date <= t.Date
        ORDER BY er.Date DESC
     ) AS er
 GROUP BY t.Currency, date_trunc('month', t.Date)

【讨论】:

  • 哇,谢谢爱德华。我认为这样的事情在 Django ORM 中是不可能的?
  • @Kritz,对不起,我没有 Django 的能力......我希望你能找到一种方法来插入 sql 代码,或者从 Django 调用 postgres 函数。
  • 没问题 - 感谢您的帮助!
【解决方案2】:

假设您的 Currency 模型有一个符号列(根据您的需要进行更改),您可以使用以下 Django 语句来实现:

from your.models import Transaction, ExchangeRate
from django.db.models.functions import ExtractMonth
from django.db.models import Sum, F, Subquery, OuterRef

rates = ExchangeRate.objects.filter(
    currency=OuterRef("currency"), date__lt=OuterRef("date")
).order_by("-date")

Transaction.objects.annotate(
    month=ExtractMonth("date"),
    rate=Subquery(rates.values("rate")[:1]),
    conversion=F("amount") * F("rate"),
).values("currency__symbol", "month").annotate(sum=Sum("conversion")).order_by(
    "currency", "month"
)

这将产生如下列表:

{'currency__symbol': '$', 'month': 2, 'sum': 105.0},...

子查询语句将注释最后找到的比较日期的汇率。确保每笔交易都有一个汇率(汇率日期早于交易日期)。

【讨论】:

    猜你喜欢
    • 2022-01-06
    • 2016-06-08
    • 1970-01-01
    • 1970-01-01
    • 2015-02-13
    • 2019-03-19
    • 2011-01-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多