美文网首页
ORM聚合函数

ORM聚合函数

作者: 小吉头 | 来源:发表于2020-06-17 16:02 被阅读0次

    表关系如下:

    author
    +----+--------+-----+------------+
    | id | name   | age | email      |
    +----+--------+-----+------------+
    |  1 | 曹雪芹 |  35 | cxq@qq.com |
    |  2 | 吴承恩 |  28 | wce@qq.com |
    |  3 | 罗贯中 |  36 | lgz@qq.com |
    |  4 | 施耐庵 |  46 | sna@qq.com |
    +----+--------+-----+------------+
    book
    +----+----------+-------+-------+--------+-----------+--------------+----------+
    | id | name     | pages | price | rating | author_id | publisher_id | remark   |
    +----+----------+-------+-------+--------+-----------+--------------+----------+
    |  1 | 三国演义 |   987 |   108 |    4.8 |         3 |            1 | 三国演义 |
    |  2 | 水浒传   |   967 |   107 |   4.83 |         4 |            1 | 水浒传   |
    |  3 | 西游记   |  1004 |   105 |   4.85 |         2 |            2 | 西游记   |
    |  4 | 红楼梦   |  1007 |   109 |    4.9 |         1 |            2 | 红楼梦   |
    +----+----------+-------+-------+--------+-----------+--------------+----------+
    book_order
    +----+-------+---------+----------------------------+
    | id | price | book_id | create_time                |
    +----+-------+---------+----------------------------+
    |  1 |    95 |       1 | 2019-06-17 07:10:02.053000 |
    |  2 |    85 |       1 | 2020-06-17 07:10:02.053000 |
    |  3 |    88 |       1 | 2020-06-17 07:10:02.053000 |
    |  4 |    94 |       2 | 2020-06-17 07:10:02.053000 |
    |  5 |    93 |       2 | 2020-06-17 07:10:02.053000 |
    +----+-------+---------+----------------------------+
    

    平均值-AVG()

    使用aggregate和annotate执行AVG():

    from django.db.models import Avg
    from django.db import connection
    #查看所有书的平均价格
    result = Book.objects.aggregate(Avg("price"))
    print(result)
    print(connection.queries)
    >>>{'price__avg': 97.25}
    >>>SELECT AVG(`book`.`price`) AS `price__avg` FROM `book`
    
    #查看每本书的对应所有订单的平均售价
    result = Book.objects.annotate(avg = Avg("bookorder__price"))
    print(result)
    print(connection.queries)
    >>><QuerySet [<Book: Book object>, <Book: Book object>, <Book: Book object>, <Book: Book object>]>
    >>>SELECT `book`.`id`, `book`.`name`, `book`.`pages`, `book`.`price`, `book`.`rating`, `book`.`author_id`, `book`.`publisher_id`, AVG(`book_order`.`price`) AS `avg` FROM `book` LEFT OUTER JOIN `book_order` ON (`book`.`id` = `book_order`.`book_id`) GROUP BY `book`.`id` ORDER BY NULL LIMIT 21
    

    相同点:
    都可以执行聚合函数
    不同点:
    1、aggregate返回字典,示例中key默认是字段__avg,Book.objects.aggregate(avg = Avg("price"))可修改key,结果是{'avg': 97.25}
    2、annotate返回QuerySet对象,使用Book.objects.annotate(avg = Avg("bookorder__price")).values()查看结果,在模型对象属性里增加了平均值属性avg

    <QuerySet [{'publisher_id': 1, 'name': '三国演义', 'avg': 89.33333333333333, 'rating': 4.8, 'author_id': 3, 'pages': 987, 'price': 98.0, 'id': 1},{...},{...}]>
    

    3、从翻译的sql可以看出,aggregate不做分组,annotate使用group by分组。默认会根据分组字段进行排序。

    EXPLAIN
    SELECT `book`.`id`, `book`.`name`, `book`.`pages`, `book`.`price`, `book`.`rating`, `book`.`author_id`, `book`.`publisher_id`, AVG(`book_order`.`price`) AS `avg` FROM `book` LEFT OUTER JOIN `book_order` ON (`book`.`id` = `book_order`.`book_id`) GROUP BY `book`.`id` ORDER BY NULL LIMIT 21
    >>>Extra字段 Using temporary
    //去掉ORDER BY NULL查看执行计划
    >>>Using temporary; Using filesort
    

    orm翻译的sql使用了ORDER BY NULL禁用排序,提升查找效率。

    数量-Count()

    from django.db.models import Avg
    from django.db import connection
    
    
     #book表中共有多少个出版社
    result = Book.objects.aggregate(nums = Count("publisher_id"))
    print(result)
    print(connection.queries)
    >>>{'nums': 4}
    >>>SELECT COUNT(`book`.`publisher_id`) AS `nums` FROM `book`
    
     #book表中共有多少不重复的出版社
    result = Book.objects.aggregate(nums = Count("publisher_id",distinct=True))
    print(result)
    print(connection.queries)
    >>>{'nums': 2}
    >>>SELECT COUNT(DISTINCT `book`.`publisher_id`) AS `nums` FROM `book`
    
    #统计每本书的销量
    books = Book.objects.annotate(nums = Count("bookorder__id")) //bookorder_id可以简写成bookorder
    print(books.values())
    print(connection.queries)
    >>><QuerySet [{'pages': 987, 'publisher_id': 1, 'price': 98.0, 'id': 1, 'name': '三国演义', 'author_id': 3, 'rating': 4.8, 'nums': 3},{...},{...}]>
    >>>SELECT `book`.`id`, `book`.`name`, `book`.`pages`, `book`.`price`, `book`.`rating`, `book`.`author_id`, `book`.`publisher_id`, COUNT(`book_order`.`id`) AS `nums` FROM `book` LEFT OUTER JOIN `book_order` ON (`book`.`id` = `book_order`.`book_id`) GROUP BY `book`.`id` ORDER BY NULL LIMIT 21
    

    最大最小值-Max()、Min()

    aggregate()和annotate()可以加多个聚合函数

    #author年龄最大值和最小值
    result = Author.objects.aggregate(max = Max("age"),min = Min("age"))
    print(result)
    print(connection.queries)
    >>>{'max': 46, 'min': 28}
    >>>SELECT MAX(`author`.`age`) AS `max`, MIN(`author`.`age`) AS `min` FROM `author`
    
    #获取每本书售卖时的最高价和最低价
    result = Book.objects.annotate(max = Max("bookorder__price"),min = Min("bookorder__price"))
    print(result.values())
    print(connection.queries)
    >>><QuerySet [{'publisher_id': 1, 'min': 85.0, 'max': 95.0, 'author_id': 3, 'name': '三国演义', 'id': 1, 'rating': 4.8, 'pages': 987, 'price': 98.0},{...},{...}]>
    >>>SELECT `book`.`id`, `book`.`name`, `book`.`pages`, `book`.`price`, `book`.`rating`, `book`.`author_id`, `book`.`publisher_id`, MIN(`book_order`.`price`) AS `min`, MAX(`book_order`.`price`) AS `max` FROM `book` LEFT OUTER JOIN `book_order` ON (`book`.`id` = `book_order`.`book_id`) GROUP BY `book`.`id` ORDER BY NULL LIMIT 21
    

    求和-sum()

    aggregate:

    #2020年所有图书销售总额
    result = BookOrder.objects.filter(create_time__year=2020).aggregate(total = Sum("price"))
    print(result)
    print(connection.queries)
    >>>{'total': 360.0}
    >>>SELECT SUM(`book_order`.`price`) AS `total` FROM `book_order` WHERE `book_order`.`create_time` BETWEEN '2019-12-31 16:00:00' AND '2020-12-31 15:59:59.999999'
    

    因为setting里面设置了时区是Asia/Shanghai,migrations时数据库里面保存的其实是UTC时间,所以翻译结果是计算后的utc时间BETWEEN '2019-12-31 16:00:00' AND '2020-12-31 15:59:59.999999,如果要得到和数据库匹配的utc时间,可以修改setting时区为utc

    TIME_ZONE = 'UTC'
    USE_TZ = True
    

    修改后sql翻译结果:BETWEEN '2020-01-01 00:00:00' AND '2020-12-31 23:59:59.999999'
    annotate:

    #2020年每本书的销售总额
    result = Book.objects.filter(bookorder__create_time__year=2020).annotate(total=Sum("price"))
    >>><QuerySet [{'name': '三国演义', 'price': 98.0, 'id': 1, 'author_id': 3, 'total': 196.0, 'publisher_id': 1, 'rating': 4.8, 'pages': 987}, {...},{...}]>
    >>>SELECT `book`.`id`, `book`.`name`, `book`.`pages`, `book`.`price`, `book`.`rating`, `book`.`author_id`, `book`.`publisher_id`, SUM(`book`.`price`) AS `total` FROM `book` INNER JOIN `book_order` ON (`book`.`id` = `book_order`.`book_id`) WHERE `book_order`.`create_time` BETWEEN '2020-01-01 00:00:00' AND '2020-12-31 23:59:59.999999' GROUP BY `book`.`id` ORDER BY NULL LIMIT 21
    

    相关文章

      网友评论

          本文标题:ORM聚合函数

          本文链接:https://www.haomeiwen.com/subject/asclxktx.html