【问题标题】:Django. Database query: distinct for one field姜戈。数据库查询:一个字段不同
【发布时间】:2011-12-24 13:42:32
【问题描述】:

我在 DB 中有以下字段和数据:

FirstName     LastName    Date

John          Davis       10-10-2011
Joe           Gray        20-09-2011
Ann           Davis       03-04-2010
Ann           Bovis       01-04-2010

如何从具有最新日期和唯一姓氏的 DB 3 项目中选择结果中包含的所有其他字段。这意味着如果结果中包含多个 LastName Davis 的项目应该只有一个具有最新日期的项目。 甚至不知道如何在纯 SQL 上做到这一点 - Django 看起来根本不可能。

EDIT1。 SQL 查询。

我在纯 SQL 上编写查询:

SELECT TOP 3 *
FROM peopleTable as a1
WHERE  (select count(*)FROM peopleTable as a2 where a2.LastName=a1.LastName and a2.Date > a1.Date)<=0
ORDER by Date desc

我想如果我在 django 中像纯 SQL 一样使用这个查询会更好。

【问题讨论】:

    标签: sql django django-models django-queryset django-mssql


    【解决方案1】:

    你可以这样做:

    最新日期和唯一姓氏

    所有其他字段

    但你不能两者都做。如果您想获取姓氏 Davis 的最新日期,应该检索哪些其他字段,firstname=John 或 firstname=Ann?

    猜测您希望结果如下所示:

    FirstName     LastName    Date
    
    John          Davis       10-10-2011
    Joe           Gray        20-09-2011
    Ann           Bovis       01-04-2010
    

    Ann Davis 的那一排没有了,因为她不是最近的 Davis。对吗?

    在这种情况下,您的原始 SQL 类似于:

    SELECT FirstName, LastName, Date
    FROM
    Table T1
    WHERE
    NOT EXISTS (
    SELECT * FROM Table T2 WHERE T2.LastName=T1.LastName AND T2.Date > T1.Date
    )
    

    您可以使用Item.objects.raw() 选项在Django 中编写。你也可以使用extra(where=…)

    【讨论】:

    • 原始 SQL 没问题。我在问题的编辑中写了它。效果很好。因此,如果@second 建议调查 django 聚合器不起作用,我将使用原始 SQL。你的意思是我不能两者都做?你刚刚写了两个都做的 SQL 查询,我也写了。
    • 我想这是让我失望的例子。以这种方式按姓氏对人进行分组很奇怪。
    【解决方案2】:

    请参阅aggregation 上的文档

    猜你想要类似的东西

    Item.objects.values("lastname").annotate(
        date=Max("date"), firstname=Max("firstname"
        ).order_by()
    

    您必须对聚合查询中包含的所有字段进行聚合或分组。在您的情况下,您需要 max(data) 和 group_by 姓氏。您还必须为名字选择一些聚合,比如 max

    请注意,似乎有一个 postgres bug 用于聚合字符域

    【讨论】:

    • 好的,决定使用 raw() 方法。它更容易并且仍然适用于 django 模型。感谢您介绍聚合。
    【解决方案3】:

    你不能真正通过查询来做到这一点;这对 SQL 来说逻辑太多了。不过,基于字典键的唯一性,只要稍加巧思,就能得到你想要的。

    首先,获取按日期升序排序的查询集。这可能看起来违反直觉,因为您想要最新的日期,但在接下来的步骤中会有意义:

    qs = SomeModel.objects.order_by('date')
    

    接下来,我们将在列表推导中使用它来创建 (key, value) 元组(在 Python 3+ 中,您实际上可以进行字典推导,但由于我认识的人并不多,实际上使用 Python 3+,我以这种方式详细说明):

    qs_list = [(item.last_name, item) for item in qs]
    

    最后,我们将这个元组列表转换成字典:

    items = dict(qs_list)
    

    您现在将拥有一个字典,其中每个 last_name 键都是唯一的。由于字典键必须是唯一的,每个重复的姓氏的最后一个值就是实际出现的那个。由于列表是按日期升序排列的,最后一个值是“最新的”。

    您可以将此字典转换回一个直接列表或直接迭代它。唯一的问题是您不再处理 QuerySet,因此您无法执行任何进一步的过滤器等操作。请记住这一点,并在您完全构建查询后最后执行这些步骤。

    当然,如果您愿意的话,您可以将所有这些作为一个班轮完成:

    items = dict([(item.last_name, item) for item in SomeModel.objects.order_by('date')])
    

    【讨论】:

    • 因此,如果我在 DB 中有 50 000 个项目,所有项目都将在此行的内存中加载:qs_list = [(item.last_name, item) for item in qs]?我想在 DB 中做尽可能多的工作。
    • 哦等等,错过了他想要所有其他字段的部分。什么?
    • 我如何从具有最新日期和唯一姓氏的 DB 3 项目中选择结果中包含所有其他字段。
    猜你喜欢
    • 2012-05-29
    • 2020-08-05
    • 2016-05-02
    • 2018-03-02
    • 2021-03-10
    • 1970-01-01
    • 2021-03-14
    • 2013-02-22
    • 1970-01-01
    相关资源
    最近更新 更多