sql >> Database teknologi >  >> RDS >> PostgreSQL

Korrekt måde at annotere et rangfelt på for et forespørgselssæt

Desværre er det ikke en mulig operation, da (for mig) postgresql WHERE operation (filtrer/ekskluder) indsnævrer rækkerne, før aggregeringsfunktionerne kan arbejde på dem.

Den eneste løsning, jeg fandt, er simpelthen at beregne rangeringen for alle Person med et separat forespørgselssæt og derefter for at annotere dit forespørgselssæt med disse resultater.

Dette svar (se den forbedrede metode) forklarer, hvordan man "annoterer et forespørgselssæt med eksternt forberedte data i en diktat".

Her er den implementering, jeg lavede til dine modeller:

class PersonQuerySet(models.QuerySet):
    def total_scores(self):
        # compute the global ranking
        ranks = (Person.objects
                 .annotate(total_score=models.Sum('session__gamesession__score'))
                 .annotate(rank=models.Window(expression=DenseRank(),
                                              order_by=models.F('total_score').decs()))
                 .values('pk', 'rank'))
        # extract and put ranks in a dict
        rank_dict = dict((e['pk'], e['rank']) for e in ranks)

        # create `WHEN` conditions for mapping filtered Persons to their Rank
        whens = [models.When(pk=pk, then=rank) for pk, rank in rank_dict.items()]
        # build the query
        return (self.annotate(rank=models.Case(*whens, default=0,
                                               output_field=models.IntegerField()))
                .annotate(total_score=models.Sum('session__gamesession__score')))

Jeg testede det med Django 2.1.3 og Postgresql 10.5, så koden kan ændre sig let for dig.
Del gerne en version, der er kompatibel med Django 1.11!




  1. ORA-00932:inkonsistente datatyper:forventet - fik CLOB

  2. Optimer gruppevis maksimal forespørgsel

  3. Analyse med MariaDB AX - tThe Open Source Columnar Datastore

  4. Tilføjelse af en ny kolonne i en midlertidig tabel