The follwing examples will teach how to use Excel as a template engine using Axional Excel library.
1 Projectile motion solver
We have a Excel sheet that solves the physics calculations of a projectile motion uder gravity conditions. We need initial speed and angle as input parameters.

Now let's setup the input variables with names using a prefix and suffix. We will
name D7 for data.velocity
and D8 for data.angle
.

You can download the excel here
1.1 Feed the template with data
Now let's see how to:
- Load an excel as template
- Prepare the data
- Update template and evaluate results
- Return the evaluated excel to caller
<script> // 1. Load the template var wb = Ax.ms.Excel.load("https://bitbucket.org/deister/axional-docs-resources/raw/master/Excel/templates/ProjectileSolver.xlsx"); // 2. Prepare the data var input = { velocity: 200, angle: 36 }; // 3. Update template (table name perfix for named cells is data) and evaluate wb.update(input, options => { options.setTableName("data"); options.setEvaluate(true); } ); // 4. Return the evaluated excel return wb.toBlob(); </script>
We have succesfully processed our first excel template using input data to perform calculations and obtain a result.

2 Loan amortization calculator
The Loan Template serves as an example of how to use Form layout updates and row copy with formula rewriting. Let's see how.
The template contains two form areas, lender and loan. You can see in the javascript code the JSON objects to update both "form" data fields.
In the rows area we have two rows.
- Excel row 24, with the initial calculus (first payment)
- Excel row 25, with the consecutive calculus (next payment)
So we need to:
-
Get the number of payments (depending on years and payment period) calculated
by Excel from cell named
numpayments
(I15). -
Get the row 25 that we will use as template to copy rows down till fullfill
the number of payments. The cell at A25 is named
rowtemplate
. So we can use it's name to get the cell and the the row object.When row it's copied, it's formulas are rewritten moving its references to new row position.
- Once we have both, we can copy rows till number of payments minus the two initial rows.

<script> var wb = Ax.ms.Excel.load("https://bitbucket.org/deister/axional-docs-resources/raw/master/Excel/templates/Loan-Template.xlsx"); var sheet = wb.getSheet(0); var lender = { name : "Adam Wilcot", phone: "01-937-403-33002", web: "http://wilcotlender.com", mail: "adam@wilcotlender.com" } var loan = { purchase_price : 10000, percent_down: 0.05, interest: 0.0475, years: 8, payment_freq: "Monthly", first_payment: new Date(2019, 9, 1) } // Update lender prefixed cells wb.update(lender, options => { options.setTableName("lender"); } ); // Update loan prefixed cells wb.update(loan, options => { options.setTableName("loan"); } ); // Get the cell of row template (I15) var cell_numpayments = wb.getCellByName("numpayments"); // Get the cell of row template (A25) var cell_rowtemplate = wb.getCellByName("rowtemplate"); // The row that is our template var row_template = cell_rowtemplate.getRow(); console.log("sheet last row :" + sheet.getLastRowNum()); console.log("cell_rowtemplate:" + cell_rowtemplate + " " + cell_rowtemplate.getCellValue()); console.log("cell_numpayments:" + cell_numpayments + " " + cell_numpayments.getCellValue()); console.log("row_template :" + row_template + " " + row_template.getRowNum()); // Copy from row 24+1 to the number of payment less 2 (first row and template row) sheet.copyRow(row_template, row_template.getRowNum() + 1, cell_numpayments.getCellValue() - 2); return wb.toBlob(); </script>
We have succesfully processed the loan template, filled it with JSON data and generated copy of rows updating it's formula references.

