Axional Studio XSQL can be used to either read or write excel spreadsheets, thus leaving a way to easily integrate Excel with enterprise data.

1 Introduction

MS-Excel is an excellent tool for the analysis of information. However, connecting MS-Excel to a business database system may not be easy.

Axional Studio has a mechanism (grammar XSQL) to process MS-Excel sheets so that they can be read and written by the XSQL process language. Through this procedure they can be developed.

  • data loading processes from excel sheets
  • reporting processes based on MS-Excel sheet generation

Some advantages of this mechanism are:

  • The reports can be saved and then viewed and printed as the documents are pure Excel.
  • Access to database using XSQL and therefore using general security mechanisms.
  • Possibility to interrogate different database agents.
  • Security model of access to data.
  • Use of different fonts, size, styles and colors.
  • Easy writing through grammar XSQL.
  • Possibilities to copy cells, clone sheets, etc.

This type of report is ideal for balance sheets, complex reports to present to management, etc., in which a high level of personalization and presentation is required.

1.1 Examples

/>

2 The xsql-script

In this section we will explain how to generate the excel. As mentioned earlier, the generation is done from an XSQL-SCRIPT. In the XSQL-SCRIPT syntax, there is an Excel package that allows you to read and write excel files. .....

3 Example of a case

An implementation is explained below. It will be explained how to use the excel libraries to read and generate balances in excel format.

Note

This is just an example of implementation of the excel library, it is an example xsql-script.

The example consists of generating templates (excel calculation sheets) for different types of balance sheets. Then for each template define some inputs (variables that will be requested when executing, for example period, exercise, accounts, etc).

Here is an example of a template Annual accounts - Balance sheet - Normal model.

Once the template has been defined, the user can execute it, the execution process will first request the variables required by the balance. Then the process generates another excel sheet copying from the original and executing the SQL statements found in the template.

In the definition of the excel template you can have cells of different typologies:

3.1 Types of cells

Static text cells with format (for example titles, legends, etc).

Excel formulas cells.

Cells with SQL statements that will be executed when generating the excel result.

The execution process treats the cells according to their content.

3.2 Special SQL cells

There are 4 types of statements that can be used in cells.

SELECT DIRECT: The SQL statement is executed and the result is placed in the same cell.

Copy
<select-direct>
    <table name='@tmp_saldos' temp='yes'>
        <column name='cuenta' type='char'    size='14'   required='y' />
        <column name='posbal' type='char'    size='1'    required='y' />
        <column name='saldo'  type='decimal' size='14,2' required='y' />
    </table>
</select-direct>

SELECT MASTER: It is a query whose WHERE clause is completed with the condition of the select conditional of any cell in the same column.

Copy
<select-master>
    <select>
        <columns>+SUM(saldo)</columns>
        <from table='@tmp_saldos' />
        <where>posbal IN('A', 'X')</where>
    </select>
</select-master>

SELECT CONDITIONAL: It is a condition that is added to the WHERE clause of the column's master query. The result of the execution of the mounted query is placed in the same cell.

Copy
<select-conditional>
    <where>
        cuenta LIKE '2403%' OR 
        cuenta LIKE '2404%' OR 
        cuenta LIKE '2493%' OR 
        cuenta LIKE '2494%' OR 
        cuenta LIKE '293%'
    </where>
</select-conditional>

SELECT REFERENCE: The WHERE condition is the same as the cell that is referenced.

Copy
<select-reference>B12</select-reference>

3.3 Input parameters in the excel

An important aspect is the step of parameters to the execution of the excel. For example, in the case of a balance, you need to execute the balance for an exercise, or a period, or a project, account, etc.

The parameters in our example are programmed in the template, then at the time of executing the excel the system requests them from the user and places the values that the user placed in cells of the target calculation sheet.

In this way a select-direct can be as follows:

Copy
<select-direct>
    <insert table='@tmp_saldos'>
    <select>
        <columns> cuenta, (CASE WHEN (cuenta LIKE '551%' or cuenta LIKE '552%') 
        AND SUM(debe-haber) >= 0 THEN 'A' WHEN (cuenta LIKE '551%' or cuenta LIKE '552%') AND SUM(debe-haber) 
        >lt;  0 THEN 'P' ELSE 'X' END) posbal, SUM(debe-haber) saldo</columns> 
        <from table='csaldos'/> 
        <where> ejerci  = $A1 AND period  BETWEEN 0 AND $A2 AND empcode LIKE '$A3' AND proyec  LIKE '$A4' AND seccio  
            LIKE '$A5' AND sistem  LIKE '$A6' 
        </where> 
        <group> cuenta </group> 
    </select>
    </insert>
</select-direct>

Where the values $A1, $A2, $A3, $A4, $A5, $A6 will be replaced by the contents of cells A1 ..... Also in this way you can use reference to cells within our excel.

3.4 Generation of the destination

As mentioned above, our example takes an excel template (origin) and generates an excel destination (result) by copying the static cells and executing and placing the result of the special cells of type SQL.

Now, an important aspect is the order of generation of the destination cells. Here the system works in the following way.

