sql >> データベース >  >> RDS >> Mysql

OuterRefを使用した単純なサブクエリ

    この例の問題の1つは、 queryset.count()を使用できないことです。 .count()であるため、サブクエリとして クエリセットを評価してカウントを返そうとします。

    したがって、正しいアプローチは Count()を使用することだと思うかもしれません。 代わりは。多分このようなもの:

    Post.objects.annotate(
        count=Count(Tag.objects.filter(post=OuterRef('pk')))
    )
    

    これは2つの理由で機能しません:

    1. タグ querysetはすべてのTagを選択します フィールド、 Count 1つのフィールドのみをカウントできます。したがって: Tag.objects.filter(post =OutsideRef('pk'))。only('pk') 必要です( tag.pkを頼りに選択するには 。

    2. カウント それ自体はサブクエリではありません クラス、 Count Aggregateです 。したがって、 Countによって生成された式 Subqueryとして認識されません ( OutsideRef サブクエリが必要です)、 Subqueryを使用して修正できます 。

    1)と2)に修正を適用すると、次のようになります。

    Post.objects.annotate(
        count=Count(Subquery(Tag.objects.filter(post=OuterRef('pk')).only('pk')))
    )
    

    ただし 生成されているクエリを検査する場合:

    SELECT 
        "tests_post"."id",
        "tests_post"."title",
        COUNT((SELECT U0."id" 
                FROM "tests_tag" U0 
                INNER JOIN "tests_post_tags" U1 ON (U0."id" = U1."tag_id") 
                WHERE U1."post_id" = ("tests_post"."id"))
        ) AS "count" 
    FROM "tests_post" 
    GROUP BY 
        "tests_post"."id",
        "tests_post"."title"
    

    GROUP BYに気付くでしょう 句。これは、 COUNTが原因です 集計関数です。現在、結果には影響しませんが、他の場合には影響する可能性があります。そのため、 docs 集計がsubqueryに移動される別のアプローチを提案します の特定の組み合わせを介して +注釈 +

    Post.objects.annotate(
        count=Subquery(
            Tag.objects
                .filter(post=OuterRef('pk'))
                # The first .values call defines our GROUP BY clause
                # Its important to have a filtration on every field defined here
                # Otherwise you will have more than one group per row!!!
                # This will lead to subqueries to return more than one row!
                # But they are not allowed to do that!
                # In our example we group only by post
                # and we filter by post via OuterRef
                .values('post')
                # Here we say: count how many rows we have per group 
                .annotate(count=Count('pk'))
                # Here we say: return only the count
                .values('count')
        )
    )
    

    最後に、これにより次のものが生成されます:

    SELECT 
        "tests_post"."id",
        "tests_post"."title",
        (SELECT COUNT(U0."id") AS "count" 
                FROM "tests_tag" U0 
                INNER JOIN "tests_post_tags" U1 ON (U0."id" = U1."tag_id") 
                WHERE U1."post_id" = ("tests_post"."id") 
                GROUP BY U1."post_id"
        ) AS "count" 
    FROM "tests_post"
    


    1. MySqlは大規模なデータベースに適していますか?

    2. 自動バキュームがバキュームしない場合

    3. 文字列リテラルが長すぎます-Oracle11gr2で長いxmlデータをclobデータ型に割り当てる方法

    4. SqlDataSourceEnumerator.Instance.GetDataSources()は、ローカルSQLServer2008インスタンスを検索しません