Wednesday, February 28, 2018

Window expression inside Subquery

-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEgp5wx8+ggeLmQKiikpDftiGHlegFAlqXn1QACgkQkpDftiGH
lejjJA//cJexc9FXOkehvJplkUStDzazus/k2bqu07MzTF4xzLsKQOKXccTtnZH8
GRehFK2G5xKFPWoaOneAm1LtK0ycxTBsSd3imnB/VF9Vvv13c1P4PZ9NTVZ1GTiA
czBiP4VnUnbGUVraoHGWjPZMNrhcZfL9+eeoKO8tblQw3Hve9W2gnmEwvT7IRzlA
axGm8cJIu0nJsEyLZqgFvboC9SPAx2EqFAfvOLc3eGxQbXxcDuwzHQQ3YGv5Mjy1
PzffUszneNBQcxDyCxqXp1h6pXdbgmCbJC/KK+/SAsSFnXfvpORxdP7/byx+4tvL
rd84yV3ZpRaTSJ8pBKcYv0WviWFQHaaDmWsYDXAkBmsR5/SQHnqtrh/3GR8wKMDI
f7hyp/0kUhlz5OPhV89jJ/pLmDycivH70+wehPl6S4s/un9M4cS2V2GQ3qnT9IY/
oTsiAg1vomDzdUJdDOHmPxxhTz3jUcHEXs+HFoi6UiDoe9x7iyr1AaLhRHAp9sWF
Ntkh5t6f2dqP6ZbkOqsIprGCUHK0i0NqsbdlXQoaxrLi+kW7i9ohZXI1pNEgjnFM
9u5QY7d4NRWyxms0kQeV2P4y4wv+Wx+0FQdOxC/Ar46qkperkC0WytyVBCSHj0W2
jFYkdUv/FzTEsTuLLbWGtlOwIYHzykW1ftbij8nWPKdSumrN+aE=
=Uvn0
-----END PGP SIGNATURE-----
Hey folks,
I'm getting an AttributeError: 'NoneType' object has no attribute 'relabeled_clone'
when using Window expression inside Subquery:

Message.objects
.filter(pk__in=Subquery(
    Message.objects
    .annotate(latest_pk=Window(
        expression=FirstValue('pk'),
        partition_by=[F('conversation_id')],
        order_by=F('date').desc(),
    ))
    .values('latest_pk')
))

I would like to translate this SQL statement to Django ORM:

SELECT
  "conversations_message"."id",
  "conversations_message"."conversation_id",
  "conversations_message"."author_id",
  "conversations_message"."content",
  "conversations_message"."date"
FROM "conversations_message"
WHERE "conversations_message"."id" IN (
  SELECT first_value("id") OVER (PARTITION BY "conversation_id" ORDER BY "date" DESC)
  FROM conversations_message
)

I tested SQL statement and it works. I'm trying to select all conversations in DB
and prefetch latest message in each conversation.


I've found this note about using aggregates in Subqueries:
but it doesn't seem to be related to my case.

I could however replace Window function with Max aggregate:

Message.objects.filter(pk__in=Subquery(
    Message.objects
        .order_by()
        .values('conversation')
        .annotate(latest=Max('id'))
        .values('latest')
    )
)

This works too, but I don't feel very comfortable using Max on `id`.


Related question: Is there a better way to prefetch latest related items? Both in Django and raw SQL.

Thanks in advance!


Cheers,
   Tom

No comments:

Post a Comment