PostgreSQL psql to draw pie chart

Keywords: Database SQL PostgreSQL MySQL

Label

PostgreSQL, SQL, PLPGSQL, Drawing Pie Charts

background

Image is easier to understand than text. In the field of BI visualization, image is often used instead of numeric value to display some information, such as histogram, pie chart, line graph, etc.

In the AWR text report, it would be good to have several more images instead of lists.

So can SQL draw directly and convert the result of a row into an image?

for example

1. The total time-consuming proportion of TOP SQL is pie chart.

2. Pie chart showing the proportion of database object types.

3. The pie chart of the proportion of database space.

4. The space occupied by TOP objects.

PostgreSQL relies on rich SQL grammar, drawing, small CASE.

Drawing an example of SQL

https://wiki.postgresql.org/wiki/Pie_Charts

The method of drawing with psql terminal is as follows:

1. Setting variables, breadth and height of pie chart, characters representing different colors, etc.

\set width  80  
\set height 25  
\set radius 1.0  
\set colours '''#;o:X"@+-=123456789abcdef'''  

2. Drawing DEMO SQL, converting 4 rows of records into pie charts

These four lines are recorded as follows:

VALUES ('red',1),  
                ('blue',2),  
                ('orange',3),  
                ('white',4)  
        )  

Drawing SQL as follows

WITH slices AS (  
 SELECT  CAST(ROW_NUMBER() OVER () AS INTEGER) AS slice,  
         name,   
	 VALUE,  
	 100.0 * VALUE / SUM(VALUE) OVER () AS percentage,  
	 2*PI() * SUM(VALUE) OVER (ROWS unbounded preceding)   
                / SUM(VALUE) OVER () AS radians  
   FROM (VALUES ('red',1),  
                ('blue',2),  
                ('orange',3),  
                ('white',4)  
        ) AS DATA(name,VALUE))  
(  
  SELECT array_to_string(array_agg(c),'') AS pie_chart  
    FROM (  
    SELECT x, y,  
           CASE WHEN NOT (SQRT(pow(x, 2) + pow(y, 2))   
                            BETWEEN :radius*1/10 AND :radius)  
                THEN ' '  
                ELSE SUBSTRING(:colours,  
                               (SELECT MIN(slice)   
                                  FROM slices   
                                 WHERE radians >= PI() + atan2(y,-x)),  
                               1)  
                END AS c  
      FROM (SELECT 2.0*generate_series(0,:width)/:width-1.0)   AS x(x),  
           (SELECT 2.0*generate_series(0,:height)/:height-1.0) AS y(y)  
     ORDER BY y,x  
  ) AS xy  
 GROUP BY y  
 ORDER BY y  
)  
UNION ALL   
SELECT repeat(SUBSTRING(:colours,slice,1), 2) || '  ' ||   
       name || ': ' ||   
       VALUE || '  (' || round(percentage,0) || '%)'   
  FROM slices;  

3. The image results are as follows.

  
                                     pie_chart                                       
-----------------------------------------------------------------------------------  
                                         ;                                          
                          oooo;;;;;;;;;;;;;;;;;;;;;;;;;;;                           
                    ooooooooooo;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;                     
                oooooooooooooooo;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;                 
            ooooooooooooooooooooo;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;             
         ooooooooooooooooooooooooo;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;          
       oooooooooooooooooooooooooooo;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;######        
      oooooooooooooooooooooooooooooo;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;###########       
    ooooooooooooooooooooooooooooooooo;;;;;;;;;;;;;;;;;;;;;;;;##################     
   ooooooooooooooooooooooooooooooooooo;;;;;;;;;;;;;;;;;;;#######################    
  ooooooooooooooooooooooooooooooooooooo;;;;;;;;;;;;;;############################   
  oooooooooooooooooooooooooooooooooooooo;;;;;;;;#################################   
  oooooooooooooooooooooooooooooooooooo       ####################################   
  oooooooooooooooooooooooooooooooooooo       ::::::::::::::::::::::::::::::::::::   
  ooooooooooooooooooooooooooooooooo::::::::::::::::::::::::::::::::::::::::::::::   
  oooooooooooooooooooooooooooo:::::::::::::::::::::::::::::::::::::::::::::::::::   
   ooooooooooooooooooooooo::::::::::::::::::::::::::::::::::::::::::::::::::::::    
    oooooooooooooooooo:::::::::::::::::::::::::::::::::::::::::::::::::::::::::     
      ooooooooooo::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::       
       oooooo:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::        
         :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::          
            :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::             
                :::::::::::::::::::::::::::::::::::::::::::::::::::                 
                    :::::::::::::::::::::::::::::::::::::::::::                     
                          :::::::::::::::::::::::::::::::                           
                                         :                                          
 ##  red: 1  (10%)  
 ;;  blue: 2  (20%)  
 oo  orange: 3  (30%)  
 ::  white: 4  (40%)  
(30 rows)  

Is it interesting?

Converting Drawing SQL to Function Interface to Provide Arbitrary Calls

1. Function interfaces are as follows

