【问题标题】:django orm queryset - how to perform sql query MIN/MAX FILTERdjango orm queryset - 如何执行 sql 查询 MIN/MAX FILTER
【发布时间】:2021-03-08 03:49:53
【问题描述】:

我正在尝试为特定的 sql 语句创建 django ORM 查询集的帮助(您也可以在此处运行它) https://dbfiddle.uk/?rdbms=postgres_13&fiddle=31c9431d6753e2fdd8df37bbc1869e88

特别是对于这个问题,我对包含以下内容的行更感兴趣:

MIN(created_at::time) FILTER (WHERE activity_type = 1) as min_time_in,
MAX(created_at::time) FILTER (WHERE activity_type = 2) as max_time_out

如果可能的话,这里是整个 sql 以转换为 django ORM 查询集

SELECT 
    created_at::date as created_date,
    company_id,
    employee_id,
    MIN(created_at::time) FILTER (WHERE activity_type = 1) as min_time_in,
    MAX(created_at::time) FILTER (WHERE activity_type = 2) as max_time_out
FROM
   timerecord
where date(created_at) = '2020-11-18' and employee_id = 1
GROUP BY created_date, company_id, employee_id
ORDER BY created_date, employee_id

【问题讨论】:

  • 你能添加你的模型吗? Django 模型?

标签: sql django filter orm max


【解决方案1】:

原始查询:

SELECT 
    created_at::date as created_date,
    company_id,
    employee_id,
    MIN(created_at::time) FILTER (WHERE activity_type = 1) as min_time_in,
    MAX(created_at::time) FILTER (WHERE activity_type = 2) as max_time_out
FROM
   timerecord
where date(created_at) = '2020-11-18' and employee_id = 1
GROUP BY created_date, company_id, employee_id
ORDER BY created_date, employee_id;

conditional/selective aggregation 的一个示例。上面的语法在 PostgreSQL/SQLite 中可用。

使用 CASE 表达式可以很容易地重写为:

SELECT 
    created_at::date as created_date,
    company_id,
    employee_id,
    MIN(CASE WHEN activity_type = 1 THEN created_at::time END)as min_time_in,
    MAX(CASE WHEN activity_type = 2 THEN created_at::time END) as max_time_out
FROM
   timerecord
where date(created_at) = '2020-11-18' and employee_id = 1
GROUP BY created_date, company_id, employee_id
ORDER BY created_date, employee_id;

db<>fiddle demo

任何现代 RDBMS 都支持,Django 也支持:

conditional-aggregation

如果我们想知道每个 account_type 有多少客户呢?我们可以在聚合函数中嵌套条件表达式来实现这一点:

Client.objects.aggregate(
...     regular=Count('pk', filter=Q(account_type=Client.REGULAR)),
...     gold=Count('pk', filter=Q(account_type=Client.GOLD)),
...     platinum=Count('pk', filter=Q(account_type=Client.PLATINUM)),
... )

此聚合在支持它的数据库上使用 SQL 2003 FILTER WHERE 语法生成查询

...

在其他数据库上,这是使用 CASE 语句模拟的

【讨论】:

    【解决方案2】:

    您可以使用aggregate()--(doc) 方法或(annotate()--(doc) 方法)来获取结果。为此,您必须使用 Min()Max() 数据库函数以及 filter 参数。

    from django.db.models import Min, Q, Max
    
    agg_response = TimeRecord.objects.aggregate(
        min_time_in=Min("created_at", filter=Q(activity_type=1)),
        max_time_out=Max("created_at", filter=Q(activity_type=2)),
    )

    【讨论】:

      猜你喜欢
      • 2019-08-05
      • 2015-12-10
      • 1970-01-01
      • 2017-01-01
      • 1970-01-01
      • 2018-12-05
      • 2015-02-04
      • 1970-01-01
      • 2017-11-05
      相关资源
      最近更新 更多