代码之家  ›  专栏  ›  技术社区  ›  meepmeep

生成SQL错误的Django聚合查询

  •  0
  • meepmeep  · 技术社区  · 16 年前

    我正在使用最新的sql server_ado库在SQL Server 2005数据库上使用django 1.1.1。

    models.py包括:

    class Project(models.Model):
        name = models.CharField(max_length=50)
    
    class Thing(models.Model):
        project = models.ForeignKey(Project)
        reference = models.CharField(max_length=50)
    
    class ThingMonth(models.Model):
        thing = models.ForeignKey(Thing)
        timestamp = models.DateTimeField()
        ThingMonthValue = models.FloatField()
    
        class Meta:
            db_table = u'ThingMonthSummary'
    

    在一个视图中,我检索到一个名为“things”的查询集,其中包含25个内容:

    things = Thing.objects.select_related().filter(project=1).order_by('reference')
    

    然后,我想做一个聚合查询,以获取在某个时间段内前20个事件的平均thingMonthValue,以及最后5个事件的相同值。

    在前20年,我会:

    averageThingMonthValue = ThingMonth.objects.filter(thing__in=things[:20],timestamp__range="2009-01-01 00:00","2010-03-00:00")).aggregate(Avg('ThingMonthValue'))['ThingMonthValue__avg']
    

    这样可以很好地工作,并返回所需的值。

    在过去的5年里,我做到了:

    averageThingMonthValue = ThingMonth.objects.filter(thing__in=things[20:],timestamp__range="2009-01-01 00:00","2010-03-00:00")).aggregate(Avg('ThingMonthValue'))['ThingMonthValue__avg']
    

    但为此,我得到了一个SQL错误:“当子查询不与exists一起引入时,在选择列表中只能指定一个表达式。”

    Django使用的SQL查询为:

    SELECT AVG([ThingMonthSummary].[ThingMonthValue]) AS [ThingMonthValue__avg] 
    FROM [ThingMonthSummary] 
    WHERE ([ThingMonthSummary].[thing_id] IN
         (SELECT _row_num, [id] FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY [AAAA].[id] ASC) as _row_num,
         [AAAA].[id] FROM ( SELECT U0.[id] FROM [Thing] U0 WHERE U0.[project_id] = 1 ) AS [AAAA]) as QQQ
         where 20 < _row_num) AND [ThingMonthSummary].[timestamp] BETWEEN '01/01/09 00:00:00' and '03/01/10 00:00:00')
    

    你知道为什么它只适用于一部分而不适用于第二部分吗?我已经检查过了,这两片确实包含了所需的内容。

    1 回复  |  直到 16 年前
        1
  •  2
  •   Ed Harper    16 年前

    这看起来像Django ORM的SQL生成器中的一个bug。生成的SQL正在返回 _row_num 以及 id IN 第二个查询的子查询(如果不需要)。

    因为子查询可以写为 SELECT TOP 20...

    最后绕开这个 n 行计算,您可以返回 Things 并在代码中进行平均计算。

    (可能还有另一个特定于Django的解决方案,但我是一个SQL Server人员。)