create or replace function gen_charts(  
  sql text,  -- SQL,Returns two columns, the first is the description, and the second is the value of the description.  
  width int default 80,   
  height int default 25,   
  radius numeric default 1.0,   -- change into float8 Type, print solid pie chart
  colours text default '#;o:X"@+-=123456789abcdef'    
) returns setof text as $$  
declare  
begin  
return query execute format(  
$_$  
WITH slices AS (  
 SELECT  CAST(ROW_NUMBER() OVER () AS INTEGER) AS slice,  
         name,   
	 VALUE,  
	 100.0 * VALUE / SUM(VALUE) OVER () AS percentage,  
	 2*PI() * SUM(VALUE) OVER (ROWS unbounded preceding)   
                / SUM(VALUE) OVER () AS radians  
   FROM (%s  
        ) AS DATA(name,VALUE))  
(  
  SELECT array_to_string(array_agg(c),'') AS pie_chart  
    FROM (  
    SELECT x, y,  
           CASE WHEN NOT (SQRT(pow(x, 2) + pow(y, 2))   
                            BETWEEN %s*1/10 AND %s)  
                THEN ' '  
                ELSE SUBSTRING(%L,  
                               (SELECT MIN(slice)   
                                  FROM slices   
                                 WHERE radians >= PI() + atan2(y,-x)),  
                               1)  
                END AS c  
      FROM (SELECT 2.0*generate_series(0,%s)/%s-1.0) AS x(x),  
           (SELECT 2.0*generate_series(0,%s)/%s-1.0) AS y(y)  
     ORDER BY y,x  
  ) AS xy  
 GROUP BY y  
 ORDER BY y  
)  
UNION ALL   
SELECT repeat(SUBSTRING(%L,slice,1), 2) || '  ' ||   
       name || ': ' ||   
       VALUE || '  (' || round(percentage,0) || '%%)'   
  FROM slices;  
$_$, sql, radius, radius, colours, width, width, height, height, colours);  
  
return;  
end;  
$$ language plpgsql strict;  

Examples of Graphic Function Interface

1. Print the proportion of different object types in the current database

postgres=# select * from gen_charts('select relkind,count(*) from pg_class group by relkind');  
                                    gen_charts                                     
-----------------------------------------------------------------------------------
                                         ;                                        
                          ;;;;;;;;;;;;;;;;;;;;;;;;;;;####                         
                    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;###########                   
                ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;################               
            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#####################           
         ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#########################        
       ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;############################      
      ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;##############################     
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#################################   
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;###################################  
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;##################################### 
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;###################################### 
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;       #################################### 
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oo       o::::::::::::::::::::::::::::::::::: 
  ;;;;;;;;;;;;;;;;;;;;;;;ooooooooooooooooooooooooooooo::::::::::::::::::::::::::: 
  ;;;;;;;;;;;;oooooooooooooooooooooooooooooooooooooooooooooooo::::::::::::::::::: 
   ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo::::::::::  
    oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo:   
      ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo     
       ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo      
         ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo        
            ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo           
                ooooooooooooooooooooooooooooooooooooooooooooooooooo               
                    ooooooooooooooooooooooooooooooooooooooooooo                   
                          ooooooooooooooooooooooooooooooo                         
                                         o                                        
 ##  r: 71  (20%)
 ;;  v: 119  (34%)
 oo  i: 138  (40%)
 ::  t: 20  (6%)
 XX  c: 1  (0%)
(31 rows)

2. Print objects larger than 8K, the top ten objects in the spatial ranking, their respective proportion

postgres=# select * from gen_charts('select relname , pg_relation_size(oid) from pg_class where pg_relation_size(oid) > 8192 order by pg_relation_size(oid) desc limit 10'); 
                                    gen_charts                                     
-----------------------------------------------------------------------------------
                                         #                                        
                          ###############################                         
                    ###########################################                   
                ###################################################               
            ###########################################################           
         #################################################################        
       #####################################################################      
      #######################################################################     
    ###########################################################################   
   #############################################################################  
  ############################################################################### 
  ############################################################################### 
  ####################################       #################################### 
  ####################################       ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
  ##############################################;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
  ###################################################;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
   #######################################################;;;;;;;;;;;;;;;;;;;;;;  
    ##########################################################;;;;;;;;;;;;;;;;;   
      #############################################################;;;;;;;;;;     
       #################################################################;;;;      
         #################################################################        
            ###########################################################           
                ###################################################               
                    ###########################################                   
                          ###############################                         
                                         #                                        
 ##  idx_c_1: 2359795712  (90%)
 ;;  c: 248135680  (10%)
 oo  pg_proc: 663552  (0%)
 ::  pg_depend: 548864  (0%)
 XX  pg_attribute: 458752  (0%)
 ""  pg_depend_reference_index: 458752  (0%)
 @@  pg_depend_depender_index: 417792  (0%)
 ++  pg_toast_2618: 417792  (0%)
 --  pg_statistic: 385024  (0%)
 ==  pg_proc_proname_args_nsp_index: 294912  (0%)
(36 rows)

3. Print the space proportion of different databases

postgres=# select * from gen_charts('select datname, pg_database_size(datname) from pg_database group by 1');  
                                    gen_charts                                     
-----------------------------------------------------------------------------------
                                         #                                        
                          ###############################                         
                    ###########################################                   
                ###################################################               
            ###########################################################           
         #################################################################        
       #####################################################################      
      #######################################################################     
    ###########################################################################   
   #############################################################################  
  ############################################################################### 
  ############################################################################### 
  ####################################       #################################### 
  ####################################       #################################### 
  ############################################################################### 
  ############################################################################### 
   #############################################################################  
    ###########################################################################   
      #######################################################################     
       #####################################################################      
         #################################################################        
            ###########################################################           
                ###################################################               
                    ###########################################                   
                          ###############################                         
                                         #                                        
 ##  postgres: 2616839287  (99%)
 ;;  template0: 7741955  (0%)
 oo  template1: 7741955  (0%)
(29 rows)

Reference resources

http://code.openark.org/blog/mysql/sql-pie-chart

https://wiki.postgresql.org/wiki/Pie_Charts

Posted by Welling on Tue, 14 May 2019 16:30:11 -0700