Django 使用 Coalesce 从同一模型中获取最大长度值

Django get max length value from same model with Coalesce

我正在尝试使用 ORM 编写以下原始查询。我不确定是否可能。

select first_name,
       middle_name,
       COALESCE(middle_name, (
           select middle_name
           from contacts c2
           where c2.first_name = c1.first_name
             and c2.last_name = c1.last_name
             and c2.middle_name is not null
           order by length(c2.middle_name) desc
           limit 1
       )
           ) expected,
       last_name
from contacts c1

预期结果如下,如果middle_name为null,从另一条具有相同first_name和last_name的记录中获取中间名。

id| first_name | middle_name | expected | last_name
1 | ahmet      |   <NULL>    |  burak   |   ozyurt
2 | ahmet      |   burak     |  burak   |   ozyurt
class Contact(models.Model):
    first_name = models.CharField(max_length=250)
    last_name = models.CharField(max_length=250, null=True, blank=True)
    middle_name = models.CharField(max_length=250, null=True, blank=True)

数据库:Postgres
Django 版本:3.12

通过使用django ORM,您可以使用以下代码执行相同的查询

from django.db import models
from django.db.models.functions import Coalesce, Length

matched_middle_name_queryset = Contact.objects.filter(
    first_name=models.OuterRef("first_name"),
    last_name=models.OuterRef("last_name"),
    middle_name__isnull=False,
).annotate(
    middle_name_len=Length("middle_name")
).order_by("-middle_name_len").values("middle_name")[:1]

result = Contact.objects.annotate(
    matched_middle_name=models.Subquery(matched_middle_name_queryset)
    expected=Coalesce(
        models.F("middle_name")
        models.F("matched_middle_name"),
    ).values("id", "first_name", "middle_name", "expected", "last_name")
)

解释

  1. models.OuterRef用于从子查询的父查询中引用字段。
  2. -前缀在order_by("-middle_name_len")是降序
  3. .values("middle_name") 仅用于选择 middle_name 个值。
  4. 切片[:1]是为了限制子查询的结果为一个

小贴士

  • 您可以使用 result.query 检查 ORM 将为您生成什么查询。