0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

MySQL ✕ DjangoのORMで、サブクエリでGROUP BYとかDISTINCTとかにハマる

Last updated at Posted at 2021-06-14

やろうとしたこと

例えば、次のような共通部品から、優先(priorityが小さいもの)して使うものを抽出したい。

products

id
1
2
3

common_parts

product_id priority name
1 1 ネジa
2 1 ネジb
1 2 ネジA
2 2 ネジB
1 3 ネジα

このとき、MySQL ✕ DjangoのORMでは色々制約が合って、なかなか満足行くものがすぐに作れなかった。

NGパターン

group_byでいいじゃない?

        queryset = Products.objects.all().annotate(
            common_part=Subquery(
                CommonParts.objects.filter(
                    product_id=OuterRef('pk'),
                ).order_by('priority').group_by('product_id').values('name')
            ),
        )

DjangoのORMに、group_byは無いそうです(;・∀・)

distinctで、product_idを指定すればいいじゃない?

        queryset = Products.objects.all().annotate(
            common_part=Subquery(
                CommonParts.objects.filter(
                    product_id=OuterRef('pk'),
                ).order_by('priority').distinct('product_id').values('name')
            ),
        )

MySQLが、distinctに引数は指定できないそうです(;・∀・)
PostgreSQLはできるみたいな情報は在った気がする。

OKパターン

        queryset = Products.objects.all().annotate(
            common_part=Subquery(
                CommonParts.objects.filter(
                    product_id=OuterRef('pk'),
                ).order_by('priority')[:1].values('name')
            ),
        )

順番つけた後に、1つ目のものを取ってくる。
まぁ、はじめにこれがすぐ思いつく人も多いか(´Д`)…

ポイント

  • [1]ではなく[:1]にすることで、共通部品がなくてもエラーにならないようにした。

所感

後から考えると、すぐにOKパターンが思いついても良さそうなもんだなと思ったけど、思考の流れ的に「こういう場合Group By使うよな」から始まってたからなかなかたどり着くのに時間がかかった。。
distinctについても、結構

MyModel.objects.all().values_list('hoge', flat=True).order_by('hoge').distinct()

で出来る話はたくさん出てきたけど、使いたい項目とdistinctしたい項目が違うことで悩まされた。(↑はPostgreSQLではdistinctに引数指定できるのに、MySQLではできないけどどうするのっていう対処法だった)

今回わかったgroup_byはDjangoのORMにないことと、distinctを引数に使えないという仕様は覚えておこうと思って残しておく。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?