The tablefunc module provides functions that return tables (multiple rows).
It is a trusted extension available to non-superusers with CREATE privilege.
CREATEEXTENSIONtablefunc;
normal_rand – Generate Random Values
Produces a set of normally distributed random values (Gaussian distribution):
SELECT*FROMnormal_rand(1000,5,3);-- numvals: number of values, mean: 5, stddev: 3
crosstab(text) – Single-Parameter Pivot
Pivots data from long format to wide format. The SQL must return row_name, category, and value columns:
CREATETABLEct(idSERIAL,rowidTEXT,attributeTEXT,valueTEXT);INSERTINTOct(rowid,attribute,value)VALUES('test1','att1','val1'),('test1','att2','val2'),('test1','att3','val3'),('test2','att1','val5'),('test2','att2','val6'),('test2','att3','val7');SELECT*FROMcrosstab('SELECT rowid, attribute, value FROM ct ORDER BY 1,2')ASct(row_nametext,category_1text,category_2text,category_3text);row_name|category_1|category_2|category_3----------+------------+------------+------------
test1|val1|val2|val3test2|val5|val6|val7
The input query should always use ORDER BY 1,2 to ensure proper grouping.
Extra output columns beyond the available values are filled with nulls.
crosstab(text, text) – Two-Parameter Pivot with Categories
Handles cases where some groups may not have data for all categories:
CREATETABLEsales(yearint,monthint,qtyint);INSERTINTOsalesVALUES(2007,1,1000),(2007,2,1500),(2007,7,500),(2007,11,1500),(2007,12,2000),(2008,1,1000);SELECT*FROMcrosstab('SELECT year, month, qty FROM sales ORDER BY 1','SELECT m FROM generate_series(1,12) m')AS(yearint,"Jan"int,"Feb"int,"Mar"int,"Apr"int,"May"int,"Jun"int,"Jul"int,"Aug"int,"Sep"int,"Oct"int,"Nov"int,"Dec"int);year|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec------+------+------+-----+-----+-----+-----+-----+-----+-----+-----+------+------
2007|1000|1500|||||500||||1500|20002008|1000|||||||||||
The source SQL may include “extra” columns between row_name and category/value.
Displays hierarchical data stored in a table with key and parent-key fields:
CREATETABLEconnectby_tree(keyidtext,parent_keyidtext,posint);INSERTINTOconnectby_treeVALUES('row1',NULL,0),('row2','row1',0),('row3','row1',0),('row4','row2',1),('row5','row2',0),('row6','row4',0),('row7','row3',0),('row8','row6',0),('row9','row5',0);-- With branch display and ordering
SELECT*FROMconnectby('connectby_tree','keyid','parent_keyid','pos','row2',0,'~')ASt(keyidtext,parent_keyidtext,levelint,branchtext,posint);keyid|parent_keyid|level|branch|pos-------+--------------+-------+---------------------+-----
row2||0|row2|1row5|row2|1|row2~row5|2row9|row5|2|row2~row5~row9|3row4|row2|1|row2~row4|4row6|row4|2|row2~row4~row6|5row8|row6|3|row2~row4~row6~row8|6