【问题标题】:Postgres Recursive query + group by + join in DjangoPostgres递归查询+分组+加入Django
【发布时间】:2011-08-05 07:55:59
【问题描述】:

我的要求是编写一个 sql 查询来获取托管对象发生的子区域明智(故障)事件计数。我的数据库是 postgres 8.4。让我解释一下使用表结构。

我在 django 中的表: 托管对象:

class Managedobject(models.Model):
   name                = models.CharField(max_length=200, unique=True)
   iscontainer         = models.BooleanField(default=False,)
   parentkey           = models.ForeignKey('self', null=True)

事件表:

class Event(models.Model):
    Name        = models.CharField(verbose_name=_('Name'))
    foid        = models.ForeignKey(Managedobject)

托管对象记录:

NOC
   Chennai
      MO_1
      MO_2
      MO_3
   Mumbai
      MO_4
      MO_5
      MO_6
   Delhi
   Bangalore
IP
   Calcutta
   Cochin

事件记录:

event1 MO_1
event2 MO_2
event3 MO_3
event4 MO_5
event5 MO_6    

现在我需要获取所有子区域的事件计数。例如,

for NOC region:
  Chennai - 3
  Mumbai - 2
  Delhi - 0
  Bangalore - 0

到目前为止,我能够在两个不同的查询中得到结果。

  1. 获取子区域。

    select id from managedobject where iscontainer = True and parentkey = 3489
    
  2. 对于每个区域(使用for循环),获取计数如下:

    SELECT count(*) 
    from event ev 
    WHERE ev.foid 
    IN (
        WITH RECURSIVE q AS (
            SELECT h 
            FROM managedobject h 
            WHERE parentkey = 3489 
            UNION ALL 
            SELECT hi 
            FROM q 
            JOIN managedobject hi 
            ON hi.parentkey = (q.h).id 
        ) 
        SELECT (q.h).id FROM q
    )
    

请帮助组合查询以使其成为单个查询并获得前 5 个区域。由于在 django 中查询很困难,所以我要进行原始 sql 查询。

【问题讨论】:

  • 您需要iscontainer 字段吗?如果 parentkey = None 那么对象不是容器,如果 Managedobject 有父键,那么它是容器?
  • @krieger。感谢您的努力。这里的容器有不同的含义。 Managedobject 表中的父/子关系级别无穷无尽。如果记录被标记为容器,则它是刚刚添加用于分组的逻辑实体。即使记录 MO_1 也可以有子 MO_11,但它不是一个容器,因为它代表一个物理实体。
  • 哦,我明白了,我误读了您最初的问题。我稍后再看一下。对于那个很抱歉。我认为 MO_1 是事件,它们也是事件相关的托管对象。

标签: django postgresql recursion sql


【解决方案1】:

我收到了查询:

WITH RECURSIVE q AS ( 
  SELECT  h, 
          1 AS level, 
          id AS ckey, 
          displayname as dname 
  FROM managedobject h 
  WHERE parentkey = 3489  
    and logicalnode=True 

 UNION ALL 

 SELECT  hi, 
         q.level + 1 AS level, 
         ckey, 
         dname 
 FROM q 
   JOIN managedobject hi ON hi.parentkey = (q.h).id 
) 
SELECT count(ckey) as ccount, 
       ckey, 
       dname 
FROM q 
  JOIN event as ev on ev.foid_id = (q.h).id 
GROUP BY ckey, dname 
ORDER BY ccount DESC 
LIMIT 5

【讨论】:

  • 这个表达式:ev.foid_id = (q.h).id 在做什么?是不是打错字了?
  • 不,这是一个正在运行的查询。在 Django 中,外键字段将附加“_id”。在 postgres 递归查询中,您必须以“(q.h).id”的形式访问该字段。
  • 我从未见过带有递归 CTE 的语法。我想说q.id 对于内部查询应该足够了。外部应该使用q.ckey
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-12-18
  • 1970-01-01
  • 2014-10-29
  • 1970-01-01
  • 1970-01-01
  • 2015-08-15
  • 1970-01-01
相关资源
最近更新 更多