Every PostgreSQL window function Django wraps.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | # ====================================================================== # Every PostgreSQL window function Django wraps. `RowNumber` numbers rows, # `PercentRank`/`CumeDist` give relative position, `Ntile` buckets, `Lead` peeks # at the next row, and `FirstValue`/`LastValue`/`NthValue` read specific rows in # the window. `LastValue`/`NthValue` need an explicit `frame=RowRange(None, # None)` to see the whole partition, not just up to the current row. A custom # frame also powers the running total. # ====================================================================== # ---------------------------------------------------------------------- # ranking & value functions # ---------------------------------------------------------------------- # Django: Book.objects.annotate( rownum=Window(RowNumber(), order_by=F("price").desc()), pct=Window(PercentRank(), order_by=F("price").desc()), cume=Window(CumeDist(), order_by=F("price").desc()), half=Window(Ntile(num_buckets=2), order_by=F("price").desc()), nxt=Window(Lead("price"), order_by=F("price").desc()), first=Window(FirstValue("title"), order_by=F("price").desc()), last=Window(LastValue("title"), order_by=F("price").desc(), frame=RowRange(start=None, end=None)), second=Window(NthValue("title", nth=2), order_by=F("price").desc(), frame=RowRange(start=None, end=None)), ).order_by("-price") # SQL: # SELECT "examples_book"."id", "examples_book"."title", "examples_book"."author_id", "examples_book"."price", "examples_book"."pages", "examples_book"."published", "examples_book"."is_active", "examples_book"."tags", "examples_book"."data", "examples_book"."search", "examples_book"."title_upper", ROW_NUMBER() OVER (ORDER BY "examples_book"."price" DESC) AS "rownum", PERCENT_RANK() OVER (ORDER BY "examples_book"."price" DESC) AS "pct", CUME_DIST() OVER (ORDER BY "examples_book"."price" DESC) AS "cume", NTILE(2) OVER (ORDER BY "examples_book"."price" DESC) AS "half", LEAD("examples_book"."price", 1) OVER (ORDER BY "examples_book"."price" DESC) AS "nxt", FIRST_VALUE("examples_book"."title") OVER (ORDER BY "examples_book"."price" DESC) AS "first", LAST_VALUE("examples_book"."title") OVER (ORDER BY "examples_book"."price" DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS "last", NTH_VALUE("examples_book"."title", 2) OVER (ORDER BY "examples_book"."price" DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS "second" # FROM "examples_book" # ORDER BY "examples_book"."price" DESC # Result: # #1 The Lord of the Rings: pct=0.00 cume=0.25 ntile=1 next=$19.99 first='The Lord of the Rings' last='Postgres for Authors' 2nd='Harry Potter' # #2 Harry Potter: pct=0.33 cume=0.50 ntile=1 next=$14.50 first='The Lord of the Rings' last='Postgres for Authors' 2nd='Harry Potter' # #3 The Hobbit: pct=0.67 cume=0.75 ntile=2 next=$0.00 first='The Lord of the Rings' last='Postgres for Authors' 2nd='Harry Potter' # #4 Postgres for Authors: pct=1.00 cume=1.00 ntile=2 next=$None first='The Lord of the Rings' last='Postgres for Authors' 2nd='Harry Potter' # ---------------------------------------------------------------------- # running total (custom frame: UNBOUNDED PRECEDING .. CURRENT ROW) # ---------------------------------------------------------------------- # Django: Book.objects.annotate( running=Window(Sum("price"), order_by=F("published").asc(), frame=RowRange(start=None, end=0)), ).order_by("published") # SQL: # SELECT "examples_book"."id", "examples_book"."title", "examples_book"."author_id", "examples_book"."price", "examples_book"."pages", "examples_book"."published", "examples_book"."is_active", "examples_book"."tags", "examples_book"."data", "examples_book"."search", "examples_book"."title_upper", SUM("examples_book"."price") OVER (ORDER BY "examples_book"."published" ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS "running" # FROM "examples_book" # ORDER BY "examples_book"."published" ASC # Result: # The Hobbit ($14.50) -> running total $14.50 # The Lord of the Rings ($29.00) -> running total $43.50 # Harry Potter ($19.99) -> running total $63.49 # Postgres for Authors ($0.00) -> running total $63.49 |