diff --git a/src/test/regress/expected/window_functions.out b/src/test/regress/expected/window_functions.out index 6a788a9bf..859efbc91 100644 --- a/src/test/regress/expected/window_functions.out +++ b/src/test/regress/expected/window_functions.out @@ -1,6 +1,13 @@ -- =================================================================== -- test top level window functions that are pushdownable -- =================================================================== +SHOW server_version \gset +SELECT substring(:'server_version', '\d+')::int > 10 AS version_above_ten; + version_above_ten +------------------- + t +(1 row) + -- a very simple window function with an aggregate and a window function -- distribution column is on the partition by clause SELECT @@ -404,6 +411,258 @@ ORDER BY 1 | 1 | 1 | 1 | 0 (6 rows) +-- test exclude supported +SELECT + user_id, + value_1, + array_agg(value_1) OVER (PARTITION BY user_id ORDER BY value_1 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), + array_agg(value_1) OVER (PARTITION BY user_id ORDER BY value_1 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE CURRENT ROW) +FROM + users_table +WHERE + user_id > 2 AND user_id < 6 +ORDER BY + user_id, value_1; + user_id | value_1 | array_agg | array_agg +---------+---------+-------------------------------------------------------+----------------------------------------------------- + 3 | 0 | {0} | + 3 | 1 | {0,1,1,1,1,1,1} | {0,1,1,1,1,1} + 3 | 1 | {0,1,1,1,1,1,1} | {0,1,1,1,1,1} + 3 | 1 | {0,1,1,1,1,1,1} | {0,1,1,1,1,1} + 3 | 1 | {0,1,1,1,1,1,1} | {0,1,1,1,1,1} + 3 | 1 | {0,1,1,1,1,1,1} | {0,1,1,1,1,1} + 3 | 1 | {0,1,1,1,1,1,1} | {0,1,1,1,1,1} + 3 | 2 | {0,1,1,1,1,1,1,2,2} | {0,1,1,1,1,1,1,2} + 3 | 2 | {0,1,1,1,1,1,1,2,2} | {0,1,1,1,1,1,1,2} + 3 | 3 | {0,1,1,1,1,1,1,2,2,3,3,3} | {0,1,1,1,1,1,1,2,2,3,3} + 3 | 3 | {0,1,1,1,1,1,1,2,2,3,3,3} | {0,1,1,1,1,1,1,2,2,3,3} + 3 | 3 | {0,1,1,1,1,1,1,2,2,3,3,3} | {0,1,1,1,1,1,1,2,2,3,3} + 3 | 4 | {0,1,1,1,1,1,1,2,2,3,3,3,4,4,4,4} | {0,1,1,1,1,1,1,2,2,3,3,3,4,4,4} + 3 | 4 | {0,1,1,1,1,1,1,2,2,3,3,3,4,4,4,4} | {0,1,1,1,1,1,1,2,2,3,3,3,4,4,4} + 3 | 4 | {0,1,1,1,1,1,1,2,2,3,3,3,4,4,4,4} | {0,1,1,1,1,1,1,2,2,3,3,3,4,4,4} + 3 | 4 | {0,1,1,1,1,1,1,2,2,3,3,3,4,4,4,4} | {0,1,1,1,1,1,1,2,2,3,3,3,4,4,4} + 3 | 5 | {0,1,1,1,1,1,1,2,2,3,3,3,4,4,4,4,5} | {0,1,1,1,1,1,1,2,2,3,3,3,4,4,4,4} + 4 | 0 | {0,0,0,0} | {0,0,0} + 4 | 0 | {0,0,0,0} | {0,0,0} + 4 | 0 | {0,0,0,0} | {0,0,0} + 4 | 0 | {0,0,0,0} | {0,0,0} + 4 | 1 | {0,0,0,0,1} | {0,0,0,0} + 4 | 2 | {0,0,0,0,1,2,2,2} | {0,0,0,0,1,2,2} + 4 | 2 | {0,0,0,0,1,2,2,2} | {0,0,0,0,1,2,2} + 4 | 2 | {0,0,0,0,1,2,2,2} | {0,0,0,0,1,2,2} + 4 | 3 | {0,0,0,0,1,2,2,2,3,3,3,3,3,3} | {0,0,0,0,1,2,2,2,3,3,3,3,3} + 4 | 3 | {0,0,0,0,1,2,2,2,3,3,3,3,3,3} | {0,0,0,0,1,2,2,2,3,3,3,3,3} + 4 | 3 | {0,0,0,0,1,2,2,2,3,3,3,3,3,3} | {0,0,0,0,1,2,2,2,3,3,3,3,3} + 4 | 3 | {0,0,0,0,1,2,2,2,3,3,3,3,3,3} | {0,0,0,0,1,2,2,2,3,3,3,3,3} + 4 | 3 | {0,0,0,0,1,2,2,2,3,3,3,3,3,3} | {0,0,0,0,1,2,2,2,3,3,3,3,3} + 4 | 3 | {0,0,0,0,1,2,2,2,3,3,3,3,3,3} | {0,0,0,0,1,2,2,2,3,3,3,3,3} + 4 | 4 | {0,0,0,0,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4} | {0,0,0,0,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4} + 4 | 4 | {0,0,0,0,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4} | {0,0,0,0,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4} + 4 | 4 | {0,0,0,0,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4} | {0,0,0,0,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4} + 4 | 4 | {0,0,0,0,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4} | {0,0,0,0,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4} + 4 | 4 | {0,0,0,0,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4} | {0,0,0,0,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4} + 4 | 4 | {0,0,0,0,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4} | {0,0,0,0,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4} + 4 | 4 | {0,0,0,0,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4} | {0,0,0,0,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4} + 4 | 5 | {0,0,0,0,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4,5,5} | {0,0,0,0,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4,5} + 4 | 5 | {0,0,0,0,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4,5,5} | {0,0,0,0,1,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4,5} + 5 | 0 | {0,0} | {0} + 5 | 0 | {0,0} | {0} + 5 | 1 | {0,0,1,1,1} | {0,0,1,1} + 5 | 1 | {0,0,1,1,1} | {0,0,1,1} + 5 | 1 | {0,0,1,1,1} | {0,0,1,1} + 5 | 2 | {0,0,1,1,1,2,2,2,2,2,2} | {0,0,1,1,1,2,2,2,2,2} + 5 | 2 | {0,0,1,1,1,2,2,2,2,2,2} | {0,0,1,1,1,2,2,2,2,2} + 5 | 2 | {0,0,1,1,1,2,2,2,2,2,2} | {0,0,1,1,1,2,2,2,2,2} + 5 | 2 | {0,0,1,1,1,2,2,2,2,2,2} | {0,0,1,1,1,2,2,2,2,2} + 5 | 2 | {0,0,1,1,1,2,2,2,2,2,2} | {0,0,1,1,1,2,2,2,2,2} + 5 | 2 | {0,0,1,1,1,2,2,2,2,2,2} | {0,0,1,1,1,2,2,2,2,2} + 5 | 3 | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3} | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3} + 5 | 3 | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3} | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3} + 5 | 3 | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3} | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3} + 5 | 3 | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3} | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3} + 5 | 3 | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3} | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3} + 5 | 3 | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3} | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3} + 5 | 3 | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3} | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3} + 5 | 3 | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3} | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3} + 5 | 3 | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3} | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3} + 5 | 4 | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4} | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4} + 5 | 4 | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4} | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4} + 5 | 4 | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4} | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4} + 5 | 5 | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4,5,5,5} | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4,5,5} + 5 | 5 | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4,5,5,5} | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4,5,5} + 5 | 5 | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4,5,5,5} | {0,0,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4,5,5} +(66 rows) + +-- test preceding and following on RANGE window +SELECT + user_id, + value_1, + array_agg(value_1) OVER range_window, + array_agg(value_1) OVER range_window_exclude +FROM + users_table +WHERE + user_id > 2 AND user_id < 6 +WINDOW + range_window as (PARTITION BY user_id ORDER BY value_1 RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING), + range_window_exclude as (PARTITION BY user_id ORDER BY value_1 RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING EXCLUDE CURRENT ROW) +ORDER BY + user_id, value_1; + user_id | value_1 | array_agg | array_agg +---------+---------+---------------------------------------+------------------------------------- + 3 | 0 | {0,1,1,1,1,1,1} | {1,1,1,1,1,1} + 3 | 1 | {0,1,1,1,1,1,1,2,2} | {0,1,1,1,1,1,2,2} + 3 | 1 | {0,1,1,1,1,1,1,2,2} | {0,1,1,1,1,1,2,2} + 3 | 1 | {0,1,1,1,1,1,1,2,2} | {0,1,1,1,1,1,2,2} + 3 | 1 | {0,1,1,1,1,1,1,2,2} | {0,1,1,1,1,1,2,2} + 3 | 1 | {0,1,1,1,1,1,1,2,2} | {0,1,1,1,1,1,2,2} + 3 | 1 | {0,1,1,1,1,1,1,2,2} | {0,1,1,1,1,1,2,2} + 3 | 2 | {1,1,1,1,1,1,2,2,3,3,3} | {1,1,1,1,1,1,2,3,3,3} + 3 | 2 | {1,1,1,1,1,1,2,2,3,3,3} | {1,1,1,1,1,1,2,3,3,3} + 3 | 3 | {2,2,3,3,3,4,4,4,4} | {2,2,3,3,4,4,4,4} + 3 | 3 | {2,2,3,3,3,4,4,4,4} | {2,2,3,3,4,4,4,4} + 3 | 3 | {2,2,3,3,3,4,4,4,4} | {2,2,3,3,4,4,4,4} + 3 | 4 | {3,3,3,4,4,4,4,5} | {3,3,3,4,4,4,5} + 3 | 4 | {3,3,3,4,4,4,4,5} | {3,3,3,4,4,4,5} + 3 | 4 | {3,3,3,4,4,4,4,5} | {3,3,3,4,4,4,5} + 3 | 4 | {3,3,3,4,4,4,4,5} | {3,3,3,4,4,4,5} + 3 | 5 | {4,4,4,4,5} | {4,4,4,4} + 4 | 0 | {0,0,0,0,1} | {0,0,0,1} + 4 | 0 | {0,0,0,0,1} | {0,0,0,1} + 4 | 0 | {0,0,0,0,1} | {0,0,0,1} + 4 | 0 | {0,0,0,0,1} | {0,0,0,1} + 4 | 1 | {0,0,0,0,1,2,2,2} | {0,0,0,0,2,2,2} + 4 | 2 | {1,2,2,2,3,3,3,3,3,3} | {1,2,2,3,3,3,3,3,3} + 4 | 2 | {1,2,2,2,3,3,3,3,3,3} | {1,2,2,3,3,3,3,3,3} + 4 | 2 | {1,2,2,2,3,3,3,3,3,3} | {1,2,2,3,3,3,3,3,3} + 4 | 3 | {2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4} | {2,2,2,3,3,3,3,3,4,4,4,4,4,4,4} + 4 | 3 | {2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4} | {2,2,2,3,3,3,3,3,4,4,4,4,4,4,4} + 4 | 3 | {2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4} | {2,2,2,3,3,3,3,3,4,4,4,4,4,4,4} + 4 | 3 | {2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4} | {2,2,2,3,3,3,3,3,4,4,4,4,4,4,4} + 4 | 3 | {2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4} | {2,2,2,3,3,3,3,3,4,4,4,4,4,4,4} + 4 | 3 | {2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4} | {2,2,2,3,3,3,3,3,4,4,4,4,4,4,4} + 4 | 4 | {3,3,3,3,3,3,4,4,4,4,4,4,4,5,5} | {3,3,3,3,3,3,4,4,4,4,4,4,5,5} + 4 | 4 | {3,3,3,3,3,3,4,4,4,4,4,4,4,5,5} | {3,3,3,3,3,3,4,4,4,4,4,4,5,5} + 4 | 4 | {3,3,3,3,3,3,4,4,4,4,4,4,4,5,5} | {3,3,3,3,3,3,4,4,4,4,4,4,5,5} + 4 | 4 | {3,3,3,3,3,3,4,4,4,4,4,4,4,5,5} | {3,3,3,3,3,3,4,4,4,4,4,4,5,5} + 4 | 4 | {3,3,3,3,3,3,4,4,4,4,4,4,4,5,5} | {3,3,3,3,3,3,4,4,4,4,4,4,5,5} + 4 | 4 | {3,3,3,3,3,3,4,4,4,4,4,4,4,5,5} | {3,3,3,3,3,3,4,4,4,4,4,4,5,5} + 4 | 4 | {3,3,3,3,3,3,4,4,4,4,4,4,4,5,5} | {3,3,3,3,3,3,4,4,4,4,4,4,5,5} + 4 | 5 | {4,4,4,4,4,4,4,5,5} | {4,4,4,4,4,4,4,5} + 4 | 5 | {4,4,4,4,4,4,4,5,5} | {4,4,4,4,4,4,4,5} + 5 | 0 | {0,0,1,1,1} | {0,1,1,1} + 5 | 0 | {0,0,1,1,1} | {0,1,1,1} + 5 | 1 | {0,0,1,1,1,2,2,2,2,2,2} | {0,0,1,1,2,2,2,2,2,2} + 5 | 1 | {0,0,1,1,1,2,2,2,2,2,2} | {0,0,1,1,2,2,2,2,2,2} + 5 | 1 | {0,0,1,1,1,2,2,2,2,2,2} | {0,0,1,1,2,2,2,2,2,2} + 5 | 2 | {1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3} | {1,1,1,2,2,2,2,2,3,3,3,3,3,3,3,3,3} + 5 | 2 | {1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3} | {1,1,1,2,2,2,2,2,3,3,3,3,3,3,3,3,3} + 5 | 2 | {1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3} | {1,1,1,2,2,2,2,2,3,3,3,3,3,3,3,3,3} + 5 | 2 | {1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3} | {1,1,1,2,2,2,2,2,3,3,3,3,3,3,3,3,3} + 5 | 2 | {1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3} | {1,1,1,2,2,2,2,2,3,3,3,3,3,3,3,3,3} + 5 | 2 | {1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3} | {1,1,1,2,2,2,2,2,3,3,3,3,3,3,3,3,3} + 5 | 3 | {2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4} | {2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4} + 5 | 3 | {2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4} | {2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4} + 5 | 3 | {2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4} | {2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4} + 5 | 3 | {2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4} | {2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4} + 5 | 3 | {2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4} | {2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4} + 5 | 3 | {2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4} | {2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4} + 5 | 3 | {2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4} | {2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4} + 5 | 3 | {2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4} | {2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4} + 5 | 3 | {2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4} | {2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4} + 5 | 4 | {3,3,3,3,3,3,3,3,3,4,4,4,5,5,5} | {3,3,3,3,3,3,3,3,3,4,4,5,5,5} + 5 | 4 | {3,3,3,3,3,3,3,3,3,4,4,4,5,5,5} | {3,3,3,3,3,3,3,3,3,4,4,5,5,5} + 5 | 4 | {3,3,3,3,3,3,3,3,3,4,4,4,5,5,5} | {3,3,3,3,3,3,3,3,3,4,4,5,5,5} + 5 | 5 | {4,4,4,5,5,5} | {4,4,4,5,5} + 5 | 5 | {4,4,4,5,5,5} | {4,4,4,5,5} + 5 | 5 | {4,4,4,5,5,5} | {4,4,4,5,5} +(66 rows) + +-- test preceding and following on ROW window +SELECT + user_id, + value_1, + array_agg(value_1) OVER row_window, + array_agg(value_1) OVER row_window_exclude +FROM + users_table +WHERE + user_id > 2 and user_id < 6 +WINDOW + row_window as (PARTITION BY user_id ORDER BY value_1 ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING), + row_window_exclude as (PARTITION BY user_id ORDER BY value_1 ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING EXCLUDE CURRENT ROW) +ORDER BY + user_id, value_1; + user_id | value_1 | array_agg | array_agg +---------+---------+-----------+----------- + 3 | 0 | {0,1} | {1} + 3 | 1 | {1,1,1} | {1,1} + 3 | 1 | {1,1,2} | {1,2} + 3 | 1 | {0,1,1} | {0,1} + 3 | 1 | {1,1,1} | {1,1} + 3 | 1 | {1,1,1} | {1,1} + 3 | 1 | {1,1,1} | {1,1} + 3 | 2 | {1,2,2} | {1,2} + 3 | 2 | {2,2,3} | {2,3} + 3 | 3 | {2,3,3} | {2,3} + 3 | 3 | {3,3,4} | {3,4} + 3 | 3 | {3,3,3} | {3,3} + 3 | 4 | {4,4,4} | {4,4} + 3 | 4 | {4,4,4} | {4,4} + 3 | 4 | {3,4,4} | {3,4} + 3 | 4 | {4,4,5} | {4,5} + 3 | 5 | {4,5} | {4} + 4 | 0 | {0,0,1} | {0,1} + 4 | 0 | {0,0,0} | {0,0} + 4 | 0 | {0,0} | {0} + 4 | 0 | {0,0,0} | {0,0} + 4 | 1 | {0,1,2} | {0,2} + 4 | 2 | {2,2,3} | {2,3} + 4 | 2 | {2,2,2} | {2,2} + 4 | 2 | {1,2,2} | {1,2} + 4 | 3 | {3,3,4} | {3,4} + 4 | 3 | {3,3,3} | {3,3} + 4 | 3 | {3,3,3} | {3,3} + 4 | 3 | {3,3,3} | {3,3} + 4 | 3 | {3,3,3} | {3,3} + 4 | 3 | {2,3,3} | {2,3} + 4 | 4 | {3,4,4} | {3,4} + 4 | 4 | {4,4,4} | {4,4} + 4 | 4 | {4,4,4} | {4,4} + 4 | 4 | {4,4,4} | {4,4} + 4 | 4 | {4,4,4} | {4,4} + 4 | 4 | {4,4,4} | {4,4} + 4 | 4 | {4,4,5} | {4,5} + 4 | 5 | {5,5} | {5} + 4 | 5 | {4,5,5} | {4,5} + 5 | 0 | {0,0,1} | {0,1} + 5 | 0 | {0,0} | {0} + 5 | 1 | {1,1,1} | {1,1} + 5 | 1 | {1,1,2} | {1,2} + 5 | 1 | {0,1,1} | {0,1} + 5 | 2 | {2,2,2} | {2,2} + 5 | 2 | {1,2,2} | {1,2} + 5 | 2 | {2,2,3} | {2,3} + 5 | 2 | {2,2,2} | {2,2} + 5 | 2 | {2,2,2} | {2,2} + 5 | 2 | {2,2,2} | {2,2} + 5 | 3 | {3,3,4} | {3,4} + 5 | 3 | {3,3,3} | {3,3} + 5 | 3 | {3,3,3} | {3,3} + 5 | 3 | {3,3,3} | {3,3} + 5 | 3 | {3,3,3} | {3,3} + 5 | 3 | {3,3,3} | {3,3} + 5 | 3 | {3,3,3} | {3,3} + 5 | 3 | {3,3,3} | {3,3} + 5 | 3 | {2,3,3} | {2,3} + 5 | 4 | {4,4,5} | {4,5} + 5 | 4 | {4,4,4} | {4,4} + 5 | 4 | {3,4,4} | {3,4} + 5 | 5 | {5,5} | {5} + 5 | 5 | {5,5,5} | {5,5} + 5 | 5 | {4,5,5} | {4,5} +(66 rows) + -- some tests with GROUP BY, HAVING and LIMIT SELECT user_id, sum(event_type) OVER my_win , event_type diff --git a/src/test/regress/expected/window_functions_0.out b/src/test/regress/expected/window_functions_0.out new file mode 100644 index 000000000..305d2c2a1 --- /dev/null +++ b/src/test/regress/expected/window_functions_0.out @@ -0,0 +1,943 @@ +-- =================================================================== +-- test top level window functions that are pushdownable +-- =================================================================== +SHOW server_version \gset +SELECT substring(:'server_version', '\d+')::int > 10 AS version_above_ten; + version_above_ten +------------------- + f +(1 row) + +-- a very simple window function with an aggregate and a window function +-- distribution column is on the partition by clause +SELECT + user_id, COUNT(*) OVER (PARTITION BY user_id), + rank() OVER (PARTITION BY user_id) +FROM + users_table +ORDER BY + 1 DESC, 2 DESC, 3 DESC +LIMIT 5; + user_id | count | rank +---------+-------+------ + 6 | 10 | 1 + 6 | 10 | 1 + 6 | 10 | 1 + 6 | 10 | 1 + 6 | 10 | 1 +(5 rows) + +-- a more complicated window clause, including an aggregate +-- in both the window clause and the target entry +SELECT + user_id, avg(avg(value_3)) OVER (PARTITION BY user_id, MIN(value_2)) +FROM + users_table +GROUP BY + 1 +ORDER BY + 2 DESC NULLS LAST, 1 DESC; + user_id | avg +---------+------------------ + 2 | 3 + 4 | 2.82608695652174 + 3 | 2.70588235294118 + 6 | 2.6 + 1 | 2.57142857142857 + 5 | 2.46153846153846 +(6 rows) + +-- window clause operates on the results of a subquery +SELECT + user_id, max(value_1) OVER (PARTITION BY user_id, MIN(value_2)) +FROM ( + SELECT + DISTINCT us.user_id, us.value_2, value_1, random() as r1 + FROM + users_table as us, events_table + WHERE + us.user_id = events_table.user_id AND event_type IN (1,2) + ORDER BY + user_id, value_2 + ) s +GROUP BY + 1, value_1 +ORDER BY + 2 DESC, 1; + user_id | max +---------+----- + 1 | 5 + 3 | 5 + 3 | 5 + 4 | 5 + 5 | 5 + 5 | 5 + 6 | 5 + 6 | 5 + 1 | 4 + 2 | 4 + 3 | 4 + 3 | 4 + 3 | 4 + 4 | 4 + 4 | 4 + 5 | 4 + 5 | 4 + 1 | 3 + 2 | 3 + 2 | 3 + 2 | 3 + 6 | 3 + 2 | 2 + 4 | 2 + 4 | 2 + 4 | 2 + 6 | 2 + 1 | 1 + 3 | 1 + 5 | 1 + 6 | 1 + 5 | 0 +(32 rows) + +-- window function operates on the results of +-- a join +SELECT + us.user_id, + SUM(us.value_1) OVER (PARTITION BY us.user_id) +FROM + users_table us + JOIN + events_table ev + ON (us.user_id = ev.user_id) +GROUP BY + 1, + value_1 +ORDER BY + 1, + 2 +LIMIT 5; + user_id | sum +---------+----- + 1 | 13 + 1 | 13 + 1 | 13 + 1 | 13 + 2 | 10 +(5 rows) + +-- the same query, but this time join with an alias +SELECT + user_id, value_1, SUM(j.value_1) OVER (PARTITION BY j.user_id) +FROM + (users_table us + JOIN + events_table ev + USING (user_id ) + ) j +GROUP BY + user_id, + value_1 +ORDER BY + 3 DESC, 2 DESC, 1 DESC +LIMIT 5; + user_id | value_1 | sum +---------+---------+----- + 5 | 5 | 15 + 4 | 5 | 15 + 3 | 5 | 15 + 5 | 4 | 15 + 4 | 4 | 15 +(5 rows) + +-- querying views that have window functions should be ok +CREATE VIEW window_view AS +SELECT + DISTINCT user_id, rank() OVER (PARTITION BY user_id ORDER BY value_1) +FROM + users_table +GROUP BY + user_id, value_1 +HAVING count(*) > 1; +-- Window function in View works +SELECT * +FROM + window_view +ORDER BY + 2 DESC, 1 +LIMIT 10; + user_id | rank +---------+------ + 5 | 6 + 2 | 5 + 4 | 5 + 5 | 5 + 2 | 4 + 3 | 4 + 4 | 4 + 5 | 4 + 6 | 4 + 2 | 3 +(10 rows) + +-- the other way around also should work fine +-- query a view using window functions +CREATE VIEW users_view AS SELECT * FROM users_table; +SELECT + DISTINCT user_id, rank() OVER (PARTITION BY user_id ORDER BY value_1) +FROM + users_view +GROUP BY + user_id, value_1 +HAVING count(*) > 4 +ORDER BY + 2 DESC, 1; + user_id | rank +---------+------ + 4 | 2 + 5 | 2 + 2 | 1 + 3 | 1 + 4 | 1 + 5 | 1 +(6 rows) + +DROP VIEW users_view, window_view; +-- window function uses columns from two different tables +SELECT + DISTINCT ON (events_table.user_id, rnk) events_table.user_id, rank() OVER my_win AS rnk +FROM + events_table, users_table +WHERE + users_table.user_id = events_table.user_id +WINDOW + my_win AS (PARTITION BY events_table.user_id, users_table.value_1 ORDER BY events_table.time DESC) +ORDER BY + rnk DESC, 1 DESC +LIMIT 10; + user_id | rnk +---------+----- + 3 | 121 + 5 | 118 + 2 | 116 + 3 | 115 + 4 | 113 + 2 | 111 + 5 | 109 + 3 | 109 + 4 | 106 + 2 | 106 +(10 rows) + +-- the same query with reference table column is also on the partition by clause +SELECT + DISTINCT ON (events_table.user_id, rnk) events_table.user_id, rank() OVER my_win AS rnk +FROM + events_table, users_ref_test_table uref +WHERE + uref.id = events_table.user_id +WINDOW + my_win AS (PARTITION BY events_table.user_id, uref.k_no ORDER BY events_table.time DESC) +ORDER BY + rnk DESC, 1 DESC +LIMIT 10; + user_id | rnk +---------+----- + 2 | 24 + 2 | 23 + 2 | 22 + 3 | 21 + 2 | 21 + 3 | 20 + 2 | 20 + 3 | 19 + 2 | 19 + 3 | 18 +(10 rows) + +-- similar query with no distribution column is on the partition by clause +-- is not supported +SELECT + DISTINCT ON (events_table.user_id, rnk) events_table.user_id, rank() OVER my_win AS rnk +FROM + events_table, users_ref_test_table uref +WHERE + uref.id = events_table.user_id +WINDOW + my_win AS (PARTITION BY events_table.value_2, uref.k_no ORDER BY events_table.time DESC) +ORDER BY + rnk DESC, 1 DESC +LIMIT 10; +ERROR: could not run distributed query because the window function that is used cannot be pushed down +HINT: Window functions are supported in two ways. Either add an equality filter on the distributed tables' partition column or use the window functions with a PARTITION BY clause containing the distribution column +-- ORDER BY in the window function is an aggragate +SELECT + user_id, rank() OVER my_win as rnk, avg(value_2) as avg_val_2 +FROM + events_table +GROUP BY + user_id, date_trunc('day', time) +WINDOW + my_win AS (PARTITION BY user_id ORDER BY avg(event_type) DESC) +ORDER BY + 3 DESC, 2 DESC, 1 DESC; + user_id | rnk | avg_val_2 +---------+-----+-------------------- + 1 | 1 | 3.3750000000000000 + 3 | 2 | 3.1666666666666667 + 5 | 1 | 2.6666666666666667 + 6 | 1 | 2.5000000000000000 + 4 | 1 | 2.5000000000000000 + 2 | 1 | 2.4736842105263158 + 4 | 2 | 2.4000000000000000 + 1 | 2 | 2.1428571428571429 + 5 | 2 | 2.0909090909090909 + 6 | 2 | 2.0000000000000000 + 2 | 2 | 2.0000000000000000 + 3 | 1 | 1.8000000000000000 +(12 rows) + +-- lets push the limits of writing complex expressions aling with the window functions +SELECT + COUNT(*) OVER (PARTITION BY user_id, user_id + 1), + rank() OVER (PARTITION BY user_id) as cnt1, + COUNT(*) OVER (PARTITION BY user_id, abs(value_1 - value_2)) as cnt2, + date_trunc('min', lag(time) OVER (PARTITION BY user_id)) as datee, + rank() OVER my_win as rnnk, + avg(CASE + WHEN user_id > 4 + THEN value_1 + ELSE value_2 + END) FILTER (WHERE user_id > 2) OVER my_win_2 as filtered_count, + sum(user_id * (5.0 / (value_1 + value_2 + 0.1)) * value_3) FILTER (WHERE value_1::text LIKE '%1%') OVER my_win_4 as cnt_with_filter_2 +FROM + users_table +WINDOW + my_win AS (PARTITION BY user_id, (value_1%3)::int ORDER BY time DESC), + my_win_2 AS (PARTITION BY user_id, (value_1)::int ORDER BY time DESC), + my_win_3 AS (PARTITION BY user_id, date_trunc('min', time)), + my_win_4 AS (my_win_3 ORDER BY value_2, value_3) +ORDER BY + cnt_with_filter_2 DESC NULLS LAST, filtered_count DESC NULLS LAST, datee DESC NULLS LAST, rnnk DESC, cnt2 DESC, cnt1 DESC, user_id DESC +LIMIT 5; + count | cnt1 | cnt2 | datee | rnnk | filtered_count | cnt_with_filter_2 +-------+------+------+--------------------------+------+------------------------+------------------- + 23 | 1 | 7 | Thu Nov 23 02:14:00 2017 | 6 | 0.00000000000000000000 | 72.7272727272727 + 10 | 1 | 3 | Wed Nov 22 23:01:00 2017 | 1 | 1.00000000000000000000 | 57.1428571428571 + 17 | 1 | 5 | Wed Nov 22 23:24:00 2017 | 8 | 3.0000000000000000 | 28.5714285714286 + 17 | 1 | 5 | | 10 | 2.6666666666666667 | 28.5714285714286 + 17 | 1 | 5 | Thu Nov 23 00:15:00 2017 | 7 | 3.6666666666666667 | 24.1935483870968 +(5 rows) + +-- some tests with GROUP BY along with PARTITION BY +SELECT + user_id, + rank() OVER my_win as my_rank, + avg(avg(event_type)) OVER my_win_2 as avg, + max(time) as mx_time +FROM + events_table +GROUP BY + user_id, + value_2 +WINDOW + my_win AS (PARTITION BY user_id, max(event_type) ORDER BY count(*) DESC), + my_win_2 AS (PARTITION BY user_id, avg(user_id) ORDER BY count(*) DESC) +ORDER BY + avg DESC, + mx_time DESC, + my_rank DESC, + user_id DESC; + user_id | my_rank | avg | mx_time +---------+---------+------------------------+--------------------------------- + 6 | 1 | 3.0000000000000000 | Thu Nov 23 14:00:13.20013 2017 + 6 | 2 | 3.0000000000000000 | Thu Nov 23 11:16:13.106691 2017 + 6 | 1 | 3.0000000000000000 | Thu Nov 23 07:27:32.822068 2017 + 3 | 1 | 2.9857142857142857 | Thu Nov 23 16:31:56.219594 2017 + 4 | 2 | 2.9555555555555556 | Thu Nov 23 14:19:25.765876 2017 + 4 | 1 | 2.9555555555555556 | Thu Nov 23 08:36:53.871919 2017 + 1 | 4 | 2.8633333333333333 | Wed Nov 22 21:06:57.457147 2017 + 1 | 1 | 2.8250000000000000 | Thu Nov 23 21:54:46.924477 2017 + 2 | 2 | 2.7738095238095238 | Thu Nov 23 13:27:37.441959 2017 + 1 | 2 | 2.7722222222222222 | Thu Nov 23 09:23:30.994345 2017 + 3 | 1 | 2.7682539682539682 | Thu Nov 23 01:17:49.040685 2017 + 2 | 1 | 2.7142857142857143 | Thu Nov 23 15:58:49.273421 2017 + 1 | 3 | 2.5791666666666667 | Thu Nov 23 11:09:38.074595 2017 + 3 | 1 | 2.5714285714285714 | Thu Nov 23 16:44:41.903713 2017 + 2 | 1 | 2.5158730158730159 | Thu Nov 23 14:02:47.738901 2017 + 4 | 1 | 2.47777777777777778333 | Thu Nov 23 16:20:33.264457 2017 + 4 | 3 | 2.47777777777777778333 | Thu Nov 23 08:14:18.231273 2017 + 4 | 3 | 2.47777777777777778333 | Thu Nov 23 07:32:45.521278 2017 + 1 | 1 | 2.4000000000000000 | Thu Nov 23 10:23:27.617726 2017 + 2 | 1 | 2.3869047619047619 | Thu Nov 23 17:26:14.563216 2017 + 3 | 1 | 2.3841269841269841 | Thu Nov 23 18:08:26.550729 2017 + 3 | 1 | 2.3841269841269841 | Thu Nov 23 09:38:45.338008 2017 + 3 | 2 | 2.3841269841269841 | Thu Nov 23 06:44:50.887182 2017 + 2 | 2 | 2.3095238095238095 | Thu Nov 23 04:05:16.217731 2017 + 5 | 2 | 2.3000000000000000 | Thu Nov 23 14:28:51.833214 2017 + 5 | 2 | 2.3000000000000000 | Thu Nov 23 14:23:09.889786 2017 + 4 | 1 | 2.2000000000000000 | Thu Nov 23 18:10:21.338399 2017 + 2 | 1 | 2.09126984126984126667 | Thu Nov 23 03:35:04.321504 2017 + 5 | 1 | 2.0000000000000000 | Thu Nov 23 16:11:02.929469 2017 + 5 | 1 | 2.0000000000000000 | Thu Nov 23 14:40:40.467511 2017 + 5 | 1 | 2.0000000000000000 | Thu Nov 23 13:26:45.571108 2017 +(31 rows) + +-- test for range and rows mode and different window functions +-- mostly to make sure that deparsing works fine +SELECT + user_id, + rank() OVER (PARTITION BY user_id ROWS BETWEEN + UNBOUNDED PRECEDING AND CURRENT ROW), + dense_rank() OVER (PARTITION BY user_id RANGE BETWEEN + UNBOUNDED PRECEDING AND CURRENT ROW), + CUME_DIST() OVER (PARTITION BY user_id RANGE BETWEEN + UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING), + PERCENT_RANK() OVER (PARTITION BY user_id ORDER BY avg(value_1) RANGE BETWEEN + UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) +FROM + users_table +GROUP BY + 1 +ORDER BY + 4 DESC,3 DESC,2 DESC ,1 DESC; + user_id | rank | dense_rank | cume_dist | percent_rank +---------+------+------------+-----------+-------------- + 6 | 1 | 1 | 1 | 0 + 5 | 1 | 1 | 1 | 0 + 4 | 1 | 1 | 1 | 0 + 3 | 1 | 1 | 1 | 0 + 2 | 1 | 1 | 1 | 0 + 1 | 1 | 1 | 1 | 0 +(6 rows) + +-- test exclude supported +SELECT + user_id, + value_1, + array_agg(value_1) OVER (PARTITION BY user_id ORDER BY value_1 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), + array_agg(value_1) OVER (PARTITION BY user_id ORDER BY value_1 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE CURRENT ROW) +FROM + users_table +WHERE + user_id > 2 AND user_id < 6 +ORDER BY + user_id, value_1; +ERROR: syntax error at or near "EXCLUDE" +LINE 5: ...ANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE CU... + ^ +-- test preceding and following on RANGE window +SELECT + user_id, + value_1, + array_agg(value_1) OVER range_window, + array_agg(value_1) OVER range_window_exclude +FROM + users_table +WHERE + user_id > 2 AND user_id < 6 +WINDOW + range_window as (PARTITION BY user_id ORDER BY value_1 RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING), + range_window_exclude as (PARTITION BY user_id ORDER BY value_1 RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING EXCLUDE CURRENT ROW) +ORDER BY + user_id, value_1; +ERROR: RANGE PRECEDING is only supported with UNBOUNDED +LINE 11: ..._window as (PARTITION BY user_id ORDER BY value_1 RANGE BETW... + ^ +-- test preceding and following on ROW window +SELECT + user_id, + value_1, + array_agg(value_1) OVER row_window, + array_agg(value_1) OVER row_window_exclude +FROM + users_table +WHERE + user_id > 2 and user_id < 6 +WINDOW + row_window as (PARTITION BY user_id ORDER BY value_1 ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING), + row_window_exclude as (PARTITION BY user_id ORDER BY value_1 ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING EXCLUDE CURRENT ROW) +ORDER BY + user_id, value_1; +ERROR: syntax error at or near "EXCLUDE" +LINE 12: ...value_1 ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING EXCLUDE CU... + ^ +-- some tests with GROUP BY, HAVING and LIMIT +SELECT + user_id, sum(event_type) OVER my_win , event_type +FROM + events_table +GROUP BY + user_id, event_type +HAVING count(*) > 2 + WINDOW my_win AS (PARTITION BY user_id, max(event_type) ORDER BY count(*) DESC) +ORDER BY + 2 DESC, 3 DESC, 1 DESC +LIMIT + 5; + user_id | sum | event_type +---------+-----+------------ + 4 | 4 | 4 + 3 | 4 | 4 + 2 | 4 | 4 + 1 | 4 | 4 + 5 | 3 | 3 +(5 rows) + +-- Group by has more columns than partition by +SELECT + DISTINCT user_id, SUM(value_2) OVER (PARTITION BY user_id) +FROM + users_table +GROUP BY + user_id, value_1, value_2 +HAVING count(*) > 2 +ORDER BY + 2 DESC, 1 +LIMIT + 10; + user_id | sum +---------+----- + 5 | 3 + 4 | 2 +(2 rows) + +SELECT + DISTINCT ON (user_id) user_id, SUM(value_2) OVER (PARTITION BY user_id) +FROM + users_table +GROUP BY + user_id, value_1, value_2 +HAVING count(*) > 2 +ORDER BY + 1, 2 DESC +LIMIT + 10; + user_id | sum +---------+----- + 4 | 2 + 5 | 3 +(2 rows) + +SELECT + DISTINCT ON (SUM(value_1) OVER (PARTITION BY user_id)) user_id, SUM(value_2) OVER (PARTITION BY user_id) +FROM + users_table +GROUP BY + user_id, value_1, value_2 +HAVING count(*) > 2 +ORDER BY + (SUM(value_1) OVER (PARTITION BY user_id)) , 2 DESC, 1 +LIMIT + 10; + user_id | sum +---------+----- + 5 | 3 + 4 | 2 +(2 rows) + + +-- not a meaningful query, with interesting syntax +SELECT + user_id, + AVG(avg(value_1)) OVER (PARTITION BY user_id, max(user_id), MIN(value_2)), + AVG(avg(user_id)) OVER (PARTITION BY user_id, min(user_id), AVG(value_1)) +FROM + users_table +GROUP BY + 1 +ORDER BY + 3 DESC, 2 DESC, 1 DESC; + user_id | avg | avg +---------+--------------------+------------------------ + 6 | 2.1000000000000000 | 6.0000000000000000 + 5 | 2.6538461538461538 | 5.0000000000000000 + 4 | 2.7391304347826087 | 4.0000000000000000 + 3 | 2.3529411764705882 | 3.0000000000000000 + 2 | 2.3333333333333333 | 2.0000000000000000 + 1 | 3.2857142857142857 | 1.00000000000000000000 +(6 rows) + +EXPLAIN (COSTS FALSE) +SELECT + user_id, + AVG(avg(value_1)) OVER (PARTITION BY user_id, max(user_id), MIN(value_2)), + AVG(avg(user_id)) OVER (PARTITION BY user_id, min(user_id), AVG(value_1)) +FROM + users_table +GROUP BY + 1 +ORDER BY + 3 DESC, 2 DESC, 1 DESC; + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------- + Sort + Sort Key: remote_scan.avg_1 DESC, remote_scan.avg DESC, remote_scan.user_id DESC + -> HashAggregate + Group Key: remote_scan.user_id + -> Custom Scan (Citus Real-Time) + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=57637 dbname=regression + -> WindowAgg + -> Sort + Sort Key: users_table.user_id, (min(users_table.user_id)), (avg(users_table.value_1)) + -> WindowAgg + -> Sort + Sort Key: users_table.user_id, (max(users_table.user_id)), (min(users_table.value_2)) + -> HashAggregate + Group Key: users_table.user_id + -> Seq Scan on users_table_1400256 users_table +(18 rows) + +SELECT + user_id, + 1 + sum(value_1), + 1 + AVG(value_2) OVER (partition by user_id) +FROM + users_table +GROUP BY + user_id, value_2 +ORDER BY + user_id, value_2; + user_id | ?column? | ?column? +---------+----------+-------------------- + 1 | 5 | 3.2500000000000000 + 1 | 4 | 3.2500000000000000 + 1 | 6 | 3.2500000000000000 + 1 | 12 | 3.2500000000000000 + 2 | 3 | 3.5000000000000000 + 2 | 5 | 3.5000000000000000 + 2 | 13 | 3.5000000000000000 + 2 | 6 | 3.5000000000000000 + 2 | 17 | 3.5000000000000000 + 2 | 4 | 3.5000000000000000 + 3 | 3 | 4.0000000000000000 + 3 | 13 | 4.0000000000000000 + 3 | 10 | 4.0000000000000000 + 3 | 2 | 4.0000000000000000 + 3 | 17 | 4.0000000000000000 + 4 | 4 | 3.5000000000000000 + 4 | 28 | 3.5000000000000000 + 4 | 1 | 3.5000000000000000 + 4 | 11 | 3.5000000000000000 + 4 | 17 | 3.5000000000000000 + 4 | 8 | 3.5000000000000000 + 5 | 7 | 3.5000000000000000 + 5 | 17 | 3.5000000000000000 + 5 | 24 | 3.5000000000000000 + 5 | 9 | 3.5000000000000000 + 5 | 8 | 3.5000000000000000 + 5 | 10 | 3.5000000000000000 + 6 | 6 | 3.0000000000000000 + 6 | 3 | 3.0000000000000000 + 6 | 9 | 3.0000000000000000 + 6 | 3 | 3.0000000000000000 + 6 | 5 | 3.0000000000000000 +(32 rows) + +SELECT + user_id, + 1 + sum(value_1), + 1 + AVG(value_2) OVER (partition by user_id) +FROM + users_table +GROUP BY + user_id, value_2 +ORDER BY + 2 DESC, 1 +LIMIT 5; + user_id | ?column? | ?column? +---------+----------+-------------------- + 4 | 28 | 3.5000000000000000 + 5 | 24 | 3.5000000000000000 + 2 | 17 | 3.5000000000000000 + 3 | 17 | 4.0000000000000000 + 4 | 17 | 3.5000000000000000 +(5 rows) + +-- rank and ordering in the reverse order +SELECT + user_id, + avg(value_1), + RANK() OVER (partition by user_id order by value_2) +FROM + users_table +GROUP BY user_id, value_2 +ORDER BY user_id, value_2 DESC; + user_id | avg | rank +---------+------------------------+------ + 1 | 3.6666666666666667 | 4 + 1 | 2.5000000000000000 | 3 + 1 | 3.0000000000000000 | 2 + 1 | 4.0000000000000000 | 1 + 2 | 1.5000000000000000 | 6 + 2 | 3.2000000000000000 | 5 + 2 | 1.6666666666666667 | 4 + 2 | 3.0000000000000000 | 3 + 2 | 1.3333333333333333 | 2 + 2 | 2.0000000000000000 | 1 + 3 | 2.6666666666666667 | 5 + 3 | 1.00000000000000000000 | 4 + 3 | 3.0000000000000000 | 3 + 3 | 2.4000000000000000 | 2 + 3 | 1.00000000000000000000 | 1 + 4 | 3.5000000000000000 | 6 + 4 | 3.2000000000000000 | 5 + 4 | 3.3333333333333333 | 4 + 4 | 0.00000000000000000000 | 3 + 4 | 3.0000000000000000 | 2 + 4 | 1.00000000000000000000 | 1 + 5 | 3.0000000000000000 | 6 + 5 | 2.3333333333333333 | 5 + 5 | 1.6000000000000000 | 4 + 5 | 2.8750000000000000 | 3 + 5 | 3.2000000000000000 | 2 + 5 | 3.0000000000000000 | 1 + 6 | 1.3333333333333333 | 5 + 6 | 2.0000000000000000 | 4 + 6 | 4.0000000000000000 | 3 + 6 | 1.00000000000000000000 | 2 + 6 | 2.5000000000000000 | 1 +(32 rows) + +-- order by in the window function is same as avg(value_1) DESC +SELECT + user_id, + avg(value_1), + RANK() OVER (partition by user_id order by 1 / (1 + avg(value_1))) +FROM + users_table +GROUP BY user_id, value_2 +ORDER BY user_id, avg(value_1) DESC; + user_id | avg | rank +---------+------------------------+------ + 1 | 4.0000000000000000 | 1 + 1 | 3.6666666666666667 | 2 + 1 | 3.0000000000000000 | 3 + 1 | 2.5000000000000000 | 4 + 2 | 3.2000000000000000 | 1 + 2 | 3.0000000000000000 | 2 + 2 | 2.0000000000000000 | 3 + 2 | 1.6666666666666667 | 4 + 2 | 1.5000000000000000 | 5 + 2 | 1.3333333333333333 | 6 + 3 | 3.0000000000000000 | 1 + 3 | 2.6666666666666667 | 2 + 3 | 2.4000000000000000 | 3 + 3 | 1.00000000000000000000 | 4 + 3 | 1.00000000000000000000 | 4 + 4 | 3.5000000000000000 | 1 + 4 | 3.3333333333333333 | 2 + 4 | 3.2000000000000000 | 3 + 4 | 3.0000000000000000 | 4 + 4 | 1.00000000000000000000 | 5 + 4 | 0.00000000000000000000 | 6 + 5 | 3.2000000000000000 | 1 + 5 | 3.0000000000000000 | 2 + 5 | 3.0000000000000000 | 2 + 5 | 2.8750000000000000 | 4 + 5 | 2.3333333333333333 | 5 + 5 | 1.6000000000000000 | 6 + 6 | 4.0000000000000000 | 1 + 6 | 2.5000000000000000 | 2 + 6 | 2.0000000000000000 | 3 + 6 | 1.3333333333333333 | 4 + 6 | 1.00000000000000000000 | 5 +(32 rows) + +EXPLAIN (COSTS FALSE) +SELECT + user_id, + avg(value_1), + RANK() OVER (partition by user_id order by 1 / (1 + avg(value_1))) +FROM + users_table +GROUP BY user_id, value_2 +ORDER BY user_id, avg(value_1) DESC; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Sort + Sort Key: remote_scan.user_id, (pg_catalog.sum(((pg_catalog.sum(remote_scan.avg) / pg_catalog.sum(remote_scan.avg_1)))) / pg_catalog.sum(remote_scan.rank)) DESC + -> HashAggregate + Group Key: remote_scan.user_id, remote_scan.worker_column_5 + -> Custom Scan (Citus Real-Time) + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=57637 dbname=regression + -> WindowAgg + -> Sort + Sort Key: users_table.user_id, (('1'::numeric / ('1'::numeric + avg(users_table.value_1)))) + -> HashAggregate + Group Key: users_table.user_id, users_table.value_2 + -> Seq Scan on users_table_1400256 users_table +(15 rows) + +-- order by in the window function is same as avg(value_1) DESC +SELECT + user_id, + avg(value_1), + RANK() OVER (partition by user_id order by 1 / (1 + avg(value_1))) +FROM + users_table +GROUP BY user_id, value_2 +ORDER BY user_id, avg(value_1) DESC; + user_id | avg | rank +---------+------------------------+------ + 1 | 4.0000000000000000 | 1 + 1 | 3.6666666666666667 | 2 + 1 | 3.0000000000000000 | 3 + 1 | 2.5000000000000000 | 4 + 2 | 3.2000000000000000 | 1 + 2 | 3.0000000000000000 | 2 + 2 | 2.0000000000000000 | 3 + 2 | 1.6666666666666667 | 4 + 2 | 1.5000000000000000 | 5 + 2 | 1.3333333333333333 | 6 + 3 | 3.0000000000000000 | 1 + 3 | 2.6666666666666667 | 2 + 3 | 2.4000000000000000 | 3 + 3 | 1.00000000000000000000 | 4 + 3 | 1.00000000000000000000 | 4 + 4 | 3.5000000000000000 | 1 + 4 | 3.3333333333333333 | 2 + 4 | 3.2000000000000000 | 3 + 4 | 3.0000000000000000 | 4 + 4 | 1.00000000000000000000 | 5 + 4 | 0.00000000000000000000 | 6 + 5 | 3.2000000000000000 | 1 + 5 | 3.0000000000000000 | 2 + 5 | 3.0000000000000000 | 2 + 5 | 2.8750000000000000 | 4 + 5 | 2.3333333333333333 | 5 + 5 | 1.6000000000000000 | 6 + 6 | 4.0000000000000000 | 1 + 6 | 2.5000000000000000 | 2 + 6 | 2.0000000000000000 | 3 + 6 | 1.3333333333333333 | 4 + 6 | 1.00000000000000000000 | 5 +(32 rows) + +-- limit is not pushed down to worker !! +EXPLAIN (COSTS FALSE) +SELECT + user_id, + avg(value_1), + RANK() OVER (partition by user_id order by 1 / (1 + avg(value_1))) +FROM + users_table +GROUP BY user_id, value_2 +ORDER BY user_id, avg(value_1) DESC +LIMIT 5; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Limit + -> Sort + Sort Key: remote_scan.user_id, (pg_catalog.sum(((pg_catalog.sum(remote_scan.avg) / pg_catalog.sum(remote_scan.avg_1)))) / pg_catalog.sum(remote_scan.rank)) DESC + -> HashAggregate + Group Key: remote_scan.user_id, remote_scan.worker_column_5 + -> Custom Scan (Citus Real-Time) + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=57637 dbname=regression + -> WindowAgg + -> Sort + Sort Key: users_table.user_id, (('1'::numeric / ('1'::numeric + avg(users_table.value_1)))) + -> HashAggregate + Group Key: users_table.user_id, users_table.value_2 + -> Seq Scan on users_table_1400256 users_table +(16 rows) + +EXPLAIN (COSTS FALSE) +SELECT + user_id, + avg(value_1), + RANK() OVER (partition by user_id order by 1 / (1 + avg(value_1))) +FROM + users_table +GROUP BY user_id, value_2 +ORDER BY user_id, avg(value_1) DESC +LIMIT 5; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Limit + -> Sort + Sort Key: remote_scan.user_id, (pg_catalog.sum(((pg_catalog.sum(remote_scan.avg) / pg_catalog.sum(remote_scan.avg_1)))) / pg_catalog.sum(remote_scan.rank)) DESC + -> HashAggregate + Group Key: remote_scan.user_id, remote_scan.worker_column_5 + -> Custom Scan (Citus Real-Time) + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=57637 dbname=regression + -> WindowAgg + -> Sort + Sort Key: users_table.user_id, (('1'::numeric / ('1'::numeric + avg(users_table.value_1)))) + -> HashAggregate + Group Key: users_table.user_id, users_table.value_2 + -> Seq Scan on users_table_1400256 users_table +(16 rows) + +EXPLAIN (COSTS FALSE) +SELECT + user_id, + avg(value_1), + RANK() OVER (partition by user_id order by 1 / (1 + sum(value_2))) +FROM + users_table +GROUP BY user_id, value_2 +ORDER BY user_id, avg(value_1) DESC +LIMIT 5; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Limit + -> Sort + Sort Key: remote_scan.user_id, (pg_catalog.sum(((pg_catalog.sum(remote_scan.avg) / pg_catalog.sum(remote_scan.avg_1)))) / pg_catalog.sum(remote_scan.rank)) DESC + -> HashAggregate + Group Key: remote_scan.user_id, remote_scan.worker_column_5 + -> Custom Scan (Citus Real-Time) + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=57637 dbname=regression + -> WindowAgg + -> Sort + Sort Key: users_table.user_id, ((1 / (1 + sum(users_table.value_2)))) + -> HashAggregate + Group Key: users_table.user_id, users_table.value_2 + -> Seq Scan on users_table_1400256 users_table +(16 rows) + +EXPLAIN (COSTS FALSE) +SELECT + user_id, + avg(value_1), + RANK() OVER (partition by user_id order by sum(value_2)) +FROM + users_table +GROUP BY user_id, value_2 +ORDER BY user_id, avg(value_1) DESC +LIMIT 5; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Limit + -> Sort + Sort Key: remote_scan.user_id, (pg_catalog.sum(((pg_catalog.sum(remote_scan.avg) / pg_catalog.sum(remote_scan.avg_1)))) / pg_catalog.sum(remote_scan.rank)) DESC + -> HashAggregate + Group Key: remote_scan.user_id, remote_scan.worker_column_5 + -> Custom Scan (Citus Real-Time) + Task Count: 4 + Tasks Shown: One of 4 + -> Task + Node: host=localhost port=57637 dbname=regression + -> WindowAgg + -> Sort + Sort Key: users_table.user_id, (sum(users_table.value_2)) + -> HashAggregate + Group Key: users_table.user_id, users_table.value_2 + -> Seq Scan on users_table_1400256 users_table +(16 rows) + diff --git a/src/test/regress/sql/window_functions.sql b/src/test/regress/sql/window_functions.sql index 03db00915..071c45519 100644 --- a/src/test/regress/sql/window_functions.sql +++ b/src/test/regress/sql/window_functions.sql @@ -2,6 +2,9 @@ -- test top level window functions that are pushdownable -- =================================================================== +SHOW server_version \gset +SELECT substring(:'server_version', '\d+')::int > 10 AS version_above_ten; + -- a very simple window function with an aggregate and a window function -- distribution column is on the partition by clause SELECT @@ -225,6 +228,51 @@ GROUP BY ORDER BY 4 DESC,3 DESC,2 DESC ,1 DESC; +-- test exclude supported +SELECT + user_id, + value_1, + array_agg(value_1) OVER (PARTITION BY user_id ORDER BY value_1 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), + array_agg(value_1) OVER (PARTITION BY user_id ORDER BY value_1 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE CURRENT ROW) +FROM + users_table +WHERE + user_id > 2 AND user_id < 6 +ORDER BY + user_id, value_1; + +-- test preceding and following on RANGE window +SELECT + user_id, + value_1, + array_agg(value_1) OVER range_window, + array_agg(value_1) OVER range_window_exclude +FROM + users_table +WHERE + user_id > 2 AND user_id < 6 +WINDOW + range_window as (PARTITION BY user_id ORDER BY value_1 RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING), + range_window_exclude as (PARTITION BY user_id ORDER BY value_1 RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING EXCLUDE CURRENT ROW) +ORDER BY + user_id, value_1; + +-- test preceding and following on ROW window +SELECT + user_id, + value_1, + array_agg(value_1) OVER row_window, + array_agg(value_1) OVER row_window_exclude +FROM + users_table +WHERE + user_id > 2 and user_id < 6 +WINDOW + row_window as (PARTITION BY user_id ORDER BY value_1 ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING), + row_window_exclude as (PARTITION BY user_id ORDER BY value_1 ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING EXCLUDE CURRENT ROW) +ORDER BY + user_id, value_1; + -- some tests with GROUP BY, HAVING and LIMIT SELECT user_id, sum(event_type) OVER my_win , event_type