Reading an array from several tables
Especially when working with arrays of more than two dimensions it may happen that the input data is split into several spreadsheet ranges/database tables.
We wish to read an array, INCOME, indexed by the sets CUST and PERIOD from three tables (one table per customer). In the first instance, assume that every data table includes both the CUST and the PERIOD index column, such as (table COLDAT1):
CUST | PERIOD | INCOME |
1 | 1 | 11 |
1 | 2 | 21 |
1 | 3 | 31 |
1 | 4 | 41 |
1 | 5 | 51 |
In this case we may read in the data with three statements within a single initializations block:
model "multiple data sources" uses "mmodbc" declarations CUST: set of integer PERIOD: range INCOME: dynamic array(CUST,PERIOD) of real end-declarations ! Method 1: Data in columns, with CUST index value included initializations from 'mmodbc.odbc:multitab.sqlite' INCOME as 'COLDAT1' INCOME as 'COLDAT2' INCOME as 'COLDAT3' end-initializations writeln("1: ", INCOME) end-model
The same with SQL statements:
SQLconnect('multitab.sqlite') SQLexecute("select CUST,PERIOD,INCOME from COLDAT1", INCOME) SQLexecute("select CUST,PERIOD,INCOME from COLDAT2", INCOME) SQLexecute("select CUST,PERIOD,INCOME from COLDAT3", INCOME) SQLdisconnect
Now assume that the input data table for each customer only contains the PERIOD index and the data value itself:
PERIOD | INCOME |
1 | 11 |
2 | 21 |
3 | 31 |
4 | 41 |
5 | 51 |
In this case we need to introduce an auxiliary array TEMP with just one index into which we read the data for every customer and that gets copied into the array INCOME. (This method supposes that we know the contents of the set CUST; with the first method this was not required.)
! Method 2: Data in columns, without CUST index value procedure readcol(cust:integer, table:string) declarations TEMP: array(PERIOD) of real end-declarations initializations from 'mmodbc.odbc:multitab.sqlite' TEMP as table end-initializations forall(p in PERIOD) INCOME2(cust,p):=TEMP(p) end-procedure forall(c in CUST) readcol(c, "COLDAT"+c+"A") writeln("2: ", INCOME)
If we wish to employ SQL statements for reading the data, the procedure readcol may look as follows (all else remains unchanged):
procedure readcol(cust:integer, table:string) declarations TEMP: array(PERIOD) of real end-declarations SQLexecute("select PERIOD,INCOME from "+table, TEMP) forall(p in PERIOD) INCOME(cust,p):=TEMP(p) end-procedure
In this case and with the rowwise representation shown below the formulation with SQL statements is likely to be more efficient since we only need to connect once to the data source and then execute a series of `select' commands. For initializations blocks we open and close an ODBC connection with every new block, that is, at every execution of the procedure readcol.
As a third case consider a representation of the data in transposed form, that is, not columnwise but rowwise as shown in the following example table. (This format may occur with spreadsheets but it is certainly less likely, though not impossible, with databases.) With Excel we always need to define a header row for a data range—here we have simply filled it with zeros since its contents is irrelevant. Any row headers written at the left or right of the data range are purely informative, they must not be selected as part of the range.
DUMMY | 0 | 0 | 0 | 0 | 0 | |
PERIOD | 1 | 2 | 3 | 4 | 5 | |
INCOME | 11 | 21 | 31 | 41 | 51 | |
Such rowwise formatted data may be read with the following Mosel code. As with the previous method, we define a procedure readrow to read data from a single data range. Both index sets, CUST and PERIOD, must be known and the set PERIOD must be finalized (this means that its contents cannot change any more and the set is treated by Mosel similarly to a constant set).
! Method 3: Data in rows, without CUST index value procedure readrow(cust:integer, table:string) declarations TEMP: array(1..2,PERIOD) of real end-declarations initializations from 'mmsheet.excel:multitab.xls' TEMP as 'noindex;'+table end-initializations forall(p in PERIOD) INCOME3(cust,p):=TEMP(2,p) end-procedure finalize(PERIOD) ! The index sets must be known+fixed forall(c in CUST) readrow(c, "ROWDAT"+c) writeln("3: ", INCOME3)
The corresponding SQL code looks as follows (notice the setting of the parameter SQLndxcol):
procedure readrow(cust:integer, table:string) declarations TEMP: array(1..2,PERIOD) of real end-declarations SQLexecute("select * from "+table, TEMP) forall(p in PERIOD) INCOME3(cust,p):=TEMP(2,p) end-procedure finalize(PERIOD) ! The index sets must be known+fixed setparam("sqlndxcol",false) ! Data specified in dense format (no indices) forall(c in CUST) readrow(c, "ROWDAT"+c) setparam("sqlndxcol",true)
To read the data from a database using the odbc driver instead of excel we merely need to change the file name:
initializations from 'mmodbc.odbc:skiph;multitab.sqlite' ...
© 2001-2020 Fair Isaac Corporation. All rights reserved. This documentation is the property of Fair Isaac Corporation (“FICO”). Receipt or possession of this documentation does not convey rights to disclose, reproduce, make derivative works, use, or allow others to use it except solely for internal evaluation purposes to determine whether to purchase a license to the software described in this documentation, or as otherwise set forth in a written software license agreement between you and FICO (or a FICO affiliate). Use of this documentation and the software described in it must conform strictly to the foregoing permitted uses, and no other use is permitted.