【发布时间】:2023-03-15 11:07:01
【问题描述】:
我正在尝试将此 SQL 查询(在 mySQL 中完美运行)转换为 Django ORM,以便它可以在 PostgreSQL 环境中使用(因为 SQL 查询对 PG 无效)。我尝试了几种使用聚合和注释的不同方法,但我就是想不通。
我正在尝试做的是计算每种类型的条目数(总共有 3 种类型),每个月,当前日期两侧的 6 个月!
有效的 SQL 查询是
select count(c.id) as Quantity, date_format(expiry, '%Y-%m') as Expiry, type from certificate as c
join type as t on t.id = c.type_id
where expiry >= date_format(date_sub(now(), interval 6 month), '%Y-%m-%d')
and expiry <= date_format(date_add(now(), interval 6 month), '%Y-%m-%d')
group by month(expiry), type
order by expiry asc
我将 'date_format' 更改为 postgres 'to_char' 但我似乎无法按 'month(expiry)' 分组,而 ORM 解决方案似乎是更好的方法。
主要的证书模型如下:
class Certificate(models.Model):
epc_rating = models.IntegerField(null=True, db_index=False)
building_area = models.IntegerField(db_index=False)
building_emissions = models.DecimalField(max_digits=6, decimal_places=2, db_index=False)
energy_usage = models.DecimalField(max_digits=6, decimal_places=2, db_index=False)
refrig_weight = models.IntegerField(db_index=False)
ac_output = models.IntegerField(db_index=False)
annual_heating = models.CharField(blank=True, null=True, max_length=50, db_index=False)
renewable_heating = models.CharField(blank=True, null=True, max_length=50, db_index=False)
annual_electric = models.CharField(blank=True, null=True, max_length=50, db_index=False)
typical_heating = models.CharField(blank=True, null=True, max_length=50, db_index=False)
typical_electric = models.CharField(blank=True, null=True, max_length=50, db_index=False)
renewable_electric = models.CharField(blank=True, null=True, max_length=50, db_index=False)
expiry = models.DateField(db_index=True) # This is the expiry date used
manager = models.CharField(blank=True, null=True, max_length=100, db_index=False)
rrn = models.ForeignKey(RRN, on_delete=models.CASCADE)
type = models.ForeignKey(Type, on_delete=models.CASCADE)
postcode = models.ForeignKey(Postcode, on_delete=models.CASCADE)
site = models.ForeignKey(Site, on_delete=models.CASCADE)
heating = models.ForeignKey(Heating, on_delete=models.CASCADE)
complexity = models.ForeignKey(Complexity, on_delete=models.CASCADE)
employer = models.ForeignKey(Employer, on_delete=models.CASCADE)
environment = models.ForeignKey(Environment, on_delete=models.CASCADE)
assessor = models.ForeignKey(Assessor, on_delete=models.CASCADE)
scheme = models.ForeignKey(Scheme, on_delete=models.CASCADE)
class Meta:
managed = True
db_table = 'certificate'
并且该表有一个指向“类型”表的外键链接,其模型如下:
class Type(models.Model):
type = models.CharField(blank=True, null=True, max_length=25, db_index=True)
class Meta:
managed = True
db_table = 'type'
类型表中有 3 种“类型”(我知道,命名约定令人困惑),它们是“EPC”、“TM44”和“DEC”。正如我所说,我正在尝试计算一年中每个月内每种类型的数量?
任何帮助将不胜感激,我已经尝试转换它大约 2-3 周,最终决定寻求帮助。提前致谢。
编辑 所以我应该添加我尝试过的内容......我不太了解在这个查询中我可以在哪里使用聚合函数,但我管理的注释:
currentDate = datetime.now().date()
prev_half_year = currentDate - relativedelta(months=6)
next_half_year = currentDate + relativedelta(months=6)
expiryObj = Certificate.objects.filter(expiry__range=[prev_half_year, next_half_year]).annotate(epc_count=Count('id', filter=Q(type__type='EPC'))).count()
我在最后添加了返回整数 151 的计数(这可能是正确的,我不能确定,因为这是我需要弄清楚的查询,以便我可以检查)。问题是我不确定这是否是全年的正确数字,而且我看不到如何添加 group_by 语句来获取各个月份。如果我将它添加到末尾,例如 count().group_by('expiry')”,我会得到“AttributeError:'int' object has no attribute 'group_by'”,如果我在计数之前添加它,我会得到“AttributeError:' QuerySet' 对象没有属性 'group_by'"!此外,SQL 查询能够按 Month(expiry) 分组,但我还没有找到任何与如何将其转换为 Django ORM 相关的文档。
进一步编辑 感谢 'iklinac' 提供一些关于在哪里寻找的提示。我已经设法使用此查询进一步得到结果:
results = Certificate.objects.filter(expiry__range=[prev_half_year, next_half_year]).values_list('expiry__year', 'expiry__month').annotate(Sum('type_id')).order_by('expiry__year')
这将返回一个查询集----
【问题讨论】:
-
Postgres 没有
date_add和date_sub。使用类似:select now() - interval 6 month; select now() + interval 6 month;还需要将month更改为select date_part('month', now() - interval '6 months'); 6。
标签: python sql django postgresql