【问题标题】:fetching single child row based on a max value using Django ORM使用 Django ORM 根据最大​​值获取单个子行
【发布时间】:2010-10-30 05:23:51
【问题描述】:

我有一个模型“Market”,它与另一个模型“Contract”有一对多的关系:

class Market(models.Model):
    name = ...
    ...

class Contract(models.Model):
    name= ...
    market = models.ForeignKey(Market, ...)
    current_price = ...

我想获取 Market 对象以及每个合约的最高价格。这就是我通过原始 SQL 实现的方式:

SELECT M.id as market_id, M.name as market_name, C.name as contract_name, C.price 
as price from pm_core_market M INNER JOIN
    (SELECT market_id, id, name, MAX(current_price) as price 
        FROM pm_core_contract GROUP BY market_id) AS C
ON M.id = C.market_id

有没有办法在不使用 SQL 的情况下实现这一点?如果有,在性能方面应该首选哪一个?

【问题讨论】:

    标签: sql django inner-join django-orm


    【解决方案1】:

    Django 1.1(当前为测试版)为数据库 API 添加了 aggregation 支持。您的查询可以这样完成:

    from django.db.models import Max, F
    
    Contract.objects.annotate(max_price=Max('market__contract__current_price')).filter(current_price=F('max_price')).select_related()
    

    这会生成以下 SQL 查询:

    SELECT contract.id, contract.name, contract.market_id, contract.current_price, MAX(T3.current_price) AS max_price, market.id, market.name
    FROM contract LEFT OUTER JOIN market ON (contract.market_id = market.id) LEFT OUTER JOIN contract T3 ON (market.id = T3.market_id)
    GROUP BY contract.id, contract.name, contract.market_id, contract.current_price, market.id, market.name
    HAVING contract.current_price =  MAX(T3.current_price)
    

    API 使用额外的连接而不是子查询(就像您的查询一样)。很难判断哪个查询更快,尤其是在不了解数据库系统的情况下。我建议你做一些基准测试并做出决定。

    【讨论】:

    • 我会假设子查询比两个 JOIN 更有效,但你是对的,不应该假设;对其进行基准测试并查看。
    • 艾曼,谢谢!作为一个 Django 新手,我花了一段时间才让它工作 :) 我对声明中的过滤器有一个疑问:有可能发生多份合约的价格相等的 - 不太可能 - 事件。如果是这样,查询将全部获取它们,为一个市场提供多个合约,对吗?
    • @ozgur - 事实上,如果两个合约的价格相同(也恰好是最高价),那么两者都会被退回。
    • 有解决办法吗?由于市场的性质,当一个初始化时,其合约的价格可能很容易相等!
    • @ozgur - 我认为使用 GROUP BY(如您的查询)和 Django 数据库 API 过滤重复项是不可能的。但是,您可以迭代结果并自己删除重复项。这对你有用吗?
    猜你喜欢
    • 1970-01-01
    • 2015-11-21
    • 2022-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多