On 9th of January 2023, Tom Lane committed patch:
Invent random_normal() to provide normally-distributed random numbers. There is already a version of this in contrib/tablefunc, but it seems sufficiently widely useful to justify having it in core. Paul Ramsey Discussion: https://postgr.es/m/CACowWR0DqHAvOKUCNxTrASFkWsDLqKMd6WiXvVvaWg4pV1BMnQ@mail.gmail.com
Description tells is all, but let's see how that works.
Let's generate som random_normal() values, which can be done using:
=$ SELECT random_normal() AS v FROM generate_series(1,10); v ---------------------- 2.0769129968970774 0.4215059076426097 1.085988642195048 -0.5816049253906204 0.8020449529886824 -0.28712441889530904 0.3608747983496689 1.9320722370416128 1.4822705736995292 -1.8661221359997575 (10 ROWS)
and let's see the distribution of values. Let's say that we want to group them in ranges of 0.1, for example like this:
=$ SELECT round(random_normal()::NUMERIC, 1) AS v FROM generate_series(1,10) v ------ -2.2 0.2 -0.4 -1.3 0.3 -2.5 -0.5 1.4 0.3 0.0 (10 ROWS)
and now let's make lots of them, group by the rounded value, get count, and perhaps use this to generate “a graph":
=$ SELECT round( random_normal()::pg_catalog.numeric, 1 ) AS v, COUNT(*), repeat('#', (COUNT(*) / 100)::int4) FROM generate_series( 1, 100000 ) GROUP BY 1 ORDER BY 1; v | COUNT | repeat ------+-------+------------------------------------------ -4.6 | 1 | -4.0 | 1 | -3.9 | 6 | -3.7 | 5 | -3.6 | 5 | -3.5 | 9 | -3.4 | 12 | -3.3 | 9 | -3.2 | 23 | -3.1 | 36 | -3.0 | 50 | -2.9 | 49 | -2.8 | 90 | -2.7 | 125 | # -2.6 | 115 | # -2.5 | 181 | # -2.4 | 217 | ## -2.3 | 286 | ## -2.2 | 360 | ### -2.1 | 436 | #### -2.0 | 521 | ##### -1.9 | 682 | ###### -1.8 | 777 | ####### -1.7 | 963 | ######### -1.6 | 1085 | ########## -1.5 | 1317 | ############# -1.4 | 1531 | ############### -1.3 | 1718 | ################# -1.2 | 1982 | ################### -1.1 | 2137 | ##################### -1.0 | 2425 | ######################## -0.9 | 2652 | ########################## -0.8 | 2949 | ############################# -0.7 | 3090 | ############################## -0.6 | 3395 | ################################# -0.5 | 3529 | ################################### -0.4 | 3759 | ##################################### -0.3 | 3827 | ###################################### -0.2 | 3916 | ####################################### -0.1 | 3898 | ###################################### 0.0 | 3952 | ####################################### 0.1 | 4017 | ######################################## 0.2 | 3924 | ####################################### 0.3 | 3822 | ###################################### 0.4 | 3656 | #################################### 0.5 | 3601 | #################################### 0.6 | 3391 | ################################# 0.7 | 3223 | ################################ 0.8 | 2891 | ############################ 0.9 | 2688 | ########################## 1.0 | 2317 | ####################### 1.1 | 2195 | ##################### 1.2 | 1897 | ################## 1.3 | 1685 | ################ 1.4 | 1389 | ############# 1.5 | 1272 | ############ 1.6 | 1054 | ########## 1.7 | 932 | ######### 1.8 | 750 | ####### 1.9 | 619 | ###### 2.0 | 538 | ##### 2.1 | 386 | ### 2.2 | 375 | ### 2.3 | 285 | ## 2.4 | 250 | ## 2.5 | 183 | # 2.6 | 140 | # 2.7 | 94 | 2.8 | 78 | 2.9 | 57 | 3.0 | 48 | 3.1 | 35 | 3.2 | 19 | 3.3 | 22 | 3.4 | 11 | 3.5 | 12 | 3.6 | 8 | 3.7 | 5 | 3.8 | 4 | 3.9 | 3 | 4.0 | 2 | 4.2 | 1 | (82 ROWS)
We can, of course, use the params to move result set a bit, or make it wider/narrower:
=$ SELECT round( random_normal(10, 0.3)::pg_catalog.numeric, 1 ) AS v, COUNT(*), repeat('#', (COUNT(*) / 100)::int4) FROM generate_series( 1, 100000 ) GROUP BY 1 ORDER BY 1; v | COUNT | repeat ------+-------+--------------------------------------------------------------------------------------------------------------------------------------- 8.6 | 1 | 8.7 | 3 | 8.8 | 5 | 8.9 | 16 | 9.0 | 44 | 9.1 | 152 | # 9.2 | 353 | ### 9.3 | 895 | ######## 9.4 | 1818 | ################## 9.5 | 3305 | ################################# 9.6 | 5397 | ##################################################### 9.7 | 8177 | ################################################################################# 9.8 | 10542 | ######################################################################################################### 9.9 | 12642 | ############################################################################################################################## 10.0 | 13300 | ##################################################################################################################################### 10.1 | 12559 | ############################################################################################################################# 10.2 | 10542 | ######################################################################################################### 10.3 | 8051 | ################################################################################ 10.4 | 5464 | ###################################################### 10.5 | 3388 | ################################# 10.6 | 1861 | ################## 10.7 | 824 | ######## 10.8 | 392 | ### 10.9 | 191 | # 11.0 | 49 | 11.1 | 19 | 11.2 | 7 | 11.3 | 3 | (28 ROWS)
Looks pretty awesome. It will definitely help with building some test datasets. Thanks to all involved.