Django 1.6 + MySQL :键入 Cast MySQL 变量以搜索 Max、Avg
Django 1.6 + MySQL : Type Cast MySQL variable to search for Max, Avg
我的模型有点像
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
表示Float中的值存储为VarChar,w.r.t时间存储为unixtime
在尝试获取 current_value
的最大值和平均值时,我得到了意想不到的结果,因为对于 Max,MySQL 会进行基于字符串的比较,其中在 '100' value < '9.99'
中Float 中的 w.r.t 值不正确。
我试过了:
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`
从 performance_utilizationstatus
按 performance_utilizationstatus
排序。sys_timestamp
降序;
但工作代码需要 GROUP BY on (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`
分组依据 performance_utilizationstatus
.device_name
, performance_utilizationstatus
.service_name
,
performance_utilizationstatus
.data_source
按 performance_utilizationstatus
.sys_timestamp
排序;
如何添加GROUP BY CLAUSE?
使用 annotate
在这里不起作用
1111, 'Invalid use of group function'
或
ERROR 1056 (42000): Can't group on 'max_val'
RAW SQL 是最后的选择吗?
我认为你必须选择 .raw
,因为这里不可能使用 .extra
。
问题是因为 Django
没有 .group_by
按某物分组的唯一方法是在那之后使用 .values
和 .annotate
。 (正如您在第一次尝试中所做的那样)
所以.. 为什么你不能使用 .extra
?因为:
Any extra() call made after a values() call will have its extra
selected fields ignored.
和
If you use a values() clause after an extra() call, any fields defined
by a select argument in the extra() must be explicitly included in the
values() call.
所以获取 .extra
字段的唯一方法是将它们添加到 .values
中,但这将导致按此字段分组,这是一种不希望的行为。
我的模型有点像
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
表示Float中的值存储为VarChar,w.r.t时间存储为unixtime
在尝试获取 current_value
的最大值和平均值时,我得到了意想不到的结果,因为对于 Max,MySQL 会进行基于字符串的比较,其中在 '100' value < '9.99'
中Float 中的 w.r.t 值不正确。
我试过了:
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`
从 performance_utilizationstatus
按 performance_utilizationstatus
排序。sys_timestamp
降序;
但工作代码需要 GROUP BY on (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`
分组依据 performance_utilizationstatus
.device_name
, performance_utilizationstatus
.service_name
,
performance_utilizationstatus
.data_source
按 performance_utilizationstatus
.sys_timestamp
排序;
如何添加GROUP BY CLAUSE?
使用 annotate
在这里不起作用
1111, 'Invalid use of group function'
或
ERROR 1056 (42000): Can't group on 'max_val'
RAW SQL 是最后的选择吗?
我认为你必须选择 .raw
,因为这里不可能使用 .extra
。
问题是因为 Django
没有 .group_by
按某物分组的唯一方法是在那之后使用 .values
和 .annotate
。 (正如您在第一次尝试中所做的那样)
所以.. 为什么你不能使用 .extra
?因为:
Any extra() call made after a values() call will have its extra selected fields ignored.
和
If you use a values() clause after an extra() call, any fields defined by a select argument in the extra() must be explicitly included in the values() call.
所以获取 .extra
字段的唯一方法是将它们添加到 .values
中,但这将导致按此字段分组,这是一种不希望的行为。