Django 1.6 + MySQL:输入Cast MySQL变量来搜索Max,Avg

时间:2015-03-14 18:31:54

标签: mysql django django-orm django-aggregation

我的模型有点像

class ServiceUtilization(models.Model):
device_name = models.CharField()
service_name = models.CharField()
data_source = models.CharField()
current_value = models.CharField()
sys_timestamp = models.IntegerField()

现在,current_value表示存储为VarChar的浮点值,w.r.t存储为unixtime的时间

在尝试获取current_value的Max和Average值时,我得到了意想不到的结果,因为对于Max,MySQL会进行基于字符串的比较,其中'100' value < '9.99'在Float中采用不正确的wrt值

我试过了:

perf = ServiceUtilization.objects.filter(
        device_name__in=devices,
        service_name__in=services,
        data_source__in=data_sources,
        sys_timestamp__gte=start_date,
        sys_timestamp__lte=end_date
    ).values(
        'device_name',
        'service_name',
        'data_source'
    ).annotate(
        max_val=Max('current_value'),
        avg_val=Avg('current_value')
    )

它提供的结果不正确。

然后看:HOW select min from cast varchar to int in mysql

我考虑过使用extra

提供查询集
perf = ServiceUtilization.objects.extra(
       select={
          'max_val': "MAX(CAST(current_value AS SIGNED))",
          'avg_val': "AVG(CAST(current_value AS SIGNED))"
       }
       ).filter(
        device_name__in=devices,
        service_name__in=services,
        data_source__in=data_sources,
        sys_timestamp__gte=start_date,
        sys_timestamp__lte=end_date
    ).values(
        'device_name',
        'service_name',
        'data_source',
        'max_val',
        'avg_val'
    )

但这仅提供单一值而非预期结果。这转换为SQL

SELECT (MAX(CAST(current_value AS SIGNED))) AS `max_val`, (AVG(CAST(current_value AS SIGNED))) AS `avg_val`, `performance_utilizationstatus`.`device_name`, `performance_utilizationstatus`.`service_name`, `performance_utilizationstatus`.`data_source`

FROM performance_utilizationstatus ORDER BY performance_utilizationstatussys_timestamp DESC;

但是工作代码需要GROUP BY(device_name,service_name,data_source)

SELECT (MAX(CAST(current_value AS SIGNED))) AS `max_val`, (AVG(CAST(current_value AS SIGNED))) AS `avg_val`, `performance_utilizationstatus`.`device_name`, `performance_utilizationstatus`.`service_name`, `performance_utilizationstatus`.`data_source`  FROM `performance_utilizationstatus` 

GROUP BY performance_utilizationstatusdevice_nameperformance_utilizationstatusservice_nameperformance_utilizationstatusdata_source ORDER BY performance_utilizationstatussys_timestamp DESC;

如何添加GROUP BY CLAUSE?

使用annotate无效

1111, 'Invalid use of group function'

ERROR 1056 (42000): Can't group on 'max_val'

RAW SQL会不会成为最后的手段?

1 个答案:

答案 0 :(得分:0)

我认为你必须使用.raw,因为在这里使用.extra是不可能的。

问题是因为Django没有.group_by唯一的方法是在此之后使用.values.annotate。 (,因为你在第一次尝试时已经完成了

所以..为什么你不能使用.extra?这是因为:

  

在values()调用之后进行的任何extra()调用都会有额外的   选中的字段被忽略。

  

如果在extra()调用后使用values()子句,则定义任何字段   通过extra()中的select参数必须明确包含在   values()调用。

因此获取.extra字段的唯一方法是将它们添加到.values中,但这会导致按此字段进行分组,这是一种不受欢迎的行为。