3 Gantt Chart (I)
In the following example we will see how to use database project information to fill a Excel Gantt template. Let's see first a database model to support the project information.
3.1 The database model
CREATE TABLE IF NOT EXISTS plan ( task VARCHAR(40), responsible VARCHAR(40), start DATE, end DATE, days INTEGER, status VARCHAR(20) ); INSERT INTO plan VALUES("Set Kick-Off Meeting", "Alex B.", MDY(9,2,2022), MDY(9,3,2022), 1, "Complete"); INSERT INTO plan VALUES("Agree on Objectives", "Frank C.", MDY(9,3,2022), MDY(9,7,2022), 4, "Complete"); INSERT INTO plan VALUES("Detailed Reqs.", "Jacob S.", MDY(9,7,2022), MDY(9,12,2022), 5, "Complete"); INSERT INTO plan VALUES("Hardware Reqs.", "Jacob S.", MDY(9,9,2022), MDY(9,11,2022), 2, "Overdue" ); INSERT INTO plan VALUES("Final Resource Plan", "Jacob S.", MDY(9,11,2022), MDY(9,15,2022), 4, "In Progress"); INSERT INTO plan VALUES("Staffing", "Alex B.", MDY(9,16,2022), MDY(9,17,2022), 1, "In Progress"); INSERT INTO plan VALUES("Technical Reqs.", "Frank C.", MDY(9,17,2022), MDY(9,21,2022), 4, "Not Started"); INSERT INTO plan VALUES("DB Development", "Shari W.", MDY(9,22,2022), MDY(9,24,2022), 2, "Not Started"); INSERT INTO plan VALUES("API Development", "Shari W.", MDY(9,23,2022), MDY(9,27,2022), 4, "Not Started"); INSERT INTO plan VALUES("UI Client", "Alex B.", MDY(9,25,2022), MDY(9,29,2022), 4, "Not Started"); INSERT INTO plan VALUES("Testing", "Kennedy K.", MDY(9,24,2022), MDY(10,2,2022), 8, "Not Started"); INSERT INTO plan VALUES("Dev. Complete", "Jacob S.", MDY(10,2,2022), MDY(10,5,2022), 3, "Not Started"); INSERT INTO plan VALUES("Hardware Config.", "Alex B.", MDY(10,5,2022), MDY(10,7,2022), 2, "Not Started"); INSERT INTO plan VALUES("System Testing", "Kennedy K.", MDY(10,6,2022), MDY(10,9,2022), 3, "Not Started");
3.2 The Gantt template
The Gantt template contains named cells for project
and plan
data sets. You can download the templater here

