Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Truy vấn con đơn giản với OuterRef

Một trong những vấn đề với ví dụ của bạn là bạn không thể sử dụng queryset.count() như một truy vấn con, bởi vì .count() cố gắng đánh giá bộ truy vấn và trả về số lượng.

Vì vậy, người ta có thể nghĩ rằng cách tiếp cận phù hợp sẽ là sử dụng Count() thay thế. Có thể như thế này:

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

Điều này sẽ không hoạt động vì hai lý do:

  1. Thẻ Tag bộ truy vấn chọn tất cả Tag các trường, trong khi Count chỉ có thể tính trên một lĩnh vực. Do đó:Tag.objects.filter(post=OuterRef('pk')).only('pk') là cần thiết (để chọn đếm trên tag.pk ).

  2. Count bản thân nó không phải là Subquery lớp, Count là một Aggregate . Vì vậy, biểu thức được tạo bởi Count không được công nhận là Subquery (OuterRef yêu cầu truy vấn con), chúng tôi có thể khắc phục điều đó bằng cách sử dụng Subquery .

Áp dụng các bản sửa lỗi cho 1) và 2) sẽ tạo ra:

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

Tuy nhiên nếu bạn kiểm tra truy vấn đang được tạo:

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"

bạn sẽ thấy GROUP BY mệnh đề. Điều này là do COUNT là một hàm tổng hợp. Hiện tại nó không ảnh hưởng đến kết quả, nhưng trong một số trường hợp khác thì có thể. Đó là lý do tại sao tài liệu đề xuất một cách tiếp cận khác, trong đó tập hợp được chuyển vào subquery thông qua sự kết hợp cụ thể của các giá trị Tag + annotate + values :

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')
    )
)

Cuối cùng điều này sẽ tạo ra:

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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm cách nào để tổng hợp các cột trên nhiều bảng trong MySQL?

  2. Hàm SELECT trong MySQL để tính tổng dữ liệu hiện tại

  3. Đặt hàng theo ngày (varchar)?

  4. Hàm MySQL để tìm số ngày làm việc giữa hai ngày

  5. SQLSTATE [HY093]:Số tham số không hợp lệ:tham số không được xác định