{"id":984,"date":"2009-07-24T06:00:12","date_gmt":"2009-07-24T04:00:12","guid":{"rendered":"http:\/\/code.openark.org\/blog\/?p=984"},"modified":"2009-07-27T12:53:50","modified_gmt":"2009-07-27T10:53:50","slug":"rotating-sql-graphs-horizontally","status":"publish","type":"post","link":"https:\/\/code.openark.org\/blog\/mysql\/rotating-sql-graphs-horizontally","title":{"rendered":"Rotating SQL graphs horizontally"},"content":{"rendered":"<p>We all love graphs. We all love SQL hacks. We all know the SQL hack which displays a character-based graph (example follows for those unfamiliar).<\/p>\n<p>But we all love <em>horizontal<\/em> graphs, not vertical ones. We are used to the X axis being horizontal, Y being vertical. Not vice versa.<\/p>\n<p>In this post I&#8217;ll present a SQL hack which rotates a vertical graph to horizontal. In fact, the technique shown will rotate any &#8216;textual image&#8217;; but graphs are a nice example.<\/p>\n<h4>A vertical graph example<\/h4>\n<p>What&#8217;s prettier than a sinus curve? I have prepared a simple table that will serve nicely, and can be found in <a href=\"http:\/\/code.openark.org\/blog\/wp-content\/uploads\/2009\/07\/graph.sql\">graph_tables.sql<\/a>.<\/p>\n<p><!--more--><\/p>\n<blockquote>\n<pre>SELECT * FROM sample_values;\r\n+-----+----------------------+\r\n| id  | val                  |\r\n+-----+----------------------+\r\n|   0 |                    1 |\r\n|   1 |     1.09983341664683 |\r\n|   2 |     1.19866933079506 |\r\n|   3 |     1.29552020666134 |\r\n|   4 |     1.38941834230865 |\r\n|   5 |      1.4794255386042 |\r\n|   6 |     1.56464247339504 |\r\n|   7 |     1.64421768723769 |\r\n|   8 |     1.71735609089952 |\r\n|   9 |     1.78332690962748 |\r\n...\r\n| 246 |    0.492103409609378 |\r\n| 247 |    0.580639083926769 |\r\n| 248 |    0.673364873895278 |\r\n| 249 |    0.769354294072604 |\r\n| 250 |    0.867648249902227 |\r\n| 251 |    0.967264620669155 |\r\n| 252 |     1.06720807252547 |\r\n| 253 |     1.16648000353716 |\r\n| 254 |     1.26408852138447 |\r\n| 255 |     1.35905835402217 |\r\n+-----+----------------------+\r\n256 rows in set (0.00 sec)<\/pre>\n<\/blockquote>\n<p>The common trick for displaying a graph is something like:<\/p>\n<blockquote>\n<pre>SELECT\r\n  id,\r\n  CONCAT(REPEAT('-',(val*10+1)-1),'#',REPEAT('-',22-(val*10+1))) AS bar\r\nFROM\r\n  sample_values\r\nLIMIT 100\r\n+----+------------------------+\r\n| id | bar                    |\r\n+----+------------------------+\r\n|  0 | ----------#----------- |\r\n|  1 | -----------#---------- |\r\n|  2 | ------------#--------- |\r\n|  3 | -------------#-------- |\r\n|  4 | --------------#------- |\r\n|  5 | ---------------#------ |\r\n|  6 | ----------------#----- |\r\n|  7 | ----------------#----- |\r\n|  8 | -----------------#---- |\r\n|  9 | ------------------#--- |\r\n| 10 | ------------------#--- |\r\n| 11 | -------------------#-- |\r\n| 12 | -------------------#-- |\r\n| 13 | --------------------#- |\r\n| 14 | --------------------#- |\r\n| 15 | --------------------#- |\r\n| 16 | --------------------#- |\r\n| 17 | --------------------#- |\r\n| 18 | --------------------#- |\r\n| 19 | -------------------#-- |\r\n| 20 | -------------------#-- |\r\n| 21 | -------------------#-- |\r\n| 22 | ------------------#--- |\r\n| 23 | -----------------#---- |\r\n| 24 | -----------------#---- |\r\n| 25 | ----------------#----- |\r\n| 26 | ---------------#------ |\r\n| 27 | --------------#------- |\r\n...\r\n+----+------------------------+\r\n100 rows in set (0.00 sec)<\/pre>\n<\/blockquote>\n<blockquote><p>In the above I&#8217;ve explicitly stretched values for them to be presentable.<\/p><\/blockquote>\n<p>So that&#8217;s the vertical graph. It&#8217;s not easy to read, plus you need to scroll down on your terminal to find out what&#8217;s going on. Can we rotate it?<\/p>\n<h4>Rotating the graph<\/h4>\n<p>We will combine the String Walking technique with <a title=\"Unwalking a string with GROUP_CONCAT\" href=\"http:\/\/code.openark.org\/blog\/mysql\/unwalking-a-string-with-group_concat\">String Unwalking<\/a>. What we need and assume is as follows:<\/p>\n<ul>\n<li> The above graph pads the bars up to some fixed length.<\/li>\n<li>Said length is not too high, so as to fit nicely within our screen.<\/li>\n<li>We have an integers table, used for string walking.<\/li>\n<\/ul>\n<p>The idea is to iterate the textual column character by character <em>from end to start<\/em> (done by string walking), and convert each such character column to row (done by string unwalking).<\/p>\n<blockquote>\n<pre>SELECT\r\n  GROUP_CONCAT(SUBSTRING(bar,tinyint_asc.value,1) ORDER BY id SEPARATOR '') AS `Sinus graph`\r\nFROM\r\n  tinyint_asc\r\nINNER JOIN (\r\n  SELECT\r\n    id,\r\n    CONCAT(REPEAT('-',(val*10+1)-1),'#',REPEAT('-',22-(val*10+1))) AS bar\r\n  FROM\r\n    sample_values\r\n  LIMIT 100) sel_graph\r\nWHERE\r\n  tinyint_asc.value BETWEEN 1 AND CHAR_LENGTH(bar)\r\nGROUP BY\r\n  tinyint_asc.value\r\nORDER BY\r\n  tinyint_asc.value DESC;\r\n\r\n+------------------------------------------------------------------------------------------------------+\r\n| Sinus graph                                                                                          |\r\n+------------------------------------------------------------------------------------------------------+\r\n| ---------------------------------------------------------------------------------------------------- |\r\n| -------------######---------------------------------------------------------######------------------ |\r\n| -----------##------###---------------------------------------------------###------###--------------- |\r\n| ---------##-----------#-------------------------------------------------#------------#-------------- |\r\n| --------#--------------##---------------------------------------------##--------------##------------ |\r\n| ------##-----------------#-------------------------------------------#------------------#----------- |\r\n| -----#--------------------#-----------------------------------------#--------------------#---------- |\r\n| ----#----------------------#---------------------------------------#----------------------#--------- |\r\n| ---#------------------------#-------------------------------------#------------------------#-------- |\r\n| --#--------------------------#-----------------------------------#--------------------------#------- |\r\n| -#----------------------------#---------------------------------#----------------------------#------ |\r\n| #------------------------------#-------------------------------#------------------------------#----- |\r\n| --------------------------------#-----------------------------#--------------------------------#---- |\r\n| ---------------------------------#---------------------------#----------------------------------#--- |\r\n| ----------------------------------#-------------------------#------------------------------------#-- |\r\n| -----------------------------------##----------------------#--------------------------------------#- |\r\n| -------------------------------------#--------------------#----------------------------------------# |\r\n| --------------------------------------#-----------------##------------------------------------------ |\r\n| ---------------------------------------#---------------#-------------------------------------------- |\r\n| ----------------------------------------##-----------##--------------------------------------------- |\r\n| ------------------------------------------##-------##----------------------------------------------- |\r\n| --------------------------------------------#######------------------------------------------------- |\r\n+------------------------------------------------------------------------------------------------------+<\/pre>\n<\/blockquote>\n<p>Now that&#8217;s much prettier, isn&#8217;t it?<\/p>\n<h4>Crazy stuff challenge<\/h4>\n<p>For those eager to improve upon this, I raise a few challenges (no prize but fame, though). Use the given data (<a href=\"http:\/\/code.openark.org\/blog\/wp-content\/uploads\/2009\/07\/graph.sql\">graph_tables.sql<\/a>), to produce:<\/p>\n<ul>\n<li>(Vertical) values on the X-axis for all graph points.<\/li>\n<li>Min\/max values for Y-axis, on separate column.<\/li>\n<li>As I understand it, full, in place, values for Y-axis is not possible; please prove me wrong!<\/li>\n<li>Other crazy stuff?<\/li>\n<\/ul>\n<p>Please add solutions in comments!<\/p>\n<p>[Continues on: <a href=\"http:\/\/code.openark.org\/blog\/mysql\/generic-auto-scaling-scaled-sql-graphs\">Generic, auto scaling, scaled SQL graphs<\/a>]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>We all love graphs. We all love SQL hacks. We all know the SQL hack which displays a character-based graph (example follows for those unfamiliar). But we all love horizontal graphs, not vertical ones. We are used to the X axis being horizontal, Y being vertical. Not vice versa. In this post I&#8217;ll present a [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"enabled":false},"version":2}},"categories":[5],"tags":[41,21],"class_list":["post-984","post","type-post","status-publish","format-standard","hentry","category-mysql","tag-graphs","tag-sql"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p2bZZp-fS","_links":{"self":[{"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/posts\/984","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/comments?post=984"}],"version-history":[{"count":24,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/posts\/984\/revisions"}],"predecessor-version":[{"id":1074,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/posts\/984\/revisions\/1074"}],"wp:attachment":[{"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/media?parent=984"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/categories?post=984"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/tags?post=984"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}