【问题标题】:Execute GROUP BY HAVING in django orm on a many to many relationship?在多对多关系上在 django orm 中执行 GROUP BY HAVING?
【发布时间】:2020-09-08 02:17:19
【问题描述】:

我有以下型号:

class Tag(models.Model):
    name = models.CharField(max_length=255, unique=True, default="")


class Problem(models.Model):
    tags = models.ManyToManyField(Tag, related_name="problems")
    index = models.CharField(max_length=5)
    name = models.CharField(max_length=255)
    rating = models.IntegerField(default=-1)

我要执行以下查询:

SELECT
    "p"."index",
    "p"."name",
    "p"."rating"
FROM
    problem p
WHERE
    p.id IN (
        SELECT
            pt.problem_id
        FROM
            problem_tags pt
            JOIN tag t ON pt.tag_id = t.id
        WHERE
            t.name IN ('math', 'binary search', 'implementation')
        GROUP BY
            pt.problem_id
        HAVING
            COUNT(*) = 3
    )
ORDER BY
    rating,
    index;

我用过类似的东西:

Problem.tags.through.objects.values("problem_id").filter(
    tag__name__in=("math", "binary search", "implementation")
).annotate(count=models.Count("*")).filter(count=3)

但它会发出以下查询,其中SELECT 中的第一个COUNT(*) 是多余且错误的:

SELECT
    "api_problem_tags"."problem_id",
    COUNT(*) AS "count"
FROM
    "api_problem_tags"
    INNER JOIN "api_tag" ON ("api_problem_tags"."tag_id" = "api_tag"."id")
WHERE
    "api_tag"."name" IN ('math', 'binary search', 'implementation')
GROUP BY
    "api_problem_tags"."problem_id"
HAVING
    COUNT(*) = 3

如何摆脱第一个COUNT(*)

【问题讨论】:

    标签: python sql django django-models django-orm


    【解决方案1】:

    我想你可以使用Countfilter 参数。

    Problem.objects.annotate(
       tag_count=Count(
           'tags',
           filter=Q(tags__name__in=["math", "binary search", "implementation"],
       )
    ).filter(tag_count=3)
    

    【讨论】:

    • 它不会产生所需的查询,我怀疑它适合用例,但与提供的相关查询相比几乎需要 3 次执行。
    猜你喜欢
    • 1970-01-01
    • 2012-09-18
    • 2018-01-14
    • 1970-01-01
    • 1970-01-01
    • 2021-08-01
    • 2019-02-28
    • 1970-01-01
    相关资源
    最近更新 更多