The route of the origin excel and the generation of the destination is done by columns, this means that it begins with the column A and begins to process rows 1,2,3 ... n. Then continue with the column B

3.5 XSQL-SCRIPT run excel

In the dictionary database wic_icon this example is cataloged with the name cxls_runexcel. This xsql-script has two objectives If the template has input variables, these variables are requested first. Generate the result xsql-script.

3.5.1 Input variables

Copy
<if>
    <expr><eq><system.isBatch />true</eq></expr>
    <then>

        <set name='p_excel_name'>
            <system.prompt>Excel name: </system.prompt>
        </set>

        <map name='m_inputs' />
        <foreach>
            <select prefix='m_'>
                <columns>
                    *
                </columns>  
                <from table='cxls_input' />
                <where>
                    excel_name = <p_excel_name />
                </where>
            </select>
            <do>                
                
                <set name='m_value'>
                    <system.prompt default='#m_excel_input_default'><m_excel_input_name />:</system.prompt>
                </set>
          
                <map.put name='m_inputs'>
                    <m_excel_input_cell />
                    <m_value />
                </map.put>

            </do>
        </foreach>                          
        <set name='m_name'><p_excel_name /></set>
    </then>
    <else>
        <set name='p_excel_name'><http.request.getParameter name='_VAR_EXCEL_NAME' /></set> 
        <set name='m_name'><http.request.getParameter name='excel_name' /></set>
    </else>
</if>

3.6 Generate the sheet and the destination

Another important point of the xsql-script is the reading of the excel origin and the generation of the excel destiny.

Copy
<!-- Generar el excel leer el source -->

<select prefix='m_'>
    <columns>
        *
    </columns>
    <from table='cxls_object' />
    <where>
        excel_name = <p_excel_name />
    </where>
</select>


<file.out.open id='out2'>
    <file name='file_wb_src' type='temp'/>
</file.out.open>
<file.out.write id='out2'>
    <m_excel_data />
</file.out.write>
<file.out.close id='out2' />

<set name='wb_src'>
    <excel.Workbook>
        <file name='file_wb_src'  type='temp' />
    </excel.Workbook>
</set>

<set name='sheet_src'>
    <excel.Workbook.getSheetAt index='0'>
        <wb_src />
    </excel.Workbook.getSheetAt>
</set>              

<!-- Crear el nuevo EXCEL -->

<set name='wb_dst'>
    <excel.Workbook/>
</set>

<set name='sheet_dst'>
    <excel.Workbook.createSheet name='#p_excel_name'>
        <wb_dst />
    </excel.Workbook.createSheet>
</set>

As the source excel file is in a CLOB field of the database, a select is made, the value is retrieved, written in a temporary file file_wb_src and then the excel is excel.Wookbook from this temporary file.

With the excel destination (result) is created with excel.workbook, without arguments, the system generates an empty sheet, then here the sheet is generated that is needed excel.Workbook.createSheet

3.7 Tour of the origin excel

Next, you must go through the excel origin and go generating the excel destination (copying the exceldas) according to the cell type origin.

Copy
<set name='m_cols'><excel.Sheet.getMaxColumn><sheet_src /></excel.Sheet.getMaxColumn></set>
<set name='m_rows'><excel.Sheet.getMaxRow><sheet_src /></excel.Sheet.getMaxRow></set>
<set name='column_ss'><map /></set>

<!-- Recorrer todas las columnas -->
<for name='col' start='0' end='#m_cols'>
    <do>

        
        <!-- Por cada columna recorrer las filas -->
        <for name='row' start='0' end='#m_rows'>
            <do>

.....

            </do>
        </for>

    </do>
</for>

Note

The route of the cells is carried out by COLUMNS and within each column the rows are traversed. This is important since it will determine how the SQL SENTENCES are placed, an inverse route can change the result of the report.

The system will start with COLUMN A and start processing ROWS 1,2,3,4 ...., then secure with column COLUMN B, C, etc.

3.8 Static cells or formulas excel

Cells that are not SQL statements, the system copies them as they are from the excel origin to the destination.

Copy
<set name='r'>
    <excel.Sheet.createRow row='#row'>
        <sheet_src />
    </excel.Sheet.createRow>
</set>

<set name='cell_src'>
    <excel.Sheet.createCell row='#row' col='#col'>
        <sheet_src />
    </excel.Sheet.createCell>   
</set>

<set name='value'>
    <excel.Cell.getCellValue>
        <cell_src />
    </excel.Cell.getCellValue>
</set>


<!-- Cuidado, en un cell de inputs no se puede copiar el contenido, ya que este -->
<!-- fue puesto con los INPUTS del usuario                                    -->

<set name='m_cellRef'><excel.Cell.getCellReference row='#row' col='#col' /></set>
<if>
    <expr><eq><p_debug/>Si</eq></expr>
    <then>
        <println><string>CellRef: <m_cellRef /> Row: <row /> Cell: <col /></string></println>
    </then>
</if>