3.3 Processing the template
<script> Ax.db.execute('DROP TABLE IF EXISTS plan'); Ax.db.execute(`CREATE TABLE IF NOT EXISTS plan ( task VARCHAR(40), responsible VARCHAR(40), start DATE, end DATE, days INTEGER, status VARCHAR(20) );`); Ax.db.execute(`INSERT INTO plan VALUES("Set Kick-Off Meeting", "Alex B.", MDY(9,2,2022), MDY(9,3,2022), 1, "Complete")`); Ax.db.execute(`INSERT INTO plan VALUES("Agree on Objectives", "Frank C.", MDY(9,3,2022), MDY(9,7,2022), 4, "Complete")`); Ax.db.execute(`INSERT INTO plan VALUES("Detailed Reqs.", "Jacob S.", MDY(9,7,2022), MDY(9,12,2022), 5, "Complete")`); Ax.db.execute(`INSERT INTO plan VALUES("Hardware Reqs.", "Jacob S.", MDY(9,9,2022), MDY(9,11,2022), 2, "Overdue" )`); Ax.db.execute(`INSERT INTO plan VALUES("Final Resource Plan", "Jacob S.", MDY(9,11,2022), MDY(9,15,2022), 4, "In Progress")`); Ax.db.execute(`INSERT INTO plan VALUES("Staffing", "Alex B.", MDY(9,16,2022), MDY(9,17,2022), 1, "In Progress")`); Ax.db.execute(`INSERT INTO plan VALUES("Technical Reqs.", "Frank C.", MDY(9,17,2022), MDY(9,21,2022), 4, "Not Started")`); Ax.db.execute(`INSERT INTO plan VALUES("DB Development", "Shari W.", MDY(9,22,2022), MDY(9,24,2022), 2, "Not Started")`); Ax.db.execute(`INSERT INTO plan VALUES("API Development", "Shari W.", MDY(9,23,2022), MDY(9,27,2022), 4, "Not Started")`); Ax.db.execute(`INSERT INTO plan VALUES("UI Client", "Alex B.", MDY(9,25,2022), MDY(9,29,2022), 4, "Not Started")`); Ax.db.execute(`INSERT INTO plan VALUES("Testing", "Kennedy K.", MDY(9,24,2022), MDY(10,2,2022), 8, "Not Started")`); Ax.db.execute(`INSERT INTO plan VALUES("Dev. Complete", "Jacob S.", MDY(10,2,2022), MDY(10,5,2022), 3, "Not Started")`); Ax.db.execute(`INSERT INTO plan VALUES("Hardware Config.", "Alex B.", MDY(10,5,2022), MDY(10,7,2022), 2, "Not Started")`); Ax.db.execute(`INSERT INTO plan VALUES("System Testing", "Kennedy K.", MDY(10,6,2022), MDY(10,9,2022), 3, "Not Started")`); // 1. Load the template var wb = Ax.ms.Excel.load("https://bitbucket.org/deister/axional-docs-resources/raw/master/Excel/templates/Gantt-Template-1.xlsx"); // 2. Create a project JSON description var project = { name : "The Project Name", manager: "The Manager Name", deliverable: "The Deliverable", scope: "The Scope", } // 3. Update "project" fields wb.update(project, options => { options.setTableName("project"); } ); // 4. Load data for project orderde by date var rs = Ax.db.executeQuery( "SELECT * FROM plan ORDER BY start" ); // 5. Update rows starting with "plan" wb.update(rs, options => { options.setTableName("plan"); // Skip first row (the header) options.setStartRow(wb.getNamedRow("plan") + 1); // Evaluate formulas options.setEvaluate(true); } ); // 6. Get date filled by formula on "project.start" var date = wb.getCellByName("project.start"); console.log("Date cell =" + date); console.log("Date value=" + date.getCellValue()); // 7. Get the sheet (0=first) and the chart from sheet (0=first chart from sheet) var chart = wb.getSheet(0).getCharts()[0]; // 8. Adjust the minimum value for value axis with start date chart.getValueAxis().setMinimum(date.getCellValue()); rs.close(); // 9. Return the Excel as BLOB Ax.db.execute('DROP TABLE plan'); return wb.toBlob(); </script>
We have succesfully generated a Gantt with it's chart filling data from JSON and database and adjusting chart axis with calculated date.
4 Gantt Chart (II)
The following example is a more complex Gantt template using a hierachical structure.
4.1 The database model
The gantt
table in the following example is a simple data model to
store hierachical information.
CREATE TABLE gantt ( ID INTEGER NOT NULL, parentID INTEGER, orderID INTEGER NOT NULL, priority CHAR(1) NOT NULL, taskname VARCHAR(25), leader VARCHAR(20), start DATE NOT NULL, end DATE NOT NULL, completed DECIMAL(5,2) NOT NULL ); INSERT INTO gantt VALUES (1, NULL, 1, "", "" , "Root Node", MDY(1,1,3000), MDY(1, 1, 3000), 0); INSERT INTO gantt VALUES (2, 1, 1, "M", "Analisys" , "", MDY(9,1,2022), MDY(9,6,2022), 100); INSERT INTO gantt VALUES (3, 2, 1, "M", "Set Kick-Off Meeting" , "Alex B.", MDY(9,2,2022), MDY(9,3,2022), 80); INSERT INTO gantt VALUES (4, 2, 1, "M", "Agree on Objectives" , "Frank C.", MDY(9,4,2022), MDY(9,7,2022), 0); INSERT INTO gantt VALUES (5, 2, 1, "M", "Requirements planning" , "Jacob S.", MDY(9,7,2022), MDY(9,12,2022), 50); INSERT INTO gantt VALUES (6, 5, 1, "M", "Detailed Reqs." , "Jacob S.", MDY(9,10,2022), MDY(9,15,2022), 80); INSERT INTO gantt VALUES (7, 5, 1, "M", "Hardware Reqs." , "Jacob S.", MDY(9,11,2022), MDY(9,12,2022), 0); INSERT INTO gantt VALUES (8, 5, 1, "M", "Technical Reqs." , "Frank C.", MDY(9,17,2022), MDY(9,21,2022), 50); INSERT INTO gantt VALUES (9, 2, 1, "M", "Staffing" , "Alex B.", MDY(9,16,2022), MDY(9,17,2022), 0); INSERT INTO gantt VALUES (10, 1, 1, "M", "Development" , "", MDY(9,22,2022), MDY(10,5, 2022), 0); INSERT INTO gantt VALUES (11, 10, 1, "M", "DB Development" , "Shari W.", MDY(9,22,2022), MDY(9,24,2022), 25); INSERT INTO gantt VALUES (12, 10, 1, "M", "API Development" , "Shari W.", MDY(9,23,2022), MDY(9,27,2022), 10); INSERT INTO gantt VALUES (13, 10, 1, "M", "UI Client" , "Alex B.", MDY(9,25,2022), MDY(9,29,2022), 0); INSERT INTO gantt VALUES (14, 10, 1, "M", "Testing" , "Kennedy K.", MDY(9,24,2022), MDY(10,2,2022), 0); INSERT INTO gantt VALUES (15, 10, 1, "M", "Dev. Complete" , "Jacob S.", MDY(10,2,2022), MDY(10,5,2022), 0); INSERT INTO gantt VALUES (16, 1, 1, "M", "Deployment" , "", MDY(10,5,2022), MDY(10,17, 2022), 0); INSERT INTO gantt VALUES (17, 16, 1, "M", "Hardware Config." , "Alex B.", MDY(10,10,2022), MDY(10,12,2022), 0); INSERT INTO gantt VALUES (18, 16, 1, "M", "System Testing" , "Kennedy K.", MDY(10,11,2022), MDY(10,14,2022), 0); INSERT INTO gantt VALUES (19, 1, 1, "M", "Support" , "", MDY(10,14,2022),MDY(12,24,2022), 0); INSERT INTO gantt VALUES (20, 19, 1, "M", "Acvanced formation" , "John M.", MDY(10,14,2022), MDY(10,20,2022), 0); INSERT INTO gantt VALUES (21, 19, 1, "M", "Phone Support" , "N/A", MDY(12,1,2022), MDY(12,9,2022), 0);
Now, we can use the CONNECT BY clause for performing recursive operations in hierarchical queries.
SELECT id, parentid, orderid, level, LPAD(' ', 2 * LEVEL - 1) || TRIM(taskname) name, leader, start, end, end-start duration FROM gantt START WITH id = 1 CONNECT BY PRIOR id = parentID ORDER BY id
+----------+----------+----------+-------+----------------------------------------+--------------------+----------+----------+----------+
|id |parentid |orderid |level |name |leader |start |end |duration |
+----------+----------+----------+-------+----------------------------------------+--------------------+----------+----------+----------+
| 1| | 1| 1| | |2019-01-01|2019-01-20| 19|
| 2| 1| 1| 2| Analisys | |2019-01-01|2019-01-20| 19|
| 3| 2| 1| 3| Set Kick-Off Meeting |Alex B. |2022-09-02|2022-09-03| 1|
| 4| 2| 1| 3| Agree on Objectives |Frank C. |2022-09-03|2022-09-07| 4|
| 5| 2| 1| 3| Requirements plannin |Jacob S. |2022-09-07|2022-09-12| 5|
| 6| 5| 1| 4| Detailed Reqs. |Jacob S. |2022-09-07|2022-09-12| 5|
| 7| 5| 1| 4| Hardware Reqs. |Jacob S. |2022-09-09|2022-09-11| 2|
| 8| 5| 1| 4| Technical Reqs. |Frank C. |2022-09-17|2022-09-21| 4|
| 9| 2| 1| 3| Staffing |Alex B. |2022-09-16|2022-09-17| 1|
| 10| 1| 1| 2| Development | |2019-01-01|2019-01-20| 19|
| 11| 10| 1| 3| DB Development |Shari W. |2022-09-22|2022-09-24| 2|
| 12| 10| 1| 3| API Development |Shari W. |2022-09-23|2022-09-27| 4|
| 13| 10| 1| 3| UI Client |Alex B. |2022-09-25|2022-09-29| 4|
| 14| 10| 1| 3| Testing |Kennedy K. |2022-09-24|2022-10-02| 8|
| 15| 10| 1| 3| Dev. Complete |Jacob S. |2022-10-02|2022-10-05| 3|
| 16| 1| 1| 2| Deployment | |2019-01-01|2019-01-20| 19|
| 17| 16| 1| 3| Hardware Config. |Alex B. |2022-10-05|2022-10-07| 2|
| 18| 16| 1| 3| System Testing |Kennedy K. |2022-10-06|2022-10-09| 3|
+----------+----------+----------+-------+----------------------------------------+--------------------+----------+----------+----------+
4.2 The Gantt template 2
The Gantt template 2, contains named cells for project
and a sheet
with templates of each line corresponding to its indentation level.
You can download the template here

