2016-07-20 3 views
2

Ich habe drei Tabellen mit dem Namen Groups, GroupMembers und DailyTable jeweils. Hier sind meine Modelle für jeden von ihnen:Um DENSE_RANK() auf die Ausgabe einer Abfrage anzuwenden

models.py

class Group(models.Model): 

    name = models.CharField(max_length=255, blank=False, null=False) 
    group_type = models.ForeignKey('GroupType',blank=True,default=False) 

    class Meta: 
     db_table = 'groups' 

class GroupMembers(models.Model): 
    group = models.ForeignKey('Group') 
    user = models.ForeignKey('User') 
    status = models.CharField(max_length=20) 

    class Meta: 
     db_table = 'group_members' 
     unique_together = ['group', 'user'] 

class DailyTable(models.Model):  
    class Meta: 
     managed = True 
     db_table = 'dailytable' 

    user_id = models.IntegerField(db_index=True)   
    calories = models.FloatField()   
    date = models.DateField() 

I indiviaully von jeder Gruppe verbrannte Kalorien berechnen wollte. So feuerte ich die unten Abfrage nach oben:

select groups.id,groups.name as group_display_name, 
(select count(*) from group_members where group_id = groups.id and status = 'accepted' and groups.group_type_id = 1) as total_members, 
(select sum(calories) from dailytable where user_id in (select user_id from group_members where group_id = groups.id and groups.group_type_id = 1) and dailytable.date='2016-02-02') as total_calories, 
(select case when exists(select * from group_members where group_id = groups.id and user_id = 3 and status = 'accepted' and groups.group_type_id = 1) then cast(1 as bit) else cast(0 as bit) end) as is_member_of_group 
from groups 
where groups.group_type_id = 1 
order by total_calories desc 
nulls last; 

Im Folgenden finden Sie die Ausgabe, die ich enter image description here Jetzt bekomme ich die Gruppen auf dem total_calories basierend auf RANK wollte, dass ich verbrannt haben, so dass ich die folgenden Änderungen in der Abfrage :

.... 
dense_rank() over(order by total_calories) 
from groups 
.... 

Fehler: Spalte "total_calories" existiert nicht

I RANK mit dem Ausgang der Abfrage anwenden möchten. Gibt es einen Weg, dies zu erreichen?

Antwort

1

Dies ist, weil Sie versuchen, abgeleiteten Spaltenalias in dicht_rank() zu verwenden, die dort nicht verfügbar ist. Wrap-Abfrage in CTE und wenden Sie dichte_Rank() darauf an:

WITH baseQuery AS (
    SELECT 
     groups.id, 
     groups.name AS group_display_name, 
     (
      SELECT 
       count(*) 
      FROM group_members 
      WHERE 
       group_id = groups.id AND status = 'accepted' AND groups.group_type_id = 1) AS total_members, 
     (
      SELECT 
       sum(calories) 
      FROM dailytable 
      WHERE 
       user_id IN (
        SELECT 
         user_id 
        FROM group_members 
        WHERE 
         group_id = groups.id 
         AND groups.group_type_id = 1 
       ) AND dailytable.date = '2016-02-02' 
     ) AS total_calories, 
     (
      SELECT 
       CASE WHEN exists(SELECT 
            * 
           FROM group_members 
           WHERE 
            group_id = groups.id 
            AND user_id = 3 
            AND status = 'accepted' 
            AND groups.group_type_id = 1) 
        THEN cast(1 AS BIT) 
       ELSE cast(0 AS BIT) END) AS is_member_of_group 
    FROM groups 
    WHERE 
     groups.group_type_id = 1 
) 
    select * , 
     dense_rank() over(order by total_calories) 
    from baseQuery 
    ORDER BY total_calories DESC 
    NULLS LAST 
1

Umgeben Sie die Abfrage und berechnen Sie den Rang in der äußeren Auswahl.

Im folgenden Beispiel verwendet die Abfrage Joins und eine Gruppe anstelle von Unterabfragen, um die Summen zu berechnen.

select 
q.*, 
DENSE_RANK() over (order by total_calories) as total_calories_rank 
from 
(
    select 
    g.id as group_id, 
    g.name as group_name, 
    count(distinct m.user_id) as total_members, 
    sum(d.calories) as total_calories, 
    cast(max(case when m.user_id = 3 then 1 else 0 end) as bit) as user_3_is_member_of_group 
    from groups g 
    inner join group_members m on (g.id = m.group_id and m.status = 'accepted') 
    left join (
     select user_id, sum(calories) as calories 
     from dailytable 
     where date = '2016-02-02' 
     group by user_id 
    ) d on (m.user_id = d.user_id) 
    where g.group_type_id = 1 
    group by g.id, g.name 
) q 
order by total_calories desc 
nulls last; 
Verwandte Themen