Fix a few more refs
[worg.git] / org-tutorials / multitarget-tables.org
blob78d49e24a2bd756262b6adeb02eba2b3e8b637be
1 #+TITLE: Using Org-Mode Table Formatting Functions
2 #+AUTHOR: Jason Riedy
3 #+EMAIL: jason@acm.org
4 #+LANGUAGE: en
5 #+TEXT: *Abstract:* Org-mode's ability to slice one table into many
6 #+TEXT: separately formatted destinations helps keep documentation
7 #+TEXT: and data in sync.  We provide an example using both the
8 #+TEXT: multiple-target facilities and formatting with functions.
9 #+TEXT: Side-effects in the functions gather header data necessary
10 #+TEXT: for generating flexible SQL insertion statements.
11 #+OPTIONS:    H:3 num:nil toc:t \n:nil ::t |:t ^:t -:t f:t *:t tex:t d:(HIDE) tags:not-in-toc
12 #+STARTUP:    align fold nodlcheck hidestars oddeven lognotestate
13 #+SEQ_TODO:   TODO(t) INPROGRESS(i) WAITING(w@) | DONE(d) CANCELED(c@)
14 #+TAGS:       Write(w) Update(u) Fix(f) Check(c) 
15 #+PRIORITIES: A C B
16 #+CATEGORY:   worg-tutorial
18 # This file is released by its authors and contributors under the GNU
19 # Free Documentation license v1.3 or later, code examples are released
20 # under the GNU General Public License v3 or later.
22 [[file:../index.org][{Back to Worg's index}]]
24 * Introduction
26 In large-scale data analysis, one often associates integers with
27 parameter name rather than strings.  The performance and storage
28 difference is significant for multi-gigabyte data sets.  But integers
29 are not at all convenient or descriptive.  Systems like [[http://www.r-project.org][R]] provide a
30 =factor= data type that translates the stored integers into user-level
31 strings.  Emulating that construct in SQL is handy for data transfer
32 with [[http://www.sqlite.org][SQLite]] or out-of-core analysis in R using a [[http://cran.r-project.org/web/packages/SQLiteDF/index.html][SQL back-end]].  That
33 leaves the problem of maintaining a registry of integer level codes,
34 string names, and documentation.
36 [[https://orgmode.org][Org-mode]] provide a fast, light-weight table mechanism that can be sent
37 in email, bundled with code, or embedded in documentation.  The tables
38 can be transformed and placed elsewhere.  It sounds like a perfect
39 registry, generating documentation and code from one data table.
40 Similar techniques could be used in a multi-lingual document to store
41 many translations in one table and send them to sections in specific
42 languages.
44 We start with a simple table:
46 #+ORGTBL: SEND exdoc orgtbl-to-orgtbl :skipcols (2) :fmt (1 "=%s=") :hfmt (1 "%s")
47 #+ORGTBL: SEND exsql orgtbl-to-sqlinsert :sqlname "extbl" :fmt (2 "%s") :tstart "#+BEGIN_EXAMPLE\nBEGIN TRANSACTION;" :tend "COMMIT;\n#+END_EXAMPLE"
48 | Name  | Level | Description |
49 |-------+-------+-------------|
50 | normx |     1 | norm(x, \infty)  |
51 | normb |     2 | norm(b, \infty)  |
52 | normA |     3 | norm(A, \infty)  |
54 That one source table contains the documentation in the first and third
55 column:
57 #+BEGIN RECEIVE ORGTBL exdoc
58 | Name  | Description |
59 |-------+-------------|
60 | =normx= | norm(x, \infty)  |
61 | =normb= | norm(b, \infty)  |
62 | =normA= | norm(A, \infty)  |
63 #+END RECEIVE ORGTBL exdoc
65 The first two columns of the source table provide the data we must
66 transfer the SQL.  The third column can be used to embed some
67 documentation into the table itself after the string is sanitized for
68 SQL.  The remaining necessary information, the SQL destination table
69 name, can be provided as a parameter to =#+ORGTBL: SEND=, producing the
70 following code chunk:
72 #+BEGIN RECEIVE ORGTBL exsql
73 #+BEGIN_SRC sql
74 BEGIN TRANSACTION;
75 INSERT INTO extbl( Name, Level, Description ) VALUES ( 'normx' , 1 , 'norm(x, infty)' );
76 INSERT INTO extbl( Name, Level, Description ) VALUES ( 'normb' , 2 , 'norm(b, infty)' );
77 INSERT INTO extbl( Name, Level, Description ) VALUES ( 'normA' , 3 , 'norm(A, infty)' );
78 COMMIT;
79 #+END_SRC
80 #+END RECEIVE ORGTBL exsql
82 We will explain the parameters used to produce both outputs.  The SQL
83 insertion statements use functions as formatting parameters, some of
84 which are called purely for the side-effect of gathering the header
85 fields.  The SQL-generating code is distributed with org-mode in
86 =contrib/lisp/orgtbl-sqlinsert.el=.
88 * Specifying multiple destinations for a single table
90 Sending one table to multiple destinations is straight-forward.  Add one
91 =SEND= directive for each destination.  For example, the first table has
92 the following two directives prepended, with parameters described later:
94 : #+ORGTBL: SEND exdoc orgtbl-to-orgtbl ...
95 : #+ORGTBL: SEND exsql orgtbl-to-sqlinsert ...
97 The documentation removes the second column and adds fiddly formatting
98 parameters with
100 : :skipcols (2) :fmt (1 "=%s=") :hfmt (1 "%s")
102 The SQL-generating line gathers the destination table name and passes
103 integers through unchanged with the parameters
105 : :sqlname "extbl" :fmt (2 "%s")
107 The SQL table name defaults to the name of the target, =exsql= in this
108 case.  And the default formatting used for other columns is
109 =orgtbl-sql-strip-and-quote=.  That routine only removes potentially
110 non-portable constructs; it is not designed to prevent insertion
111 attacks.
113 We could apply =orgtbl-sql-strip-and-quote= to the first column of the
114 documentation table to ensure the strings match exactly, but it easier
115 to use simple, non-mangled strings as names.
117 By default, a block of insertions is wrapped in =BEGIN TRANSACTION= and
118 =COMMIT= statements.  These can be supressed by setting =:tstart= and
119 =:tend= to =nil=.  The example used in this document uses a
120 "double-embedding" trick to wrap the statement in an org-mode code
121 block:
123 : :tstart "#+BEGIN_EXAMPLE\nBEGIN TRANSACTION;"
124 : :tend "COMMIT;\n#+END_EXAMPLE"
126 Similar wrapping can embed the SQL statements into literate programs.
127 There is built-in support for [[http://www.eecs.harvard.edu/nr/noweb/][Noweb]] with the =:nowebname= parameter.
128 Setting =:nowebname= to a string wraps the insertions in a Noweb code
129 chunk named with the string.
131 * Formatting with functions for side effects and display
133 The =orgtbl-to-sqlinsert= routine calls =orgtbl-to-generic= for all the
134 generic table parsing.  The parameters provide an example of using
135 functions for gathering data as well as formatting.  Emacs Lisp's
136 dynamic binding allows manipulating any symbols in the current
137 environment, so the formatting functions do not need to pass parameters
138 through the outer functions.
140 The default =:tstart= parameter is one example used strictly for
141 formatting.  After the =:nowebname= parameter is decoded and bound to
142 =nowebname=, it can be checked within a thunk to produce the starting
143 string:
145 : :tstart (lambda () (concat (if nowebname
146 :                                (format "<<%s>>= \n" nowebname)
147 :                              "")
148 :                            "BEGIN TRANSACTION;"))
150 The functions need not be pure.  The header formatting gathers the
151 first header line into the variable =hdrlist= with
152 : :hfmt (lambda (f) (progn (if firstheader (push f hdrlist)) ""))
153 Then each line is preceded with a function that uses =hdrlist= to ensure
154 data values are associated with named columns rather than just
155 positions.
157 : :lstart (lambda () (concat "INSERT INTO "
158 :                            sqlname "( "
159 :                            (mapconcat 'identity (reverse hdrlist)
160 :                                       ", ")
161 :                            " )" (if breakvals "\n" " ")
162 :                                     "VALUES ( "))
164 Note that =orgtbl-to-sqlinsert= takes advantage of org-mode's applying
165 the formatting to each cell /before/ checking for a line-formatting
166 function.  The header line itself and sectioning line are suppressed
167 with the settings
169 : :hlfmt (lambda (lst) (setq firstheader nil))
170 : :hline nil
171 : :remove-nil-lines t
173 Similar techniques could be used to generate a table's SQL definition
174 from the second header line.
176 * Current limitations
178 One current limitation is that all the tables are in the same Emacs
179 buffer and hence the same text file.  A literate programming mechanism
180 like [[http://www.eecs.harvard.edu/nr/noweb/][Noweb]] can separate the chunks.
182 Also, the tables must be sent manually.  Writing a function that scans
183 an entire buffer for all =SEND= and =RECEIVE= pairs is feasible, as is
184 using [[http://www.gnu.org/software/emacs/elisp/html_node/Overlays.html][overlays]] to manage automatic updates.