4.3 Processing the template
<script> Ax.db.execute('DROP TABLE IF EXISTS gantt'); Ax.db.execute(`CREATE TABLE gantt ( ID INTEGER NOT NULL, parentID INTEGER, orderID INTEGER NOT NULL, priority CHAR(1) NOT NULL, taskname VARCHAR(25), leader VARCHAR(20), start DATE NOT NULL, end DATE NOT NULL, completed DECIMAL(5,2) NOT NULL );`); Ax.db.execute(`INSERT INTO gantt VALUES (1, NULL, 1, "", "" , "Root Node", MDY(1,1,3000), MDY(1, 1, 3000), 0);`); Ax.db.execute(`INSERT INTO gantt VALUES (2, 1, 1, "M", "Analisys" , "", MDY(9,1,2022), MDY(9,6,2022), 100);`); Ax.db.execute(`INSERT INTO gantt VALUES (3, 2, 1, "M", "Set Kick-Off Meeting" , "Alex B.", MDY(9,2,2022), MDY(9,3,2022), 80);`); Ax.db.execute(`INSERT INTO gantt VALUES (4, 2, 1, "M", "Agree on Objectives" , "Frank C.", MDY(9,4,2022), MDY(9,7,2022), 0);`); Ax.db.execute(`INSERT INTO gantt VALUES (5, 2, 1, "M", "Requirements planning" , "Jacob S.", MDY(9,7,2022), MDY(9,12,2022), 50);`); Ax.db.execute(`INSERT INTO gantt VALUES (6, 5, 1, "M", "Detailed Reqs." , "Jacob S.", MDY(9,10,2022), MDY(9,15,2022), 80);`); Ax.db.execute(`INSERT INTO gantt VALUES (7, 5, 1, "M", "Hardware Reqs." , "Jacob S.", MDY(9,11,2022), MDY(9,12,2022), 0);`); Ax.db.execute(`INSERT INTO gantt VALUES (8, 5, 1, "M", "Technical Reqs." , "Frank C.", MDY(9,17,2022), MDY(9,21,2022), 50);`); Ax.db.execute(`INSERT INTO gantt VALUES (9, 2, 1, "M", "Staffing" , "Alex B.", MDY(9,16,2022), MDY(9,17,2022), 0);`); Ax.db.execute(`INSERT INTO gantt VALUES (10, 1, 1, "M", "Development" , "", MDY(9,22,2022), MDY(10,5, 2022), 0);`); Ax.db.execute(`INSERT INTO gantt VALUES (11, 10, 1, "M", "DB Development" , "Shari W.", MDY(9,22,2022), MDY(9,24,2022), 25);`); Ax.db.execute(`INSERT INTO gantt VALUES (12, 10, 1, "M", "API Development" , "Shari W.", MDY(9,23,2022), MDY(9,27,2022), 10);`); Ax.db.execute(`INSERT INTO gantt VALUES (13, 10, 1, "M", "UI Client" , "Alex B.", MDY(9,25,2022), MDY(9,29,2022), 0);`); Ax.db.execute(`INSERT INTO gantt VALUES (14, 10, 1, "M", "Testing" , "Kennedy K.", MDY(9,24,2022), MDY(10,2,2022), 0);`); Ax.db.execute(`INSERT INTO gantt VALUES (15, 10, 1, "M", "Dev. Complete" , "Jacob S.", MDY(10,2,2022), MDY(10,5,2022), 0);`); Ax.db.execute(`INSERT INTO gantt VALUES (16, 1, 1, "M", "Deployment" , "", MDY(10,5,2022), MDY(10,17, 2022), 0);`); Ax.db.execute(`INSERT INTO gantt VALUES (17, 16, 1, "M", "Hardware Config." , "Alex B.", MDY(10,10,2022), MDY(10,12,2022), 0);`); Ax.db.execute(`INSERT INTO gantt VALUES (18, 16, 1, "M", "System Testing" , "Kennedy K.", MDY(10,11,2022), MDY(10,14,2022), 0);`); Ax.db.execute(`INSERT INTO gantt VALUES (19, 1, 1, "M", "Support" , "", MDY(10,14,2022),MDY(12,24,2022), 0);`); Ax.db.execute(`INSERT INTO gantt VALUES (20, 19, 1, "M", "Acvanced formation" , "John M.", MDY(10,14,2022), MDY(10,20,2022), 0);`); Ax.db.execute(`INSERT INTO gantt VALUES (21, 19, 1, "M", "Phone Support" , "N/A", MDY(12,1,2022), MDY(12,9,2022), 0);`); // 1. Load the template var wb = Ax.ms.Excel.load("https://bitbucket.org/deister/axional-docs-resources/raw/master/Excel/templates/Gantt-Template-2.xlsx"); // 2. Create a project JSON description var sheet = wb.getSheet(0); var project = { name : "Development Software", company: "ACME Company Ltd.", manager: "The Manager Name", start_date: "1/9/2022", deliverable: "The Deliverable", } // 3. Update "project" fields wb.update(project, options => { options.setTableName("project"); } ); // 4. Load data of project items var rs = Ax.db.executeQuery(` SELECT id, parentid, orderid, level, LPAD(' ', 2 * LEVEL - 1) || TRIM(taskname) name, leader, start, end, end-start duration, completed / 100.0 completed FROM gantt START WITH id = 1 CONNECT BY PRIOR id = parentID ORDER BY id ` ); rowno = 8; for (var row of rs) { if (row.parentid == null) continue; // Get the cell from named row template var cell_rowtemplate = wb.getCellByName("rowtemplate" + row.level); // The whole row of cell var row_template = cell_rowtemplate.getRow(); // Copy root from template to sheet in row rowno, just once. sheet.copyRow(row_template, rowno, 1); sheet.setCellValue(rowno, 1, row.name); sheet.setCellValue(rowno, 2, row.leader); sheet.setCellValue(rowno, 4, row.start); sheet.setCellValue(rowno, 6, row.duration); sheet.setCellValue(rowno, 7, row.completed); rowno++; } /* console.log(sheet.getSheetConditionalFormatting().toResultSet()); for (var condFormat of sheet.getSheetConditionalFormatting()) { console.log("Format1: " + condFormat + " range:" + condFormat.getFormattingRanges()); for (var condformat2 of condFormat) { console.log(" Format2: " + condformat2); } } */ // 5. Return the Excel as BLOB Ax.db.execute('DROP TABLE gantt'); return wb.toBlob(); </script>
We have succesfully generated a Gantt type 2, filling data from JSON and database by copying level template rows from sheet 1 and filling cells with data from database.
5 Deprecation Inventory Table
You can use Excel Spreadsheers to perform, complex calculations like deprecation of inventory. In this example we defined a template where we can inject inventory data and get deprecation table.
5.1 Processing the template
Execute this script to see how to implement templates for recursive table calculation:
<script> // 1. Load the template var wb = Ax.ms.Excel.load("https://bitbucket.org/deister/axional-docs-resources/raw/master/Excel/templates/Depreciation-Template.xlsx"); // 2. Create a project JSON description var sheet = wb.getSheet(0); var asset = { code : "AXJ200-0352", name: "EMC2 DataStore 4500 E5", description: "", location: "Nevada Datacenter N1 - Rack 19", serial: "NMK345AZV", adquisition: "14/3/2019", cost: 9800.0, activation: "1/7/2019", salvage: 500, method: "SL", } // 3. Update "project" fields wb.update(asset, options => { options.setTableName("asset"); options.setEvaluate(true); } ); wb.evaluate(); // 4. Return the Excel as BLOB return wb.toBlob(); </script>
6 Data transformation
This example show how to use templates to making a transformation from source table ctercero and cterdire to match some theorical specification required by third party.
First, we create a Template Excel with two sheets: sheet0 will store data retrieved from database, sheet1 will store a row with formulas to transform this data. You can get sample template excel from ctercero.xlsx
Be aware, we use named cells to simplify template JS program. To create a vertical projection as rows of all data in recordset, you should name cells in a single column, and prefix the name with a single virtual table name followed by ".".
Example code is self explained, so follow it to understand how it works.
This example is based on tables present in Axional ERP Financials. You require to execute it in an Axional ERP database to work properly.
<script> // ================================================================================= // Load an XSL template // Sheet 0 is where we store data in named cells. // Sheet 1 is where we have the formulas to process data from named cells on sheet 0 // ================================================================================= var wb = Ax.ms.Excel.load("https://bitbucket.org/deister/axional-docs-resources/raw/master/Excel/templates/ctercero.xlsx"); // ================================================================================= // Get database data and store into memory cause we need to know the number of rows. // We will use the number of rows to copy as many Excel ROWS as database rows selected. // ================================================================================= Ax.db.execute('DROP TABLE IF EXISTS @ctercero'); Ax.db.execute('DROP TABLE IF EXISTS @cterdire'); Ax.db.execute(`CREATE TEMP TABLE @ctercero ( codigo CHAR(12), nombre NCHAR(60) );`); Ax.db.execute(`CREATE TEMP TABLE @cterdire ( codigo CHAR(12), direcc NVARCHAR(60), poblac NVARCHAR(60), codprv CHAR(6), codpos CHAR(10), codnac CHAR(3), telef1 VARCHAR(20), fax1 VARCHAR(20), email VARCHAR(255) );`); Ax.db.execute(`INSERT INTO @ctercero VALUES (00010, 'MOZART ART SL' );`); Ax.db.execute(`INSERT INTO @ctercero VALUES (00002, 'REPSOL BUTANO S.A.' );`); Ax.db.execute(`INSERT INTO @ctercero VALUES (00003, 'TELEFONICA DE ESPAÑA S.A.' );`); Ax.db.execute(`INSERT INTO @ctercero VALUES (00004, 'CEPSA' );`); Ax.db.execute(`INSERT INTO @ctercero VALUES (00005, 'SISTEMAS DIGITALES CORPORATE S.L.' );`); Ax.db.execute(`INSERT INTO @ctercero VALUES (00006, 'PROAUDIT CONSULTING, S.L.' );`); Ax.db.execute(`INSERT INTO @ctercero VALUES (00007, 'NOTARIA AGUSTIN - CASADO, C.B.' );`); Ax.db.execute(`INSERT INTO @ctercero VALUES (00008, 'COVASA' );`); Ax.db.execute(`INSERT INTO @ctercero VALUES (00009, 'CAFES BATALLA 2000 S.L.' );`); Ax.db.execute(`INSERT INTO @ctercero VALUES (90001, 'TRIATLON, SA' );`); Ax.db.execute(`INSERT INTO @cterdire VALUES (00010, 'Calle Bolivia, 195', 'Barcelona', '08', '08018', 'ESP', '933089908', '933081568', 'info@mozart.com' );`); Ax.db.execute(`INSERT INTO @cterdire VALUES (00002, 'Calle Mendez Alvaro, 44', 'Madrid', '28', '28045', 'ESP', '91 789 24 00', NULL, 'deister@gmail.com' );`); Ax.db.execute(`INSERT INTO @cterdire VALUES (00003, 'Gran Via, 28', 'Madrid', '28', '28013', 'ESP', '91 121 10 00', NULL, 'deister@gmail.com' );`); Ax.db.execute(`INSERT INTO @cterdire VALUES (00004, 'Av. del Partenon, 12 Campo De Las Naciones', 'Madrid', '28', '28042', 'ESP', '913376000', '913376003', 'deister@gmail.com' );`); Ax.db.execute(`INSERT INTO @cterdire VALUES (00005, 'Avda. Alcalde Porqueres, 6', 'Lleida', '25', '25008', 'ESP', '973 477 22 44', NULL, 'deister@gmail.com' );`); Ax.db.execute(`INSERT INTO @cterdire VALUES (00006, 'VIA LAIETANA, 45 A, 4 2º', 'Barcelona', '08', '08003', 'ESP', '934883131', NULL, 'deister@gmail.com' );`); Ax.db.execute(`INSERT INTO @cterdire VALUES (00007, 'AVDA. DIAGONAL, 538, 2º 2º', 'Barcelona', '08', '08006', 'ESP', '91 345 29 34', NULL, 'deister@gmail.com' );`); Ax.db.execute(`INSERT INTO @cterdire VALUES (00008, 'Carretera de Francia, 345', 'Ametlla Del Valles, L', '08', '08480', 'ESP', '93 890 34 55', NULL, 'deister@gmail.com' );`); Ax.db.execute(`INSERT INTO @cterdire VALUES (00009, 'Poligon Industrial Cami Dels Frares, Par.69 C/ C. Nave 1', 'Lleida', '25', '25191', 'ESP', '973 474 29 30', NULL, 'deister@gmail.com' );`); Ax.db.execute(`INSERT INTO @cterdire VALUES (90001, 'Avenida Europa Edificio Alcor Plaza 2-2', 'Alcorcón', '28', '28922', 'ESP', '918386100', '916 64 83 36', NULL );`); var rs_data = Ax.db.executeQuery(` SELECT FIRST 10 ctc.codigo, ctc.nombre, ctd.direcc, ctd.poblac, ctd.codprv, ctd.codpos, ctd.codnac, ctd.telef1 telef, ctd.fax1 fax, ctd.email, 2508 debe, 9634 haber FROM @ctercero ctc, @cterdire ctd WHERE ctc.codigo = ctd.codigo AND ctd.codpos is not null `).toMemory(); // ================================================================================= // Update excel workbook using named columns. All cells prefixed by "ctercero." // that matches a column in select will be updated. // The projection must be vertical cause we have multiple rows. This implies all // all named cells must be in a single row. // ================================================================================= wb.update(rs_data, options => { options.setTableName("ctercero"); options.setStartRow(wb.getNamedRow("ctercero") + 1); }); // ================================================================================= // Point to sheet1 where we have the formulas. // In this sheet whe have // // [row 0] cell name1, cell name2, ... // [row 1] formula1, formula2, ... // [row 2] empty // // So we have only 1 row with formulas. // // NOTICE that sheet and row starts at index 0. So accessing first sheet is // wb.getSheet(0) and second is wb.getSheet(1) // // ================================================================================= var sheet = wb.getSheet(1); var row_template = sheet.getRow(1); // ================================================================================= // Copy from row 1 (row_template in target sheet) to row 2 in target sheet up to the // number of ctercero rows selected. // // This is a magic trick. As we copy sample row with formula to increasing number // of row, copied formulas will be transformed for the new references. And will // be evauated. // ================================================================================= sheet.copyRow(row_template, row_template.getRowNum() + 1, rs_data.getRowCount()); // ================================================================================= // To retrieve formula calculated rows, you can use select() method. This method, // operates in a similar way like update() searching a row with named cells starting by // tableName and creating a resultset with all rows bellow reference one. // ================================================================================= var rs2 = wb.select(options => { options.setTableName("result"); // Select data starting at row 2 options.setStartRow(2); // Return calculated value instead of formula text options.setEvaluate(true); }); console.log(rs2); // ================================================================================= // Return the resulting Excel as BLOB // ================================================================================= return wb.toBlob(); Ax.db.execute('DROP TABLE @ctercero'); Ax.db.execute('DROP TABLE @cterdire'); </script>