<if>
    <expr><isnull><map.get name='p_inputs'><m_cellRef/></map.get></isnull></expr>
    <then>

        <!-- copy cell to destination and get new cell ref -->
        <set name='cell_dst'>
            <excel.Sheet.copyCell row='#row' col='#col'>
                <wb_src />
                <cell_src />
                <wb_dst />
                <sheet_dst />
            </excel.Sheet.copyCell>
        </set>
    
    </then>
</if>

First the cell is generated in destination excel.Sheet.createCell and then with the tag excel.Sheet.copyCell the specified cell is copied from the source sheet to the destination sheet.

3.9 Special cells (SQL SENTENCES)

Each special cell (SENTENCES SQL) the system treats in a different way, for example in the case of a SELECT MASTER, here the system should not execute it, but save it and then execute it for each SELECT CONDITIONAL.

Copy
<!-- check original value is SQL cell, then process -->
<if>
    <expr>
        <string.startsWith>
            <value/>
            <string>>lt;select-master</string>
        </string.startsWith>
    </expr>
    <then>
    
    
        <set name='value'>
            <sql.select2native secure='true'>
                <dom.element.getFirstChildElement>
                    <dom.parse><value /></dom.parse>
                </dom.element.getFirstChildElement>
             </sql.select2native>
        </set>
    
        <if>
            <expr><eq><p_debug/>Si</eq></expr>
            <then>
                <println><string>Registre SQL Master: <value /></string></println>
            </then>
        </if>
    
    
        <set name='value'>
            <map.put name='column_ss'>
                <col />
                <value />
            </map.put>
        </set>
    
    
        
        <excel.Cell.setCellValue>
            <cell_dst/>
            <string />
        </excel.Cell.setCellValue>
    
    </then>
</if>

As the piece of code is seen, the sentences are parsed and placed on a map, so that they can be used later.

3.10 Execute a SELECT and put the result in a CELL

In the case of cells of type SELECT-CONDITIONAL the system must execute the SELECT-MASTER of that column, adding the condition that is specified in the SELECT tag -CONDITIONAL.

Copy
<!-- SELECT CONDITION, execute with stored column SENTENCE -->
<if>
    <expr>
        <string.startsWith>
            <value/>
            <string>>lt;select-conditional</string>
        </string.startsWith>
    </expr>
    <then>
            
        <set name='sentence'>
            <map.get name='column_ss'>
                <col />
            </map.get>
        </set>

        <if>
            <expr>
                <isnull><sentence /></isnull>
            </expr>
            <then>
                <set name='value'>No sentence defined for columns</set>
            </then>
            <else>


                <set name='value'>
                    <sql.select2native secure='true'>
                        <dom.element.getFirstChildElement>
                            <dom.parse><value /></dom.parse>
                        </dom.element.getFirstChildElement>
                    </sql.select2native>
                </set>

                <if>
                    <expr><eq><p_debug/>Si</eq></expr>
                    <then>
                        <println><string>Exceute SQL conditional: <value /></string></println>
                    </then>
                </if>

                <excel.Cell.setCellValueSQL>
                    <sheet_dst/>
                    <r/>
                    <cell_dst/>
                    <string trim='true'>
                        <sentence />
                        <string.nl />
                        <string>AND (</string>
                        <value />
                        <string>)</string>
                    </string>
                </excel.Cell.setCellValueSQL>
            
            </else>
        </if>

    </then>

</if>

From the map column_ss you get the corresponding SELECT-MASTER, you also get the content of the SELECT-CONDITIONAL tag, you get the SQL statement to execute and the tag excel.Cell.setCellValueSQL is used to execute the SQL and place the result in the corresponding cell.

3.11 Record the destination excel

The last step is to save the destination excel file (result) in the database so that it can be consulted later.

Copy
<excel.Workbook.write>
    <wb_dst />
    <file name="test.xls" type="temp"/>
</excel.Workbook.write>

<set name='m_cxls_output_excel_execid'>0</set>
<set name='m_cxls_output_excel_name'><p_excel_name /></set>
<set name='m_cxls_output_excel_info'><m_excel_info /></set>
<set name='m_cxls_output_excel_type'>application/vnd.ms-excel</set>
<set name='m_cxls_output_excel_size'>
    <file.length>
        <file name='test.xls' type='temp' />
    </file.length>
</set>
<set name='m_cxls_output_excel_data'>
    <file.getBytes>
        <file name='test.xls' type='temp' />
    </file.getBytes>
</set>
<set name='m_cxls_output_user_created'><system.user.getCode /></set>
<set name='m_cxls_output_date_created'><date.current /></set>
<insert table='cxls_output' prefix='m_cxls_output_' />

<set name='m_excel_execid'><sqlca.serial /></set>

<!-- Se devuelve el serial del documento generador. -->
              
<return><m_excel_execid /></return>

With the tag excel.Workbook.write the destination excel is written to disk (in a temporary file), then this temporary file is taken and inserted into a table cxls_output so that later it can be consulted without the need to run again.

3.12 Return the excel file

The last step is to return the excel file in this way you can see the result by the browser.

Copy
<return name='result.xls' type='application/vnd-excel'>
    <string.getBytes><m_excel_data /></string.getBytes>
</return>