Search code examples
postgresqlcountwindow-functions

Get the ID of a table and its modulo respect the total rows in the same table in Postgres


While trying to map some data to a table, I wanted to obtain the ID of a table and its modulo respect the total rows in the same table. For example, given this table:

id
--
 1
 3
10
12

I would like this result:

id | mod
---+----
 1 |   1    <-  1 mod 4
 3 |   3    <-  3 mod 4
10 |   2    <- 10 mod 4
12 |   0    <- 12 mod 4

Is there an easy way to achieve this dynamically (as in, not counting the rows on before hand or doing it in an atomic way)?

So far I've tried something like this:

SELECT t1.id, t1.id % COUNT(t1.id) mod FROM tbl t1, tbl t2 GROUP BY t1.id;

This works but you must have the GROUP BY and tbl t2 as otherwise it returns 0 for the mod column which makes sense because I think it works by multiplying the table by itself so each ID gets a full set of the table. I guess for small enough tables this is ok but I can see how this becomes problematic for larger tables.

Edit: Found another hack-ish way:

WITH total AS (
    SELECT COUNT(*) cnt FROM tbl
)

SELECT t1.id, t1.id % t2.cnt mod FROM tbl t1, total t2

It similar to the previous query but it "collapses" the multiplication to a single row with the previous count.


Solution

  • You can use COUNT() window function:

    SELECT id, 
           id % COUNT(*) OVER () mod 
    FROM tbl;
    

    I'm sure that the optimizer is smart enough to calculate the result of the window function only once.

    See the demo.