Interfacing GAMS with other applications

Tutorial and examples

Erwin Kalvelagen, erwin@gams.com
Amsterdam Optimization
http://www.gams.com/~erwin


This document will illustrate how GAMS can cooperate with other programs, and how GAMS can be called from familiar programming environments.

The text in this document assumes you have access to a recent GAMS system. The latest GAMS system can always be downloaded from the download page http://www.gams.com/download.

This document is under permanent construction.


Content

0. What's new

1. Importing and exporting data

1.1 GAMS Syntax for flat file input

1.2 Importing from Excel

1.2.1 Comma delimited files
1.2.2 The XLS2GMS utility
1.2.3 Excel as database

1.3 Importing from Oracle

1.3.1 SQL*Plus
1.3.2 SQL2GMS
1.3.3 Dates

1.4 Importing from Access

1.4.1 Comma delimited files
1.4.2 The MDB2GMS utility
1.4.3 MDB2GMS advanced use
1.4.4 Download MDB2GMS
1.4.5 SQL2GMS
1.4.6 Dates

1.5 Importing from DB2

1.6 Importing from MySQL

1.7 Importing from SQL Server

1.8 Importing from Sybase

1.9 The SQL2GMS utility

1.9.1 Reading DBASE files
1.9.2 SQL2GMS advanced use
1.9.3 Download SQL2GMS
1.9.4 SQL2GMS script
1.9.5 SQL2GMS timeouts

1.10 GAMS Syntax for flat file output

1.11 Exporting to Excel

1.11.1 Excel Text Import
1.11.2 Excel CSV Import
1.11.3 GDX to Excel
1.11.4 GDX2XLS
1.11.5 GDX2XLS AutoFilter

1.12 Exporting to Oracle

1.12.1 Oracle CSV Import
1.12.2 GDX to Oracle

1.13 Exporting to Access

1.13.1 Access CSV Import
1.13.2 GDX to Access
1.13.3 VBScript
1.13.4 JScript
1.13.5 Combining GDX2ACCESS with VBscript
1.13.6 Using a ref file with GDX2ACCESS 2.2

1.14 Exporting to dBase

1.15 Exporting to DB2

1.16 Exporting to MySQL

1.17 Exporting to SQL Server

1.18 Exporting to Sybase

1.19 Other tools for spreadsheet reading and writing

1.20 Exporting to LaTeX

1.21 Exporting to Gnuplot

1.22 Exporting MPS files

1.23 Importing MPS files

1.23.1 MPS2GAMS
1.23.2 MPS2GMS

1.24 Importing NETGEN network problems

1.25 Importing GNETGEN network problems

1.26 Exporting to HTML

1.27 Exporting to XML

1.28 A Mini User Interface

1.28.1 The ASK utility
1.28.2 FileOpenBox
1.28.3 Download ASK

1.29 GDX Viewer

1.29.1 GAMS IDE built-in viewer
1.29.2 Standalone GDX Viewer
1.29.3 GDXViewer List View
1.29.4 GDXViewer Cube View
1.29.5 GDXViewer Graphs
1.29.6 GDXViewer Command Line Processing
1.29.7 Download GDXViewer

1.30 ShellExecute

1.31 Tips, tricks and caveats

Tip: extension to 3 and more dimensions
Tip: macro's for repetitions
Caveat: Non American English language settings
Tip: Mapping index label names I
Tip: Mapping index label names II
Tip: Save and restart
Tip: Save and restart 2
Tip: Once a day data extraction
Tip: Reading CSV files with SQL2GMS

2 Executing GAMS

2.1 GAMS return codes

2.2 Spawning GAMS

2.3 Spawning GAMS from C: a minimal example

2.4 Spawning GAMS from Visual Basic

2.5 Spawning GAMS from Delphi

2.6 Spawning GAMS from Excel and Access

2.7 Spawning GAMS from Visual C++

2.8 Spawning GAMS from Oracle (advanced example)

2.9 Spawning GAMS from Java

2.10 Spawning GAMS from a Web Server

2.11 Spawning GAMS from a Job Scheduler

2.11.1 The Windows Task Scheduler
2.11.2 The Windows NT AT Command
2.11.3 cron on Unix/Linux

2.12 Remote execution of GAMS jobs from the IDE

2.13 Running GAMS from an ActiveX component

2.14 Spawning GAMS from C#

3 External functions

3.1 A simple example

3.2 Spline interpolation

4 GDX API

4.1 GDX Introduction

4.2 API Documentation

4.3 Language bindings


0. What's new

datedescription
jan 2001Added download sections to table of contents
feb 2001Coloring of literal text, addition of external functions
march 2001Added NETGEN, GNETGEN and MPS sections
june 2001TSP example now references http://www.gams.com/~erwin/mip1.pdf.
QP example now references http://www.gams.com/~erwin/nlp1.pdf.
Fixed exegams.xls so it works on NT4/Excel2000
Added CloseHandle to exegams.xls
aug 2001Added reference to http://www.gams.com/~erwin/interpolation.pdf.
Updated the link to XLLINK.
Mention $call problem on Win2K
dec 2001XLS2GMS updated
Added Visual C++ CreateProcess example with I/O redirection
jan 2002Mention $call parsing bugs
Changed link to GNUPLOT home page
Added reference to GAMS/FITPACK (PDF)
march 2002New section 2.7, 2.8, 2.9 (Oracle, Java and Web server interfaces)
Added reference: GAMS/ORAQUEUE (PDF)
Added reference: http://www.gams.com/mccarl/excelgams.pdf
june 2002Mention new GDX Excel interface
june 2002Large XLS2GMS example: http://www.gams.com/~erwin/lineq/lineq.pdf.
august 2002 A Mini User Interface (the ASK utility)
GDX Viewer
sept 2002Exporting to HTML
Exporting to XML
oct 2002Mention http://www.gams.com/~erwin/dea/dea.pdf
Info on MPS2GMS in 1.23 Importing MPS files
GDX Viewer v 2.1 loads DLL correctly under NT/W2K/XP
jan 2003New: Remote execution of GAMS jobs from the IDE
New: Importing from MySQL
New: Exporting to MySQL
April 2003New:1.29.6 GDXViewer Command Line Processing
April 2003GDXViewer can now export tables to any SQL database
feb 2004Added multiple-area ranges to XLS2GMS v2 in order to be able to read Swedish national accounts. Updated help file.
march 2004WTOOLS package.
april 2004ShellExecute tool.
GDX API
july 2004In GDX API Language bindings gdx2txt, txt2gdx
august 2004Notes on SQL Server, Importing from SQL Server, Exporting to SQL Server
sept 2004Dump whole gdx file to an Access database: 1.13.2 GDX to Access
october 2004Notes on Sybase, Importing from Sybase, Exporting to Sybase
feb 2005Added example of GDX use: calculation of eigenvalues/eigenvectors. See f90 section of 4.3 GDXIO Language bindings
march 2005Added example of GDX use: calculation of inverse of a matrix. See f90 section of 4.3 GDXIO Language bindings
june 2005Dump whole gdx file to an Excel spreadsheet: 1.11.4 GDX2XLS
jan 2006Added Sudoku and portfolio spreadsheet examples to 2.6 Spawning GAMS from Excel and Access
nov 2006Added SQL2GMS written in VBscript 1.9.4 SQL2GMS script
dec 2006GDX2XLS now generates tables with autofilter 1.11.5 GDX2XLS AutoFilter
Timeouts are added to SQL2GMS, section 1.9.5 SQL2GMS timeouts
GDX2XLS and GDX2ACCESS can read GAMS reference files.
jan 2007MDB2GMS and SQL2GMS now prefetch result set rows, giving a noticeable performance improvement.
feb 2007Free Pascal bindings for GDXIO (section 4.3 GDXIO Language bindings)
Importing CSV files with SQL2GMS (section Tip: Reading CSV files with SQL2GMS)
aug 2007GDX2DBF to export GDX files to DBF (dBase,xBase,FoxPro) files section 1.14


1. Importing and exporting data


1.1 GAMS Syntax for flat file input

In this section we discuss some of the features that GAMS offers to do efficient and reliable flat file data input. Most programming languages and environments have the facilities to create flat ASCII (or EBCDIC for our IBM mainframe audience) files. In some cases GAMS can read those files directly (as we shall demonstrate below). In other cases popular scripting languages like Perl, AWK or REXX are very suited to transform them in a form that GAMS can digest.

To start with the bad news: GAMS does not have an equivalent of a read statement. All data has to be available at compile time, and inserted into the compiler input stream. This may seem a significant drawback, and indeed for some applications this is really a problem, but in many cases we can live with the techniques discussed in this document.

A basic task when importing data is to separate model specification and data input. The include facility in GAMS is very helpful in this respect. For instance when the data for a table is actually coming from another environment, one could replace the TABLE statement by an include statement. A GAMS TABLE is in fact very well suited for a human being to be read or written, but it is rather awkward for programs to generate (e.g. the numbers have to be approximately below the corresponding headers). Therefore often parameters are used, and long series of assignments are generated. For instance consider the following fragment from the TRNSPORT model which can be found in the model library:


table d(i,j) 'distance in thousands of miles'
             NEW-YORK CHICAGO TOPEKA
    SEATTLE     2.5     1.7     1.8
    SAN-DIEGO   2.5     1.8     1.4 ;
When the data for this table is coming from a program it is more convenient to say in the main program:

parameter d(i,j) 'distance in thousands of miles';
$include data.inc
display d;
and to have the include file to contain the machine generated statements:

d("SEATTLE","NEW-YORK") = 2.5;
d("SAN-DIEGO","NEW-YORK") = 2.5;
d("SEATTLE","CHICAGO") = 1.7;
d("SAN-DIEGO","CHICAGO") = 1.8;
d("SEATTLE","TOPEKA") = 1.8;
d("SAN-DIEGO","TOPEKA") = 1.4;
In fact GAMS can deal quite comfortably with a large number of such assignment statements. Models with hundreds of thousands of such statements are not an exception. Sometimes it is desired not to have the input echoed to the listing file. In that case, surround the $include by $offlisting and $onlisting instructions:

parameter d(i,j) 'distance in thousands of miles';
$offlisting
$include data.inc
$onlisting
display d;
You will notice in the listing file that line numbers are skipped where the $offlisting is in effect. In some cases it may be more convenient to use the PARAMETER initialization syntax. I.e. the main GAMS file could contain the fragment:

parameter d(i,j) 'distance in thousands of miles' /
$include data2.inc
/;
display d;
Here you see that the $include is handled in a preprocessing step before the language compiler parses the syntax: the include statements can even be used in the middle of a GAMS statement. The data file contains the following records:

SEATTLE.NEW-YORK 2.5
SAN-DIEGO.NEW-YORK 2.5
SEATTLE.CHICAGO 1.7
SAN-DIEGO.CHICAGO 1.8
SEATTLE.TOPEKA 1.8
SAN-DIEGO.TOPEKA 1.4
This approach is preferable for very large data sets as it is more efficient for GAMS.
Note: TABLEs and PARAMETERs in GAMS are really the same thing. Internally both are handled identically. The only difference is how data is entered. With a TABLE a tabular input format is used, while PARAMETERS are either calculated or inputted as a list.

1.2 Importing from Excel

1.2.1 Comma delimited files

Yet another approach is to go back to our TABLE statement, but now use comma, space or tab characters to separate the numbers. The format is for instance easily generated by Excel, using its Save As CSV functionality. Consider again our table:

table d(i,j) 'distance in thousands of miles'
             NEW-YORK CHICAGO TOPEKA
    SEATTLE     2.5     1.7     1.8
    SAN-DIEGO   2.5     1.8     1.4
In Excel 97 the table can be easily entered as follows:

Notice that we added a 'dummy' string in cell A1. This is necessary as we need a placeholder there (the underlying problem is a bug in GAMS: the comma should be enough to signal the end of a field). Now we save this worksheet as a CSV file - the type is: CSV (Comma delimited) - which will look like:


dummy,new-york,chicago,topeka
seattle,2.5,1.7,1.8
san-diego,2.5,1.8,1.4
CSV stands for Comma-Separated Values format and is a simple exchange format. This file can now be included directly into GAMS by using the $ondelim and $offdelim commands:

table d(i,j) 'distance in thousands of miles'
$ondelim
$include data.csv
$offdelim
display d;
Notice we have left out a ';' between the TABLE statement and the display statement. Usually GAMS is quite forgiving in this, and indeed the listing file shows:

  40  table d(i,j)  'distance in thousands of miles'
INCLUDE    D:\SUPPORT\DATA.CSV
  43  dummy,new-york,chicago,topeka
  44  seattle,2.5,1.7,1.8
  45  san-diego,2.5,1.8,1.4
  47  display d;

1.2.2 XLS2GMS, a simple utility

XLS2GMS is a simple utility that allows you to extract data from an Excel spreadsheet and convert it into a GAMS include file. When running xls2gms.exe without extra command line parameters, the utility will run in interactive mode. It will come up with the following form:

The input file consists of an .XLS file. By default the used part of the first sheet is exported, but this can be changed by setting an appropriate range. An example of a range that can be specified is Sheet2!A1:G8. An output file is created that can be used as a GAMS include file. The browse buttons open a File Open or a Save As dialog box that can help you in navigating around on your hard disk. It is advised to use absolute paths, as for windows applications it is not always obvious what the current directory is.

The philosophy of the utility is that you write pure GAMS syntax in the spreadsheet. I.e. you can write GAMS statements such as TABLE, SET, PARAMETER or parts of them. It is your responsability to write correct GAMS syntax. The only "smart" thing the utility does it to align cells, such that GAMS TABLE data are correctly handled.

In the above example we have a simple spreadsheet:

The output for this spreadsheet will look like:


* -----------------------------------------------------
* XLS2GMS Version 1.3, September 2000
* Erwin Kalvelagen, GAMS Development Corp.
* -----------------------------------------------------
* Application: Microsoft Excel
* Version:     8.0e
* Workbook:    C:\My Documents\test.xls
* Sheet:       Sheet1
* Range:       $A$1:$C$3
* -----------------------------------------------------
   j1 j2
i1 1  4
i2 2  3
* -----------------------------------------------------
Note: XLS2GMS is no longer distributed with GAMS. Instead use GDXXRW. PDF documentation is here: xls2gms.pdf.

Some uses of XLS2GMS are found in:

  • D. Baker, Provision of quality attributes in the food marketing chain, Danish Research Institute of Food Economics, Model for provision of food quality attributes: paper to be presented at World Livestock Congress, December 2003, www.dfk.foi.dk
  • Thomas F. Rutherford, Three Steps Involved in Implementing a GAMS/MPSGE Model, Department of Economics, University of Colorado, 2003, http://debreu.colorado.edu/tza/.
  • Erwin Kalvelagen, Solving Systems of Linear Equations with GAMS, 2002, http://www.gams.com/~erwin/lineq/lineq.pdf
  • S. K. Srivastava, R. K. Srivastava, A Hierarchical Model for Profit-driven Reverse Logistics Network Design Second World Conference on POM and 15th Annual POM Conference, Cancun, Mexico, April 30 - May 3, 2004.
  • 1.2.3 Excel as database

    In some cases it is convenient to consider tabular data in an Excel spreadsheet as a database table. Consider the spreadsheet:
    profitxls.png
    This table can be read using an SQL query:
    
    SELECT year,loc,prod,'sales',sales FROM [profitdata$] UNION SELECT year,loc,prod,'profit',profit FROM [profitdata$]
    
    The table name is equal to the sheet name. We can pass the query to the Excel ODBC driver using the tool SQL2GMS as follows:
    
    $ontext
    
      Test MS EXCEL access through ODBC
    
    $offtext
    
    set y 'years'   /1997,1998/;
    set c 'city'    /la,nyc,sfo,was/;
    set p 'product' /hardware,software/;
    set k 'key'     /sales,profit/;
    
    $onecho > excelcmd.txt
    c=DRIVER=Microsoft Excel Driver (*.xls);dbq=%system.fp%profit.xls;
    q=SELECT year,loc,prod,'sales',sales FROM [profitdata$] UNION SELECT year,loc,prod,'profit',profit FROM [profitdata$]
    o=excel.inc
    $offecho
    $call =sql2gms @excelcmd.txt
    
    parameter d(y,c,p,k) /
    $include excel.inc
    /;
    display d;
    
    The resulting include file will look like:
    
    * -----------------------------------------------------
    * SQL2GMS Version 2.2, May 2005
    * Erwin Kalvelagen, GAMS Development Corp
    * -----------------------------------------------------
    * ADO version: 2.8
    * Connection string: DRIVER=Microsoft Excel Driver (*.xls);dbq=C:\gams projects\wtools\ver002\examples\profit.xls;
    * Provider: MSDASQL
    * Query: SELECT year,loc,prod,'sales',sales FROM [profitdata$] UNION SELECT year,loc,prod,'profit',profit FROM [profitdata$]
    * -----------------------------------------------------
    1997.la.hardware.profit 8
    1997.la.hardware.sales 80
    1997.la.software.profit 16
    1997.la.software.sales 60
    1997.nyc.hardware.profit 5
    1997.nyc.hardware.sales 110
    1997.nyc.software.profit 10
    1997.nyc.software.sales 100
    1997.sfo.hardware.profit 9
    1997.sfo.hardware.sales 80
    1997.sfo.software.profit 10
    1997.sfo.software.sales 50
    1997.was.hardware.profit 7
    1997.was.hardware.sales 120
    1997.was.software.profit 20
    1997.was.software.sales 70
    1998.la.hardware.profit 6
    1998.la.hardware.sales 70
    1998.la.software.profit 10
    1998.la.software.sales 70
    1998.nyc.hardware.profit 7
    1998.nyc.hardware.sales 120
    1998.nyc.software.profit 14
    1998.nyc.software.sales 120
    1998.sfo.hardware.profit 12
    1998.sfo.hardware.sales 90
    1998.sfo.software.profit 15
    1998.sfo.software.sales 70
    1998.was.hardware.profit 12
    1998.was.hardware.sales 130
    1998.was.software.profit 15
    1998.was.software.sales 80
    * -----------------------------------------------------
    
    and the DISPLAY results will be:
    
    ----     65 PARAMETER d
    
    INDEX 1 = 1997
    
                       sales      profit
    
    la .hardware      80.000       8.000
    la .software      60.000      16.000
    nyc.hardware     110.000       5.000
    nyc.software     100.000      10.000
    sfo.hardware      80.000       9.000
    sfo.software      50.000      10.000
    was.hardware     120.000       7.000
    was.software      70.000      20.000
    
    INDEX 1 = 1998
    
                       sales      profit
    
    la .hardware      70.000       6.000
    la .software      70.000      10.000
    nyc.hardware     120.000       7.000
    nyc.software     120.000      14.000
    sfo.hardware      90.000      12.000
    sfo.software      70.000      15.000
    was.hardware     130.000      12.000
    was.software      80.000      15.000
    
    More information on SQL2GMS can be found in section 1.9 The SQL2GMS utility.

    1.3 Importing from Oracle

    1.3.1 SQL*Plus

    To export an Oracle table a simple solution is to write an SQL*Plus script. E.g. if our table looks like:
    
    SQL> describe dist;
     Name                                Null?    Type
     ----------------------------------- -------- ------------------------
     LOCA                                NOT NULL VARCHAR2(10)
     LOCB                                NOT NULL VARCHAR2(10)
     DISTANCE                                     NUMBER
    
    SQL> select * from dist;
    
    LOCA       LOCB        DISTANCE
    ---------- ---------- ---------
    seattle    new-york         2.5
    seattle    chicago          1.7
    seattle    topeka           1.8
    san-diego  new-york         2.5
    san-diego  chicago          1.8
    san-diego  topeka           1.4
    
    6 rows selected.
    
    SQL>
    
    then the following script will export this table:
    
    set pagesize 0
    set pause off
    set heading off
    spool data
    select loca||','||locb||','||distance from dist;
    spool off
    
    The resulting data file data.lst will look like:
    
    seattle,new-york,2.5
    seattle,chicago,1.7
    seattle,topeka,1.8
    san-diego,new-york,2.5
    san-diego,chicago,1.8
    san-diego,topeka,1.4
    
    This almost looks like our data initialization syntax for parameters:
    
    SEATTLE.NEW-YORK 2.5
    SAN-DIEGO.NEW-YORK 2.5
    SEATTLE.CHICAGO 1.7
    SAN-DIEGO.CHICAGO 1.8
    SEATTLE.TOPEKA 1.8
    SAN-DIEGO.TOPEKA 1.4
    
    The only differences are in the delimiters that are being used. These differences are easily digested by GAMS once it is in ondelim mode. I.e. the following syntax can be used to read the data.lst file:
    
    parameter d(i,j) 'distance in thousands of miles' /
    $ondelim
    $include data.lst
    $offdelim
    /;
    display d;
    

    1.3.2 SQL2GMS

    An alternative way to import data from Oracle is to use the tool SQL2GMS which can talk to any database with an ADO or ODBC interface.

    1.3.3 Dates

    Importing dates from Oracle databases and converting them to GAMS dates.

    For most software it is easy to generate dates that GAMS can import and understand. The most common issue is that GAMS is one day off compared to Excel, Delphi, Access, ODBC etc. Oracle is somewhat more involved. First it is useful to have the date/time exported as a Julian date. This can be done with the following stored procedure:

    
    -- julian representation of a date/time 
    -- Erwin Kalvelagen, feb 2007
    create or replace function to_julian(d IN TIMESTAMP)
    return number
    is
    begin
    return to_number(to_char(d,'J')) + to_number(to_char(d,'SSSSS'))/86400;
    end;
    
    This function can be used to export dates as simple floating point numbers. In GAMS we need just a simple adjustment by adding a constant DATEDIFF defined by:
    
    scalar
       refdategams   "march 16, 2006, 00:00"
       refdateoracle "march 16, 2006, 00:00"  /2453811/
       datediff      "difference between GAMS and Oracle date"
    ;
    refdategams = jdate(2006,3,16);
    datediff = refdategams-refdateoracle;  
    
    This trick has been applied in a complex scheduling application where dates are important datatypes that must be exchanged between the application logic and database tier and the optimization engine.

    1.4 Importing from Access

    1.4.1 Comma delimited files

    MS Access 97 can export tables into comma delimited text files using its Save As/Export menu. Suppose we have the following table:

    After choosing Save As/Export and selecting Text Files we get the following window:

    Just using the default settings, we get the following file:

    
    "seattle","new-york",2.50
    "seattle","chicago",1.70
    "seattle","topeka",1.80
    "san-diego","new-york",2.50
    "san-diego","chicago",1.80
    "san-diego","topeka",1.40
    
    which can be handled by:
    
    parameter d(i,j) 'distance in thousands of miles' /
    $ondelim
    $include dist.txt
    $offdelim
    /;
    display d;
    

    1.4.2 MDB2GMS, a simple utility

    MDB2GMS is a simple utility that allows you to extract data from an Access database and convert it into a GAMS include file. When running xls2gms.exe without extra command line parameters, the utility will run in interactive mode. It will come up with the following form:


    To extract data from an Access database we use a technique called DAO or Data Access Objects. DAO in its turn uses the Microsoft Jet Database Engine to access the Access database. The name of the database file ( .mdb file) is specified in the Input file field. The output file is specified in the second edit control. The Browse buttons allow you to navigate around on your hard disks.

    To select data the standard query language SQL is used. A query results in a table, which is formatted as a GAMS parameter initialization construct. Parameter initializations look in GAMS like:

    
    parameter p(i,j) /
            i1.j1 10.0
            i1.j2 12.1
            i1.j3  8.2
    /;
    
    If the result table contains n columns, then the first n-1 columns are considered to be sets. They contain index labels and are separated by a dot. The last column contains the data. I.e. the above syntax can be generated for the query: "select i,j,p from table" where table could look like:
    pji
    10.0j1i1
    12.1j2i1
    8.2j3i1

    Note that the order of the columns is irrelevant unless you specify select *.

    For the exact syntax of the queries that is accepted by Access we refer to the documentation that comes with MS Access. One notable syntax feature is that when field names or table names contain blanks, they can be specified in square brackets. Examples:

    
    select * from mytable
    
    select year, production from [production table]
    
    select [GAMS City],value from [example table],CityMapper where [Access City]=city
    
    There are a few special options: After setting the desired options, the OK button can be pressed to actually perform the translation.

    The utility can also be used in batch mode. I.e. if you specify from the command line:

    
    mdb2gms "I=c:\My Documents\test.mdb" O=test.inc Q="select * from data"
    
    then the utility will perform the translation without user intervention. Notice that command line parameters that contain blanks are protected by surrounding them with quotes. This command line mode can also be used from within a GAMS model.

    Consider the following table:

    Assume we want to extract sales and profit data. This can be done with the following GAMS code:

    
    set y 'years' /1997*1998/;
    set loc 'locations' /nyc,was,la,sfo/;
    set prd 'products' /hardware, software/;
    
    parameter sales(prd,loc,y) /
    $call =d:\util\mdb2gms I="C:\My Documents\test.mdb" Q="select prod,loc,year,sales from data" O=d:\tmp\sales.inc
    $include d:\tmp\sales.inc
    /;
    display sales;
    
    parameter profit(prd,loc,y) /
    $call =d:\util\mdb2gms I="C:\My Documents\test.mdb" Q="select prod,loc,year,profit from data" O=d:\tmp\profit.inc
    $include d:\tmp\profit.inc
    /;
    display profit;
    
    The listing file will show how this was expanded:
    
       1  set y years /1997*1998/;
       2  set loc locations /nyc,was,la,sfo/;
       3  set prd products /hardware, software/;
       4
       5  parameter sales(prd,loc,y) /
    INCLUDE    D:\TMP\SALES.INC
       8  * -----------------------------------------------------
       9  * MDB2GMS Version 1.2, September 2000
      10  * Erwin Kalvelagen, GAMS Development Corp
      11  * -----------------------------------------------------
      12  * DAO version: 3.51
      13  * Jet version: 3.0
      14  * Database:    C:\My Documents\test.mdb
      15  * Query:       select prod,loc,year,sales from data
      16  * -----------------------------------------------------
      17  software.nyc.1997 100
      18  software.was.1997 70
      19  software.la.1997 60
      20  software.sfo.1997 50
      21  hardware.nyc.1997 110
      22  hardware.was.1997 120
      23  hardware.la.1997 80
      24  hardware.sfo.1997 80
      25  hardware.la.1998 70
      26  software.la.1998 70
      27  hardware.nyc.1998 120
      28  software.nyc.1998 120
      29  hardware.sfo.1998 90
      30  software.sfo.1998 70
      31  hardware.was.1998 130
      32  software.was.1998 80
      33  * -----------------------------------------------------
      34  /;
      35  display sales;
      36
      37  parameter profit(prd,loc,y) /
    INCLUDE    D:\TMP\PROFIT.INC
      40  * -----------------------------------------------------
      41  * MDB2GMS Version 1.2, September 2000
      42  * Erwin Kalvelagen, GAMS Development Corp
      43  * -----------------------------------------------------
      44  * DAO version: 3.51
      45  * Jet version: 3.0
      46  * Database:    C:\My Documents\test.mdb
      47  * Query:       select prod,loc,year,profit from data
      48  * -----------------------------------------------------
      49  software.nyc.1997 10
      50  software.was.1997 20
      51  software.la.1997 16
      52  software.sfo.1997 10
      53  hardware.nyc.1997 5
      54  hardware.was.1997 7
      55  hardware.la.1997 8
      56  hardware.sfo.1997 9
      57  hardware.la.1998 6
      58  software.la.1998 10
      59  hardware.nyc.1998 7
      60  software.nyc.1998 14
      61  hardware.sfo.1998 12
      62  software.sfo.1998 15
      63  hardware.was.1998 12
      64  software.was.1998 15
      65  * -----------------------------------------------------
      66  /;
      67  display profit;
    
    The file summary gives us an overview of what files were used in this model:
    
      SEQ   GLOBAL TYPE      PARENT   LOCAL  FILENAME
    
         1        1 INPUT          0       0  D:\IMPORT\SRC\ACCESS\TEST1.GMS
         2        6 CALL           1       6  =d:\util\mdb2gms I="C:\My Documents\test.mdb" Q="select prod,loc,year,sales from data" O=d:\tmp\sales.inc
         3        7 INCLUDE        1       7  .D:\TMP\SALES.INC
         4       38 CALL           1      12  =d:\util\mdb2gms I="C:\My Documents\test.mdb" Q="select prod,loc,year,profit from data" O=d:\tmp\profit.inc
         5       39 INCLUDE        1      13  .D:\TMP\PROFIT.INC
    
    The headers are described in paragraph 1.2.2.

    The results of the DISPLAY statements can be used to verify the data was read correctly:

    
    ----     35 PARAMETER sales
    
                        1997        1998
    
    hardware.nyc     110.000     120.000
    hardware.was     120.000     130.000
    hardware.la       80.000      70.000
    hardware.sfo      80.000      90.000
    software.nyc     100.000     120.000
    software.was      70.000      80.000
    software.la       60.000      70.000
    software.sfo      50.000      70.000
    
    
    ----     67 PARAMETER profit
    
                        1997        1998
    
    hardware.nyc       5.000       7.000
    hardware.was       7.000      12.000
    hardware.la        8.000       6.000
    hardware.sfo       9.000      12.000
    software.nyc      10.000      14.000
    software.was      20.000      15.000
    software.la       16.000      10.000
    software.sfo      10.000      15.000
    
    Note: To load the above table into one parameter we can use the following SQL query:
    
    SELECT year,loc,prod,'sales',sales FROM data
    UNION 
    SELECT year,loc,prod,'profit',profit FROM data
    
    which will generate an include file that can be read as follows:
    
    parameter data(year,loc,prod,*) /
    $include data.inc
    /;
    
    To be complete we show the generated include file:
    
    * -----------------------------------------------------
    * MDB2GMS Version 2.0, November 2003
    * Erwin Kalvelagen, GAMS Development Corp
    * -----------------------------------------------------
    * DAO version: 3.6
    * Jet version: 4.0
    * Database:    E:\models\trnsportdata.mdb
    * Query:       select year,loc,prod,'sales',sales from data
    *              union
    *              select year,loc,prod,'profit',profit from data
    * -----------------------------------------------------
    1997.la.hardware.profit 8
    1997.la.hardware.sales 80
    1997.la.software.profit 16
    1997.la.software.sales 60
    1997.nyc.hardware.profit 5
    1997.nyc.hardware.sales 110
    1997.nyc.software.profit 10
    1997.nyc.software.sales 100
    1997.sfo.hardware.profit 9
    1997.sfo.hardware.sales 80
    1997.sfo.software.profit 10
    1997.sfo.software.sales 50
    1997.was.hardware.profit 7
    1997.was.hardware.sales 120
    1997.was.software.profit 20
    1997.was.software.sales 70
    1998.la.hardware.profit 6
    1998.la.hardware.sales 70
    1998.la.software.profit 10
    1998.la.software.sales 70
    1998.nyc.hardware.profit 7
    1998.nyc.hardware.sales 120
    1998.nyc.software.profit 14
    1998.nyc.software.sales 120
    1998.sfo.hardware.profit 12
    1998.sfo.hardware.sales 90
    1998.sfo.software.profit 15
    1998.sfo.software.sales 70
    1998.was.hardware.profit 12
    1998.was.hardware.sales 130
    1998.was.software.profit 15
    1998.was.software.sales 80
    * -----------------------------------------------------
    
    In the $call statement the name mdb2gms is prefixed with an equal sign. The '=' sign is needed to tell GAMS to bypass the command processor (e.g. command.com). This is needed to make sure that the utility is finished before GAMS starts to execute the $include command.

    If the '=' is absent first a shell (Unix) or command.com (Windows) is loaded, and subsequently this command processor will load the program. This extra step is only needed when executing for instance batch files, but is just a waste of resources otherwise. In our case it is even required to run directory as Window's programs running under a command processor are running detached: the command processor will terminate, giving control back to GAMS while the import filter is not finished yet. This will cause GAMS to read output files, which are not ready yet. If the program is run directly, GAMS will wait with reading the file until the import filter has properly terminated. Another problem when running a program via command.com is he limited command line length (128 characters). I.e. the '=' is an ugly but necessary detail.

    Note: for illustrative purposes we also show you another way of doing this:
    
    $call start /w d:\util\mdb2gms "i=c:\my documents\test.mdb" o=d:\tmp\test.in q="select * from mytable"
    
    which uses the Windows start command to make sure mdb2gms finishes before GAMS proceeds.
    Note 2: The original design by the author introduced a new dollar control option: $import which would combine the $call and the $include constructs. A prototype has been implemented that allowed the user to say:
    
    $import mdb2gms "i=c:\my documents\test.mdb" q="select * from mytable"
    
    instead of
    
    $call =d:\utils\mdb2gms "i=c:\my documents\test.mdb" o=d:\tmp\x.inc q="select * from mytable"
    $include d:\tmp\x.inc
    
    Unfortunately this feature never made it into the production version of GAMS.
    We use command line parameters to pass on options to the import filter program. This will cause long command lines. The current version of GAMS does not allow command lines longer than 255 characters. When specifying many long parameters, you may run out of space. To prevent long command lines we allow the command line parameters to be stored in a separate text file. The name of this text file can then be passed on as a command line parameter by prefixing it with an @ sign:
    
    @filename
    
    An example:
    
    set i /
    $call =d:\utils\mdb2gms @"C:\My Documents\options.txt"
    $include "c:\my documents\data.inc"
    /;
    
    where options.txt contains the text:
    
    I=C:\my documents\test.mdb
    Q=select * from mytable
    O=C:\my documents\data.inc
    
    Each option should be on its own line. File names containing blanks don't need quotes, but if they are present they are filtered out. It is possible to have GAMS write the command file as follows:
    
    $set cmdfile "c:\windows\temp\commands.txt"
    $echo "I=E:\models\labordata.mdb" >  "%cmdfile%"
    $echo "O=E:\models\labor.INC"     >> "%cmdfile%"
    $echo "Q=select * from labor"     >> "%cmdfile%"
    $call ="d:\win9x program files\gams21.2\mdb2gms.exe" @"%cmdfile%"
    
    parameter p /
    $include "E:\models\labor.INC"
    /;
    display p;
    
    Newer versions of GAMS allow for:
    
    $set cmdfile "c:\windows\temp\commands.txt"
    $onecho  >  "%cmdfile%"
    I=E:\models\labordata.mdb
    O=E:\models\labor.INC
    Q=select * from labor
    $offecho
    $call ="d:\win9x program files\gams21.2\mdb2gms.exe" @"%cmdfile%"
    
    parameter p /
    $include "E:\models\labor.INC"
    /;
    display p;
    

    Version 1.4 of MDB2GMS allows to write data to a GDX file instead of or in addition to a GAMS include file. GDX files are explained in in section section 1.29. The command line parameter is X=gdxfile.gdx.

    The following command line options are available for mdb2gms: R=batchrowsize
    OptionDescription
    I=inputfileThis option is required and specifies the name of the .MDB file containing the Access database. If the file contains blanks the name should be surrounded by double quotes. It is advised to use absolute paths, so Access has no confusion what file to open. On a network UNC names can be used, and files from another computer can be accessed, e.g. "\\hostname\c\my documents\a.mdb." This option is required.
    O=outputfileThis option specifies the name of the output file. Make sure the directory is writeable. UNC names can be used. This is a required option.
    Q=queryThis option can be used to specify an SQL query. Queries contain spaces and thus have to be surrounded by double quotes. For the exact syntax of the queries that is accepted by Access we refer to the documentation that comes with MS Access. One notable syntax feature is that when field names or table names contain blanks, they can be specified in square brackets. Examples:
     Q="select * from mytable"
     Q="select year, production from [production table]"
     Q="select [GAMS City],value from [example table],CityMapper where [Access City]=city"
    
    DDebug. This option can be used for debugging purposes. If specified the import filter will no run minimized but "restored", i.e. as a normal window. In addition the program will not terminate until the user clicks the Close button. This allows you to monitor possible errors during execution of mdb2gms.
    BIf this parameter is specified, strings that have blanks in them will be quoted. If the string is already quoted this step is not performed. If the name contains an embedded single quote, the surrounding quotes will be double quotes. If the name already contains a double quote, the surrounding quotes will be single quotes. If both single and double quotes are present in the string, then all double quotes are replaced by single quotes and the surrounding quotes will be double quotes. By default this option is turned off.
    MRun in modest or mute mode: no additional information, such as version number etc. is written to the listing file.
    LEmbed the data in $offlisting, $onlisting. A quick way to reduce the size of the listing file.
    @filenameCauses the program to read options from a file. If the file name contains blanks, it can be surrounded by double quotes. The option file contains one option per line, in the same syntax as if it were specified on the command line.
    X=GDXfilenameWrites results to the specified GDX file. For more information on GDX files see section GDXViewer. This option is new in version 1.4.
    Version 2.8 introduces a command line parameter to set how many rows are imported by the utility at the time. By default R=100. This strategy gives a significant performance improvement. E.g. a complex 625000 row query had the following result:
    R=nOutputseconds
    1include file276.69
    1gdx file265.11
    100include file48.75
    100gdx file40.41

    Notes

    1.4.3 MDB2GMS advanced use

    Version 1.4 allows for writing query results to a GDX file instead of or in addition to a GAMS include file. For more information on GDX files see section section 1.28. The user interface has been changed to include a facility for providing a GDX filename:

    Writing to the GDX file is also supported through the command line using the X=gdxfilename command line parameter. As there is significant overhead in starting MS Access and opening the database file, a facility has been added to execute multiple queries in one call. For example:
    
    $ontext
    
      Example database access with MDB2GMS
    
      Multiple queries in one call
    
    $offtext
    
    $onecho > cmd.txt
    I=%system.fp%sample.mdb
    
    Q1=select distinct(year) from data
    O1=year.inc
    
    Q2=select distinct(loc) from data
    O2=loc.inc
    
    Q3=select distinct(prod) from data
    O3=prod.inc
    
    Q4=select prod,loc,year,sales from data
    O4=sales.inc
    
    Q5=select prod,loc,year,profit from data
    O5=profit.inc
    $offecho
    
    $call =mdb2gms @cmd.txt
    
    set y 'years' /
    $include year.inc
    /;
    set loc 'locations' /
    $include loc.inc
    /;
    set prd 'products' /
    $include prod.inc
    /;
    
    parameter sales(prd,loc,y) /
    $include sales.inc
    /;
    display sales;
    
    parameter profit(prd,loc,y) /
    $include profit.inc
    /;
    display profit;
    
    Notice that Qn is matched by On. It is also possible to write directly to a GDX file:
    
    $ontext
    
      Example database access with MDB2GMS
    
      Multiple queries in one call, store in GDX file
    
    $offtext
    
    $onecho > cmd.txt
    I=%system.fp%sample.mdb
    X=sample.gdx
    
    Q1=select distinct(year) from data
    s1=year
    
    Q2=select distinct(loc) from data
    s2=loc
    
    Q3=select distinct(prod) from data
    s3=prd
    
    Q4=select prod,loc,year,sales from data
    p4=sales
    
    Q5=select prod,loc,year,profit from data
    p5=profit
    $offecho
    
    $call =mdb2gms @cmd.txt
    
    $call =gdxviewer sample.gdx
    
    set y 'years';
    set loc 'locations';
    set prd 'products';
    parameter sales(prd,loc,y);
    parameter profit(prd,loc,y);
    
    $gdxin 'sample.gdx'
    $load y=year loc prd sales profit
    
    display sales;
    display profit;
    
    Here a query Qn is matched either by a set name Sn or a parameter name Pn.

    1.4.4 Download MDB2GMS

    MDB2GMS is now part of the standard GAMS distribution. PDF documentation is here: mdb2gms.pdf.

    Example applications:

    1.4.5 SQL2GMS

    MDB2GMS requires availability of MS Access. The tool SQL2GMS can be used to read MDB files without having Access installed on your machines. The following connection strings can be used to read Access tables:
    ODBC
    
    C=DRIVER={Microsoft Access Driver (*.mdb)};dbq=c:\path\file.mdb 
    
    OLEDB
    
    C=Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\path\file.mdb
    
    See section: 1.9 The SQL2GMS utility.

    1.4.6 Dates

    GAMS dates are one day off when importing from MS Access.

    Suppose we have an MS Access table with one single date column:

    
    datefield
    ----------
    3/12/2007 
    3/13/2007 10:00:00 AM 
    3/14/2007 8:30:00 PM
    
    We try to import this into GAMS as follows:
    
    $call =mdb2gms I="%system.fp%sample.mdb" Q="select datefield,Cdbl(datefield) from datetable" O=x.inc
    
    parameter p(*) /
    $include x.inc
    /
    ;
    display p;
    
    alias(*,i);
    parameter q(*,*);
    loop(i$p(i),
     q(i,'year') = gyear(p(i));
     q(i,'month') = gmonth(p(i));
     q(i,'day') = gday(p(i));
     q(i,'hour') = ghour(p(i));
     q(i,'minute') = gminute(p(i));
    );
    display q;
    
    Note that the Cdbl() function converts the date to a floating point number (double precision). The generated include file looks like:
    
    * -----------------------------------------------------
    * MDB2GMS Version 2.8, January 2007 
    * Erwin Kalvelagen, GAMS Development Corp 
    * ----------------------------------------------------- 
    * DAO version: 3.6 
    * Jet version: 4.0 
    * Database:    D:\mdb2gms\examples\sample.mdb 
    * Query:       select datefield,Cdbl(datefield) from datetable 
    * ----------------------------------------------------- 
    '3/12/2007' 39153 
    '3/13/2007 10:00:00 AM' 39154.4166666667 
    '3/14/2007 8:30:00 PM' 39155.8541666667 
    * -----------------------------------------------------
    
    which looks ok. However, when we look at the GAMS results in the listing file we see:
    
    ----     28 PARAMETER p  
    
    3/12/2007             39153.000,    3/13/2007 10:00:00 AM 39154.417,    3/14/2007 8:30:00 PM  39155.854
    
    
    ----     39 PARAMETER q  
    
                                year       month         day        hour      minute
    
    3/12/2007                2007.000       3.000      13.000
    3/13/2007 10:00:00 AM    2007.000       3.000      14.000      10.000
    3/14/2007 8:30:00 PM     2007.000       3.000      15.000      20.000      30.000
    
    Clearly the dates are off by one day: see the column "day". We can fix this probem in different places, e.g. in the query or in the GAMS model by subtracting 1.0 from an imported date. This problem occurs not only in MS Access but also with other software packages.

    1.5 Importing from DB2

    DB2 has an EXPORT command that can be used to generate comma delimited files. An example of a DB2 session that illustrates this is shown below:
    
    ------------------------------------- Command Entered -------------------------------------
    describe table db2admin.dist
     ;
    -------------------------------------------------------------------------------------------
    
    Column                         Type      Type
    name                           schema    name               Length   Scale Nulls
    ------------------------------ --------- ------------------ -------- ----- -----
    LOCA                           SYSIBM    VARCHAR                  10     0 No
    LOCB                           SYSIBM    VARCHAR                  10     0 No
    DISTANCE                       SYSIBM    DOUBLE                    8     0 Yes
    
      3 record(s) selected.
    
    
    
    ------------------------------------- Command Entered -------------------------------------
    select * from dist ;
    -------------------------------------------------------------------------------------------
    
    LOCA       LOCB       DISTANCE
    ---------- ---------- ------------------------
    seattle    new-york     +2.50000000000000E+000
    seattle    chicago      +1.70000000000000E+000
    seattle    topeka       +1.80000000000000E+000
    san-diego  new-york     +2.50000000000000E+000
    san-diego  chicago      +1.80000000000000E+000
    san-diego  topeka       +1.40000000000000E+000
    
      6 record(s) selected.
    
    
    
    ------------------------------------- Command Entered -------------------------------------
    export to c:\tmp\export.txt of del select * from dist ;
    -------------------------------------------------------------------------------------------
    SQL3104N  The Export utility is beginning to export data to file
    "c:\tmp\export.txt".
    
    SQL3105N  The Export utility has finished exporting "6" rows.
    
    
    Number of rows exported: 6
    
    The resulting data file export.txt will look like:
    
    "seattle","new-york",+2.50000000000000E+000
    "seattle","chicago",+1.70000000000000E+000
    "seattle","topeka",+1.80000000000000E+000
    "san-diego","new-york",+2.50000000000000E+000
    "san-diego","chicago",+1.80000000000000E+000
    "san-diego","topeka",+1.40000000000000E+000
    
    This file can be read easily:
    
    parameter d(i,j) 'distance in thousands of miles' /
    $ondelim
    $include export.txt
    $offdelim
    /;
    display d;
    

    1.6 Importing from MySQL

    MySQL can write the results of a SELECT statement to a file as follows:
    
    mysql> select * from dist;
    +-----------+----------+----------+
    | loca      | locb     | distance |
    +-----------+----------+----------+
    | seattle   | new-york |       50 |
    | seattle   | chicago  |      300 |
    | seattle   | topeka   |        0 |
    | san-diego | new-york |      275 |
    | san-diego | chicago  |        0 |
    | san-diego | topeka   |      275 |
    +-----------+----------+----------+
    6 rows in set (0.01 sec)
    
    mysql> select * from dist into outfile '/tmp/data.csv' 
        -> fields terminated by ','
        -> optionally enclosed by '"'
        -> lines terminated by '\n';
    Query OK, 6 rows affected (0.00 sec)
    
    The resulting CSV file looks like:
    
    "seattle","new-york",50
    "seattle","chicago",300
    "seattle","topeka",0
    "san-diego","new-york",275
    "san-diego","chicago",0
    "san-diego","topeka",275
    
    which can be read by GAMS directly. This approach can be automated as follows:
    
    [erwin@localhost erwin]$ cat myscript
    use test
    select * from dist into outfile '/tmp/data.csv' 
         fields terminated by ','
         optionally enclosed by '"'
         lines terminated by '\n';
    [erwin@localhost erwin]$ cat x.gms
    
    set i /seattle, san-diego/;
    set j /new-york, chicago, topeka/;
    
    $call 'mysql -u root < myscript'
    parameter dist(i,j) /
    $ondelim
    $include /tmp/data.csv
    $offdelim
    /;
    
    display dist; 
    
    [erwin@localhost erwin]$ gams x
    GAMS Rev 132  Copyright (C) 1987-2002 GAMS Development. All rights reserved
    Licensee: GAMS Development Corporation, Washington, DC   G871201:0000XX-XXX
              Free Demo,  202-342-0180,  sales@gams.com,  www.gams.com   DC9999
    --- Starting compilation
    --- x.gms(5) 1 Mb
    --- call mysql -u root < myscript
    --- .data.csv(6) 1 Mb
    --- x.gms(15) 1 Mb
    --- Starting execution
    --- x.gms(18) 1 Mb
    *** Status: Normal completion
    [erwin@localhost erwin]$
    
    The listing file shows that the table is read correctly:
    
       1
       2  set i /seattle, san-diego/;
       3  set j /new-york, chicago, topeka/;
       4
       6  parameter dist(i,j) /
    INCLUDE    /tmp/data.csv
       9  "seattle","new-york",50
      10  "seattle","chicago",300
      11  "seattle","topeka",0
      12  "san-diego","new-york",275
      13  "san-diego","chicago",0
      14  "san-diego","topeka",275
      16  /;
      17
      18  display dist;
      19
      20
      21
    
       SEQ   GLOBAL TYPE      PARENT   LOCAL  FILENAME
    
         1        1 INPUT          0       0  /home/erwin/x.gms
         2        5 CALL           1       5  mysql -u root < myscript
         3        8 INCLUDE        1       8  ./tmp/data.csv
    
    
    
    ----     18 PARAMETER dist
    
                 new-york     chicago      topeka
    
    seattle        50.000     300.000
    san-diego     275.000                 275.000
    
    Instead of maintaining the MySQL script in a separate file, it can also be written by GAMS using a statement like:
    
    file script /myscript/;
    putclose script
       "use test"/
       "select * from dist into outfile '/tmp/data.csv' "/
       "   fields terminated by ','"/
       "   optionally enclosed by '",'"',"'"/
       "   lines terminated by '\n';"/
    ;
    
    However, as we use $call which is a compile time statement, this would not work work (the $call would be executed before the put statement). The solution is to use instead :
    
    $onecho > myscript
    use test
    select * from dist into outfile '/tmp/data.csv' 
         fields terminated by ','
         optionally enclosed by '"'
         lines terminated by '\n';
    $offecho
    
    This will write the script at compile time.

    1.7 Importing from SQL Server

    SQL Server is Microsoft's flagship database. It comes in different flavors, including SQL Server, MSDE and SQL Server Express. A good way to import SQL server data into GAMS is using the SQL2GMS tool. Below is an example of its use:
    
    $set commandfile commands.txt
    $onecho > %commandfile%
    C=provider=sqloledb;data source=athlon\SQLExpress;Initial catalog=test;user id=sa;password=password
    O=C:\WINNT\gamsdir\xx.inc
    Q=SELECT * FROM x
    $offecho
    $call =sql2gms @%commandfile%
    parameter p(i,j) /
    $include "C:\WINNT\gamsdir\xx.inc"
    /;
    display p;
    

    To export SQL Server data to CSV files we can use the BCP utility.

    
    C:\Program Files\Microsoft SQL Server\90\Tools\binn>bcp test..results out x.csv -S athlon\sqlexpress -c -U sa -P password -t,
    
    Starting copy...
    
    6 rows copied.
    Network packet size (bytes): 4096
    Clock Time (ms.) Total     : 10     Average : (600.00 rows per sec.)
    
    C:\Program Files\Microsoft SQL Server\90\Tools\binn>type x.csv
    seattle,new-york,50.0
    seattle,chicago,300.0
    seattle,topeka,0.0
    san-diego,new-york,275.0
    san-diego,chicago,0.0
    san-diego,topeka,275.0
    
    It is somewhat more difficult to create a proper CSV file. A format specification file can help here. For an example see the next section on Sybase.

    Other tools to export files include DTS (Data Transformation Services) and linked ODBC data sources.

    Finally we can program directly an interface between SQL server tables and GAMS GDX files. A small example in C# can look like:

    
    gdxio = new csharpclient();
    //
    // read a set
    //
    gdxio.gdxdatawritestrstart(ap, "location", "from db", 1, csharpclient.dt_set, 0);
    String q = "select distinct(location) from exporttable";
    SqlCommand cmd = new SqlCommand(q, conn);
    SqlDataReader myReader = cmd.ExecuteReader();
    String[] astrelements = new String[10];
    for (int i = 0; i < 10; ++i)
        astrelements[i] = "";
    double[] avals = new double[5];
    while (myReader.Read())
    {
        astrelements[0] = myReader.GetString(0);
        avals[0] = 0.0;
        Boolean ok = gdxio.gdxdatawritestr(ap,astrelements,avals);
    }
    gdxio.gdxdatawritedone(ap);
    myReader.Close();
    
    //
    // read a data table
    //
    gdxio.gdxdatawritestrstart(ap, "data", "from db", 2, csharpclient.dt_par, 0);
    q = "select location, capacity, cost exporttable";
    cmd = new SqlCommand(q, conn);
    myReader = cmd.ExecuteReader();
    while (myReader.Read())
    {
        astrelements[0] = myReader.GetString(0);
        astrelements[1] = "capacity";
        avals[0] = myReader.GetInt32(1);
        Boolean ok = gdxio.gdxdatawritestr(ap, astrelements, avals);
    
        if (!myReader.IsDBNull(2)) {
            astrelements[1] = "cost";
            avals[0] = myReader.GetDouble(2);
            ok = gdxio.gdxdatawritestr(ap, astrelements, avals);
        }
    }
    gdxio.gdxdatawritedone(ap);
    myReader.Close();
    gdxio.gdxclose(ref ap);
    

    1.8 Importing from Sybase

    Sybase is largely the same as SQL Server. For exporting ascii files from a Sybase table, the utility bcp can be used, as discussed in the previous section.

    An example of use of this utility is shown below:

    
    [erwin@fedora sybase]$ isql -U sa -S LOCALHOST -D testdb -P sybase -J iso_1
    1> select * from results
    2> go
     loca       locb       shipment
     ---------- ---------- --------------------
     seattle    new-york              50.000000
     seattle    chicago              300.000000
     seattle    topeka                 0.000000
     san-diego  new-york             275.000000
     san-diego  chicago                0.000000
     san-diego  topeka               275.000000
     
    (6 rows affected)
    1> quit
    [erwin@fedora sybase]$ cat bcp.fmt
    10.0
    4
    1       SYBCHAR 0       0       "\""    1       loca
    2       SYBCHAR 0       10      "\",\"" 1       loca
    3       SYBCHAR 0       10      "\","   2       locb
    4       SYBCHAR 0       17      "\n"    3       shipment
    [erwin@fedora sybase]$ bcp testdb..results out res.txt -S LOCALHOST  -U sa -P sybase -J iso_1 -f bcp.fmt
     
    Starting copy...
     
    6 rows copied.
    Clock Time (ms.): total = 1  Avg = 0 (6000.00 rows per sec.)
    [erwin@fedora sybase]$ cat res.txt
    "seattle","new-york",50.0
    "seattle","chicago",300.0
    "seattle","topeka",0.0
    "san-diego","new-york",275.0
    "san-diego","chicago",0.0
    "san-diego","topeka",275.0
    [erwin@fedora sybase]$
    
    Note: the first column in the format file is a dummy (it has length 0). This is in order to write the leading quote, as bcp only allows for termination symbols.

    This can be automated using the following GAMS code:

    
    sets
      i   'canning plants'   / seattle, san-diego /
      j   'markets'          / new-york, chicago, topeka / ;
    
    
    $onecho > bcp.fmt
    10.0
    4
    1       SYBCHAR 0       0       "\""    1       loca
    2       SYBCHAR 0       10      "\",\"" 1       loca
    3       SYBCHAR 0       10      "\","   2       locb
    4       SYBCHAR 0       17      "\n"    3       shipment
    $offecho
    $call "bcp testdb..results out res.txt -S LOCALHOST  -U sa -P sybase -J iso_1 -f bcp.fmt"
    parameter d(i,j)  'distance in thousands of miles'
    /
    $ondelim
    $include res.txt
    $offdelim
    /;
    display d;
    
    Running this model will look like:
    
    [erwin@fedora sybase]$ gams trnsport_sybase
    --- Starting compilation
    --- trnsport_sybase.gms(14) 3 Mb
    --- call bcp testdb..results out res.txt -S LOCALHOST  -U sa -P sybase -J iso_1 -f bcp.fmt
     
    Starting copy...
     
    6 rows copied.
    Clock Time (ms.): total = 1  Avg = 0 (6000.00 rows per sec.)
    --- .res.txt(6) 3 Mb
    --- trnsport_sybase.gms(22) 3 Mb
    --- Starting execution
    --- trnsport_sybase.gms(27) 4 Mb
    *** Status: Normal completion
    [erwin@fedora sybase]$
    

    1.9 The SQL2GMS utility

    The SQL2GMS utility uses ADO or ActiveX Data Objects to extract data from relational databases. It can connect to almost any database from any vendor as it supports standards like ODBC.

    ADO is "Microsoft's strategic, high-level interface to all kinds of data" (http://www.microsoft.com/data/ado/default.htm). ADO can be downloaded as part of MDAC (Microsoft Data Access Components) at http://www.microsoft.com/data/download.htm.

    When running SQL2GMS utility without command line parameters, the following window will appear:

    The output file is specified in the first edit line. This is the file that will contain the results and can be included in your GAMS model. The Browse button allows you to navigate around on your hard disks.

    The connection string specifies the database to connect to and the protocol to use. The following table gives some examples:
    databaseconnection string
    ODBC
    ODBC data sourceMyDSN
    ODBC DSN with userid and passwordDSN=xxx;UID=yyy;PWD=zzz;
    ODBC File DSNFILEDSN=d:\ppp\fff.dsn;UID=yyy;PWD=zzz;
    ODBC DSN-less Text DriverDriver={Microsoft Text Driver (*.txt; *.csv)}; Dbq=d:\ppp\;Extensions=asc,csv,tab,txt;Persist Security Info=False

    (Note: the filename is used in the FROM clause in the query string.)

    ODBC DSN-less MS Access DriverDriver={Microsoft Access Driver (*.mdb)}; Dbq=d:\ppp\fff.mdb;Uid=yyy;Pwd=zzz;
    ODBC DSN-less driver for MS SQL ServerDriver={SQL Server};Server=sss;Database=ddd;Uid= yyy;Pwd=zzz;
    ODBC Driver for OracleDriver={Microsoft ODBC for Oracle}; Server=sss; Uid=yyy ; Pwd=zzz
    ODBC Driver for Oracle (old)Driver={Microsoft ODBC Driver for Oracle}; ConnectString=sss ; Uid=yyy; Pwd=zzz;
    OLEDB
    OLE DB Data link fileFile name=d:\ppp\fff.udl;
    OLE DB Provider for ODBC Access (Jet)Provider =MSDASQL; Driver={Microsoft Access Driver (*.mdb)};Dbq= d:\ppp\fff.mdb; Uid=yyy; Pwd=zzz;
    OLE DB Provider for ODBC SQL ServerProvider=MSDASQL; Driver={SQL Server}; Server=sss; Database= ddd; Uid=yyy; Pwd=zzz;
    OLE DB Provider for Microsoft Jet (Access)Provider=Microsoft.Jet.OLEDB.4.0; Data Source=d:\ppp\fff.mdb; User Id=yyy; Password=zzz;
    OLE DB Provider for Microsoft Jet (Access) with System DatabaseProvider=Microsoft.Jet.OLEDB.4.0; Data Source=d:\ppp\fff.mdb; Jet OLEDB:System Database=fff.mdw;

    Specify user id and password in the U=xxx and P=zzz options. If MDB file has a password add: Jet OLEDB:Database Password= xxx;.

    OLE DB Provider for SQL ServerProvider=sqloledb; Network Library=DBMSSOCN; Data Source=ddd ; Initial Catalog=ccc; User Id=yyy; Password=zzz;
    OLE DB Provider for SQL Server with trusted connection securityProvider=sqloledb; Network Library=DBMSSOCN; Data Source=ddd; Initial Catalog=ccc; Trusted_Connection=yes;
    MS Remote
    MS Remote - Access (Jet) through ODBC DSNRemote Server=http://xxx; Remote Provider=MSDASQL; DSN= nnn; Uid=yyy; Pwd=zzz;
    MS Remote - Access (Jet) through OLE DB ProviderProvider=MS Remote; Remote Server=http://xxx; Remote Provider=Microsoft.Jet.OLEDB.4.0; Data Source=d:\ppp\fff.mdb; Uid=yyy; Pwd=zzz;
    MS Remote - Access (Jet) through OLE DB Provider with an RDS Datafactory Custom HandlerProvider=MS Remote; Remote Server=http://xxx; Handler=MSDFMAP.Handler; Data Source=MyConnectTag

    The entry in \winnt\Msdfmap.ini is:
    [connect MyConnectTag]
    Access=ReadWrite
    Connect="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=xxx.mdb; User Id=yyy; Password=zzz;"

    MS Remote - SQL Server using ODBC DSNRemote Server=http://xxx; Remote Provider=MSDASQL; Network Library=DBMSSOCN; DSN=nnn; Uid=yyy; Pwd=zzz;
    MS Remote - SQL Server using OLE DB ProviderProvider=MS Remote; Remote Server=http://xxx; Remote Provider=SQLOLEDB; Network Library=DBMSSOCN; Data Source=nnn; Initial Catalog=ddd; User Id=yyy; Password=zzz;
    MS Remote - SQL Server through OLE DB Provider with an RDS Datafactory Custom HandlerProvider=MS Remote; Remote Server=http://xxx; Handler=MSDFMAP.Handler; Data Source=MyConnectTag

    The entry in \winnt\Msdfmap.ini is:
    [connect MyConnectTag]
    Access=ReadWrite
    Connect="Provider=SQLOLEDB; Network Library=DBMSSOCN; Data Source=nnn; Initial Catalog=ddd; User Id=yyy; Password=zzz;"

    For more information consult your local database guru and see http://www.able-consulting.com/ADO_Conn.htm, and http://www.able-consulting.com/ADO_Faq.htm.

    ODBC can be used to access a number of databases such as Oracle, SQL Server, MS Data Engine, etc. Consult your database documentation on information how to connect to your database. In some cases, database client software needs to be installed in addition to the ODBC driver. E.g. the Oracle8 ODBC driver uses OCI (Oracle Call Interface) and Net8 software. Therefore in case of Oracle, make sure the underlying protocols (SQL*Net) work properly before debugging the ODBC connection. The ODBC Source Administrator allows logging ODBC traffic to a file. This can be used to debug the connection.

    There are a few special options:

    After setting the desired options, the OK button can be pressed to actually perform the translation.

    The utility can also be used in batch mode. I.e. if you specify from the command line:

    
    sql2gms C="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\My Documents\test.mdb;" O=test.inc Q="select * from data"
    
    then the utility will perform the translation without user intervention. Notice that command line parameters that contain blanks are protected by surrounding them with quotes. This command line mode can also be used from within a GAMS model.

    The example used in paragraph 1.4.2 is trivial to adapt for SQL2GMS:

    
    set y 'years' /1997*1998/;
    set loc 'locations' /nyc,was,la,sfo/;
    set prd 'products' /hardware, software/;
    
    parameter sales(prd,loc,y) /
    $call =sql2gms C="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\My Documents\test.mdb" Q="select prod,loc,year,sales from data" O=sales.inc
    $include sales.inc
    /;
    display sales;
    
    parameter profit(prd,loc,y) /
    $call =sql2gms C="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\My Documents\test.mdb" Q="select prod,loc,year,profit from data" O=profit.inc
    $include profit.inc
    /;
    display profit;
    
    Database error messages are written to the output file using the $error construct, so that a compilation error will occur. As an example consider the call:
    
    $call =sql2gms c="DRIVER={SQL Server};SERVER=VANBUREN;UID=xxx;PWD=yyy;DATABASE=adp1SQL" q="select * from table1" B O=x.inc
    $include x.inc
    
    As this is an illegal database login, we will see:
    
    GAMS Rev 116  Copyright (C) 1987-2000 GAMS Development. All rights reserved
    Licensee: harrison                                       G990810:0928CE-WIN
              GAMS Development Corporation                               DC1556
    --- Starting compilation
    --- .X.INC(6) 1 Mb 1 Error
    *** Error 333 in D:\TMP\X.INC
        Error triggered by message above
    --- .X.INC(6) 1 Mb
    --- X.GMS(5) 1 Mb 1 Error
    *** Status: Compilation error(s)
    Exit code = 2
    
    The error message is not very helpful, but error 333 is caused by seeing a $error construct. This is caused by the include file:
    
    * -----------------------------------------------------
    * SQL2GMS Version 1.2, September 2000
    * Erwin Kalvelagen, GAMS Development Corp
    * -----------------------------------------------------
    * ADO version: 2.1
    $error [Microsoft][ODBC SQL Server Driver][SQL Server]Login failed for user 'xxx'
    
    The listing file will properly report this:
    
       1
    INCLUDE    D:\TMP\X.INC
       4  * -----------------------------------------------------
       5  * SQL2GMS Version 1.2, September 2000
       6  * Erwin Kalvelagen, GAMS Development Corp
       7  * -----------------------------------------------------
       8  * ADO version: 2.1
       9  $error [Microsoft][ODBC SQL Server Driver][SQL Server]Login failed for user 'xxx'
    ****       $333
    **** LINE      6 IN FILE D:\TMP\X.INC
      10
      11
    
    In the $call statement the utility is called with the correct parameters. The '=' sign is needed to tell GAMS to bypass the command processor (e.g. command.com). This is needed to make sure that the utility is finished before GAMS starts to execute the $include command.

    If the '=' is absent first a shell (Unix) or command.com (Windows) is loaded, and subsequently this command processor will load the program. This extra step is only needed when executing for instance batch files, but is just a waste of resources otherwise. In our case it is even required to run directory as Window's programs running under a command processor are running detached: the command processor will terminate, giving control back to GAMS while the import filter is not finished yet. This will cause GAMS to read output files, which are not ready yet. If the program is run directly, GAMS will wait with reading the file until the import filter has properly terminated. Another problem when running a program via command.com is he limited command line length (128 characters). I.e. the '=' is an ugly but necessary detail.

    Note: for illustrative purposes we also show you another way of doing this:
    
    $call start /w d:\util\sql2gms c="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=d:\import\test\test.mdb" o=d:\tmp\test.in q="select * from mytable"
    
    which uses the Windows start command to make sure sql2gms finishes before GAMS proceeds.
    Note 2: The original design by the author introduced a new dollar control option: $import which would combine the $call and the $include constructs. A prototype has been implemented that allowed the user to say:
    
    $import sql2gms c="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=d:\import\test\test.mdb" q="select * from mytable"
    
    instead of
    
    $call =d:\utils\sql2gms c="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=d:\import\test\test.mdb" o=d:\tmp\x.inc q="select * from mytable"
    $include d:\tmp\x.inc
    
    Unfortunately this feature never made it into the production version of GAMS.
    We use command line parameters to pass on options to the import filter program. This will cause long command lines. The current version of GAMS does not allow command lines longer than 255 characters. When specifying many long parameters, you may run out of space. To prevent long command lines we allow the command line parameters to be stored in a separate text file. The name of this text file can then be passed on as a command line parameter by prefixing it with an @ sign:
    
    @filename
    
    An example:
    
    set i /
    $call =sql2gms @"C:\My Documents\options.txt" $include "c:\my documents\data.inc" /;
    where options.txt contains the text:
    C=Provider=Microsoft.Jet.OLEDB.4.0;Data Source=d:\import\test\test.mdb
    Q=select * from mytable
    O=C:\my documents\data.inc
    
    Each option should be on its own line. File names containing blanks don't need quotes, but if they are present they are filtered out. It is possible to have GAMS write the command file as follows:
    
    $set cmdfile "c:\windows\temp\commands.txt"
    $echo "C=DSN=sample"              >  "%cmdfile%"
    $echo "O=E:\models\labor.INC"     >> "%cmdfile%"
    $echo "Q=select * from labor"     >> "%cmdfile%"
    $call ="d:\win9x program files\gams21.2\sql2gms.exe" @"%cmdfile%"
    
    parameter p /
    $include "E:\models\labor.INC"
    /;
    display p;
    
    Newer versions of GAMS allow for:
    
    $set cmdfile "c:\windows\temp\commands.txt"
    $onecho  >  "%cmdfile%"
    C=DSN=sample 
    O=E:\models\labor.INC
    Q=select * from labor
    $offecho
    $call ="d:\win9x program files\gams21.2\sql2gms.exe" @"%cmdfile%"
    
    parameter p /
    $include "E:\models\labor.INC"
    /;
    display p;
    

    Version 1.3 of SQL2GMS allows to write data to a GDX file instead of or in addition to a GAMS include file. GDX files are explained in in section section 1.29. The command line parameter is X=gdxfile.gdx.

    The following command line options are available for sql2gms:
    OptionDescription
    C=connectionstringThis option is required and specifies to which database ADO should connect to. The following are some examples of connection strings:
    C="MyDSN"
    C="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\My Documents\test.mdb;"
    C="DRIVER={SQL Server};SERVER=VANBUREN;DATABASE=adp1SQL"
    C="driver={SQL Server}; server=VANBUREN; database=erwindb; UID=erwin; PWD=mypassword; "
    C="driver={Oracle ODBC Driver};database=erwindb;UID=system;PWD=manager;"
    
    O=outputfileThis option specifies the name of the output file. Make sure the directory is writeable. UNC names can be used. This is a required option.
    Q=queryThis option can be used to specify an SQL query. Queries contain spaces and thus have to be surrounded by double quotes. For the exact syntax of the queries that is accepted by Access we refer to the documentation that comes with MS Access. One notable syntax feature is that when field names or table names contain blanks, they can be specified in square brackets. Examples:
    Q="select * from mytable"
    Q="select year, production from [production table]"
    Q="select [GAMS City],value from [example table],CityMapper where [Access City]=city"
    
    For an example of calling a stored procedure see section 1.9.5 SQL2GMS timeouts
    U=usernameIf not specified in the connection string this can be used to provide a database user name. Example:
    U="system"
    .
    P=passwordIf not specified in the connection string this can be used to provide a database password. Example:
    P="manager"
    .
    DDebug. This option can be used for debugging purposes. If specified the import filter will no run minimized but "restored", i.e. as a normal window. In addition the program will not terminate until the user clicks the Close button. This allows you to monitor possible errors during execution of mdb2gms.
    BIf this parameter is specified, strings that have blanks in them will be quoted. If the string is already quoted this step is not performed. If the name contains an embedded single quote, the surrounding quotes will be double quotes. If the name already contains a double quote, the surrounding quotes will be single quotes. If both single and double quotes are present in the string, then all double quotes are replaced by single quotes and the surrounding quotes will be double quotes. By default this option is turned off.
    MRun in modest or mute mode: no additional information, such as version number etc. is written to the listing file.
    LEmbed the data in $offlisting, $onlisting. A quick way to reduce the size of the listing file.
    @filenameCauses the program to read options from a file. If the file name contains blanks, it can be surrounded by double quotes. The option file contains one option per line, in the same syntax as if it were specified on the command line.
    X=GDXfilenameWrites results to the specified GDX file. For more information on GDX files see section GDXViewer. This option is new in version 1.3.

    Notes

    1.9.1 Reading DBASE Files

    The SQL2GMS utility can be used to read DBASE files. DBASE tables are stored in a *.DBF file. The approach would be:
    
    Q=select columns from dbf_file_name
    C=DRIVER=Microsoft dBase Driver (*.dbf);dbq=directory_of_dbf_file_name
    
    A complete model to read a large TABLE02.DBF file would be:
    
    $ontext
    
       Read DBASE table:
    
        Table 2. Population by sex, residence, and intercensal rates of increase
                 for total population, each census: 1948-1997
    
       Source:
          United Nations - Demographic Yearbook, Historical supplement. New York, 1999
    
    $offtext
    
    set country / 
    102005 "Algeria"
    103005 "Angola"
    106305 "Benin"
    107405 "Botswana"
    109605 "Burkina Faso"
    110405 "Burundi"
    110805 "Cameroon"
    112005 "Cape Verde"
    112405 "Central African Republic"
    113005 "Chad"
    115405 "Comoros"
    116105 "Congo"
    116905 "Côte d'Ivoire"
    118005 "Democratic Republic of the Congo"
    118205 "Djibouti"
    119205 "Egypt"
    120405 "Equatorial Guinea"
    120505 "Eritrea"
    120805 "Ethiopia"
    121005 "Former Ethiopia"
    126005 "Gabon"
    126405 "Gambia"
    127805 "Ghana"
    130405 "Guinea"
    130605 "Guinea-Bissau"
    138805 "Kenya"
    142405 "Lesotho"
    143405 "Liberia"
    143805 "Libyan Arab Jamahiriya"
    145405 "Madagascar"
    145605 "Malawi"
    147805 "Mali"
    148805 "Mauritania"
    149005 "Mauritius"
    149015 "Mauritius, Island of Mauritius"
    149025 "Mauritius, Rodrigues"
    149035 "Mauritius, Others"
    151005 "Morocco"
    151405 "Mozambique"
    152005 "Namibia"
    156205 "Niger"
    156605 "Nigeria"
    164405 "Réunion"
    165205 "Rwanda"
    165715 "Saint Helena ex. dep."
    165725 "Saint Helena: Ascension"
    165735 "Saint Helena: Tristan da Cunha"
    166805 "Sao Tome and Principe"
    167605 "Senegal"
    168005 "Seychelles"
    168805 "Sierra Leone"
    169605 "Somalia"
    170005 "South Africa"
    173105 "Sudan"
    174005 "Swaziland"
    176405 "Togo"
    178405 "Tunisia"
    179405 "Uganda"
    185505 "United Republic of Tanzania"
    185515 "United Republic of Tanzania: Tanganyika"
    185525 "United Republic of Tanzania: Zanzibar"
    190205 "Western Sahara"
    192805 "Zambia"
    193805 "Zimbabwe"
    202905 "Anguilla"
    203105 "Antigua and Barbuda"
    203705 "Aruba"
    204805 "Bahamas"
    205405 "Barbados"
    206105 "Belize"
    206205 "Bermuda"
    208805 "British Virgin Islands"
    211605 "Canada"
    212205 "Cayman Islands"
    216805 "Costa Rica"
    217005 "Cuba"
    218505 "Dominica"
    218805 "Dominican Republic"
    220005 "El Salvador"
    229005 "Greenland"
    229105 "Grenada"
    229405 "Guadeloupe"
    230005 "Guatemala"
    231205 "Haiti"
    232005 "Honduras"
    237405 "Jamaica"
    248005 "Martinique"
    249605 "Mexico"
    250705 "Montserrat"
    253305 "Netherlands Antilles"
    255805 "Nicaragua"
    259405 "Panama"
    259605 "Panama: Former Canal Zone"
    263905 "Puerto Rico"
    266205 "Saint Kitts-Nevis"
    266305 "Saint Lucia"
    266405 "Saint Pierre and Miquelon"
    266505 "Saint Vincent and the Grenadines"
    277405 "Trinidad and Tobago"
    279105 "Turks and Caicos Islands"
    286005 "United States"
    286405 "United States Virgin Islands"
    303405 "Argentina"
    306805 "Bolivia"
    307805 "Brazil"
    313405 "Chile"
    315005 "Colombia"
    319405 "Ecuador"
    322405 "Falkland Islands (Malvinas)"
    324005 "French Guiana"
    330805 "Guyana"
    360405 "Paraguay"
    360805 "Peru"
    373405 "Suriname"
    387405 "Uruguay"
    387805 "Venezuela"
    401405 "Afghanistan"
    403605 "Armenia"
    404605 "Azerbaijan"
    405005 "Bahrain"
    405205 "Bangladesh"
    406405 "Bhutan"
    409205 "Brunei Darussalam"
    410705 "Cambodia"
    413805 "China"
    413905 "China: Hong Kong SAR"
    417405 "Cyprus"
    419005 "East Timor"
    426305 "Georgia"
    434005 "India"
    434405 "Indonesia"
    435005 "Iran (Islamic Republic of)"
    435405 "Iraq"
    436205 "Israel"
    437805 "Japan"
    438405 "Jordan"
    438505 "Kazakhstan"
    439005 "Korea (Dem. People's Republic of)"
    439405 "Korea (Republic of)"
    439805 "Kuwait"
    440005 "Kyrgyzstan"
    440205 "Lao People's Democratic Republic"
    441205 "Lebanon"
    445005 "Macau"
    445805 "Malaysia"
    445825 "Malaysia: Peninsular Malaysia"
    445835 "Malaysia: Sabah"
    445845 "Malaysia: Sarawak"
    447405 "Maldives"
    450605 "Mongolia"
    451605 "Myanmar"
    452605 "Nepal"
    458605 "Oman"
    459005 "Pakistan"
    461205 "Philippines"
    464005 "Qatar"
    467205 "Saudi Arabia"
    469405 "Singapore"
    472905 "Sri Lanka"
    475205 "Syrian Arab Republic"
    475605 "Tajikistan"
    476005 "Thailand"
    478805 "Turkey"
    478905 "Turkmenistan"
    483005 "United Arab Emirates"
    487305 "Uzbekistan"
    487905 "Viet Nam"
    488105 "West Bank and Gaza Strip"
    491905 "Yemen"
    492005 "Yemen: Former Democratic Yemen"
    492105 "Yemen: Former Yemen Arab Republic"
    501805 "Albania"
    502805 "Andorra"
    504405 "Austria"
    505805 "Belarus"
    506005 "Belgium"
    507105 "Bosnia and Herzegovina"
    509405 "Bulgaria"
    513205 "Channel Islands"
    513215 "Channel Islands: Guernsey"
    513225 "Jersey"
    517105 "Croatia"
    517805 "Former Czechoslovakia"
    517905 "Czech Republic"
    518405 "Denmark"
    520705 "Estonia"
    522005 "Faeroe Islands"
    523405 "Finland"
    523805 "France"
    526805 "Germany: Federal Republic of Germany"
    526905 "Germany: Former German Democratic Republic"
    528005 "Gibraltar"
    528805 "Greece"
    531605 "Holy See"
    532805 "Hungary"
    533205 "Iceland"
    535805 "Ireland"
    536005 "Isle of Man"
    536605 "Italy"
    540705 "Latvia"
    544205 "Liechtenstein"
    544405 "Lithuania"
    544605 "Luxembourg"
    547905 "Malta"
    550205 "Monaco"
    553005 "Netherlands"
    558405 "Norway"
    562005 "Poland"
    562405 "Portugal"
    564105 "Republic of Moldova"
    564805 "Romania"
    565005 "Russian Federation"
    566605 "San Marino"
    569305 "Slovakia"
    569505 "Slovenia"
    571605 "Spain"
    573805 "Svalbard and Jan Mayen Islands"
    574405 "Sweden"
    574805 "Switzerland"
    576205 "The Former Yugoslav Rep. of Macedonia"
    579805 "Ukraine"
    584005 "United Kingdom"
    584015 "United Kingdom: England and Wales"
    584025 "United Kingdom: Northern Ireland"
    584035 "United Kingdom: Scotland"
    592405 "Former Yugoslavia"
    592505 "Yugoslavia"
    602405 "American Samoa"
    604205 "Australia"
    614405 "Christmas Islands"
    614805 "Cocos (Keeling) Islands"
    616405 "Cook Islands"
    623005 "Fiji"
    624405 "French Polynesia"
    629805 "Guam"
    638705 "Kiribati"
    648105 "Marshall Islands"
    649805 "Micronesia"
    652205 "Nauru"
    654205 "New Caledonia"
    655405 "New Zealand"
    658005 "Niue"
    658205 "Norfolk Island"
    658305 "Northern Mariana Islands"
    659105 "Palau"
    660205 "Papua New Guinea"
    661605 "Pitcairn"
    667005 "Samoa"
    670205 "Solomon Islands"
    676805 "Tokelau"
    677005 "Tonga"
    679005 "Tuvalu"
    687505 "Vanuatu"
    690005 "Wallis and Futuna Islands"
    780005 "Former USSR" 
    /;
    
    set reliability / 
     0 "Final figure, complete"
     1 "Provisional figure"
     2 "Final figure, incomplete/questionable reliability"
     3 "Provisional figure with questionable reliability"
     4 "No information available on reliability"
     5 "United Nations Population Division estimates"
     6 "Other estimates" 
    /;
    
    set vardef 'this is used to define the data record' / 
     1 "Enumerated population: Total"
     2 "Enumerated population: Male"
     3 "Enumerated population: Female"
     4 "Urban population: Number"
     5 "Urban population: Per cent"
     6 "Rural population: Number"
     7 "Rural population: Per cent"
     8 "Annual rate of increase (%)" 
    /;
    
    set year /1948*1998/;
    set day /0,1*31/;
    set month /0,1*12/;
    
    set rectype / 
     1 "Census, complete tabulation: de facto"
     2 "Census, sample tabulation: de facto"
     3 "Census, complete tabulation: de jure"
     4 "Census, sample tabulation: de jure"
     5 "Sample survey: de facto"
     6 "Sample survey: de jure"
     7 "Estimate: de facto"
     8 "Estimate: de jure" 
    /;
    
    $onecho > table02.cmd
    q=select country,year,month,day,variable,rectype,datum from table02
    c=DRIVER=Microsoft dBase Driver (*.dbf);dbq=%system.fp%
    o=table02.inc
    $offecho
    $call =sql2gms @table02.cmd
    
    parameter population(country,year,month,day,vardef,rectype) /
    $include table02.inc
    /;
    display population;
    
    Here the TABLE02.DBF file is stored in the same directory as where the .GMS file is located, hence the use of the SYSTEM.FP macro. The log looks like:
    
    GAMS Rev 142  Copyright (C) 1987-2005 GAMS Development. All rights reserved
    Licensee: Erwin Kalvelagen                               G031217:2011CE-WIN
              GAMS Development Corporation                               DC1556
    --- Starting compilation
    --- dbase.gms(312) 3 Mb
    --- call =sql2gms @table02.cmd
    ADO version: 2.8
    Query: select country,year,month,day,variable,rectype,datum from table02
    Number of rows: 5980
    Elapsed time: 0.23 seconds
    Done
    --- .table02.inc(5990) 3 Mb
    --- dbase.gms(317) 3 Mb
    --- Starting execution
    --- dbase.gms(6307) 4 Mb
    *** Status: Normal completion
    
    Note: writing dbase,xbase or foxpro files can be done with the tool GDX2DBF.

    1.9.1 SQL2GMS advanced use

    It is possible to generate a GDX file from a query in versions 1.3 and later. The user interface has a new edit line to specify the GDX output file.

    Writing to the GDX file is also supported through the command line using the X=gdxfilename command line parameter.

    As there is significant overhead in connecting to the database, a facility has been added to execute multiple queries in one call. For example:

    
    $ontext
    
      Example database access with SQL2GMS (ODBC Driver)
    
      Multiple queries in one call
    
    $offtext
    
    $onecho > cmd.txt
    C=DRIVER=Microsoft Access Driver (*.mdb);dbq=%system.fp%sample.mdb
    
    Q1=select distinct(year) from data
    O1=year.inc
    
    Q2=select distinct(loc) from data
    O2=loc.inc
    
    Q3=select distinct(prod) from data
    O3=prod.inc
    
    Q4=select prod,loc,year,sales from data
    O4=sales.inc
    
    Q5=select prod,loc,year,profit from data
    O5=profit.inc
    $offecho
    
    $call =sql2gms @cmd.txt
    
    set y 'years' /
    $include year.inc
    /;
    set loc 'locations' /
    $include loc.inc
    /;
    set prd 'products' /
    $include prod.inc
    /;
    
    parameter sales(prd,loc,y) /
    $include sales.inc
    /;
    display sales;
    
    parameter profit(prd,loc,y) /
    $include profit.inc
    /;
    display profit;
    
    Notice that Qn is matched by On. It is also possible to write directly to a GDX file:
    
    $ontext
    
      Example database access with SQL2GMS (OLEDB Driver)
    
      Multiple queries in one call, store in GDX file
    
    $offtext
    
    $onecho > cmd.txt
    C=Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%system.fp%sample.mdb
    X=sample.gdx
    
    Q1=select distinct(year) from data
    s1=year
    
    Q2=select distinct(loc) from data
    s2=loc
    
    Q3=select distinct(prod) from data
    s3=prd
    
    Q4=select prod,loc,year,sales from data
    A4=sales
    
    Q5=select prod,loc,year,profit from data
    A5=profit
    $offecho
    
    $call =sql2gms @cmd.txt
    
    $call =shellExecute gdxviewer sample.gdx
    
    set y 'years';
    set loc 'locations';
    set prd 'products';
    parameter sales(prd,loc,y);
    parameter profit(prd,loc,y);
    
    $gdxin 'sample.gdx'
    $load y=year loc prd sales profit
    
    display sales;
    display profit;
    
    Here a query Qn is matched either by a set name Sn or a parameter name An. The log should look like:
    
    GAMS Rev 142  Copyright (C) 1987-2005 GAMS Development. All rights reserved
    Licensee: Erwin Kalvelagen                               G031217:2011CE-WIN
              GAMS Development Corporation                               DC1556
    --- Starting compilation
    --- salesprofitdb10.gms(29) 2 Mb
    --- call =sql2gms @cmd.txt
    GDXIO.DLL version:_GAMS_GDX_233_2005-03-03
    ADO version: 2.8
    Query: select distinct(year) from data
    GDX id: year (Set)
    Number of rows: 2
    Elapsed time: 0.02 seconds
    Done
    Query: select distinct(loc) from data
    GDX id: loc (Set)
    Number of rows: 4
    Elapsed time: 0.00 seconds
    Done
    Query: select distinct(prod) from data
    GDX id: prd (Set)
    Number of rows: 2
    Elapsed time: 0.00 seconds
    Done
    Query: select prod,loc,year,sales from data
    GDX id: sales (Parameter)
    Number of rows: 16
    Elapsed time: 0.02 seconds
    Done
    Query: select prod,loc,year,profit from data
    GDX id: profit (Parameter)
    Number of rows: 16
    Elapsed time: 0.00 seconds
    Done
    --- salesprofitdb10.gms(31) 2 Mb
    --- call =shellExecute gdxviewer sample.gdx
    ShellExecute Version 1.0
    --- salesprofitdb10.gms(39) 2 Mb
    --- GDXin=C:\gams projects\wtools\ver002\examples\sample.gdx
    --- salesprofitdb10.gms(44) 3 Mb
    --- Starting execution
    --- salesprofitdb10.gms(44) 4 Mb
    *** Status: Normal completion
    

    1.9.3 Download SQL2GMS

    SQL2GMS is now part of the WTOOLS package. PDF documentation is here: sql2gms.pdf.

    1.9.4. SQL2GMS script

    The following GAMS code will generate and execute a script written in VBScript. It mimics the behavior of SQL2GMS.EXE and can be used for debugging or the script can be passed on to the IT support people in case there are problems with accessing the database.
    
    $ontext
    
       This script mimics SQL2GMS.
    
       Erwin Kalvelagen
       November 2006
    
    $offtext
    
    $onecho > sql2gms.vbs
    '
    ' parameters
    '
    t1 = 3                    ' connection timeout
    t2 = 0                    ' command timeout
    c = "Provider=MSDASQL;Driver={SQL Server};Server=DUOLAP\SQLEXPRESS;Database=testdata;Uid=gams;Pwd=gams;"  ' connection string
    q = "select * from data"  ' query
    o = "output.inc"          ' the output file to be generated
    b = false                 ' whether to quote indices (e.g. because of embedded blanks)
    
    '
    ' create ADO connection object
    '
    set ADOConnection = CreateObject("ADODB.Connection")
    ADOVersion = ADOConnection.Version
    WScript.Echo "ADO Version:",ADOVersion
    
    '
    ' make db connection
    '
    ADOConnection.ConnectionTimeout = t1
    ADOConnection.ConnectionString = c
    ADOConnection.Open
    
    '
    ' Open file
    '
    set fso = CreateObject("Scripting.FileSystemObject")
    set outputfile = fso.CreateTextFile(o,True)
    outputfile.writeLine "*----------------------------------------------------"
    outputfile.writeLine "*  SQL2GMS/Vbscript 1.0"
    outputfile.writeLine "*  Connection:"&c
    outputfile.writeLine "*  Query:"&q
    outputfile.writeLine "*----------------------------------------------------"
    
    '
    ' setup query
    '
    starttime = time
    ADOConnection.CommandTimeout = t2
    const adCmdText = 1
    set RecordSet = ADOConnection.Execute(q,,adCmdText)
    
    '
    ' get results
    '
    NumberOfFields = RecordSet.Fields.Count
    eof = RecordSet.EOF
    if eof then
       WScript.Echo "No records"
       Wscript.quit
    end if
    
    '
    '  loop through records
    '
    NumberOfRows = 0
    do until eof
       NumberOfRows = NumberOfRows + 1
       Row = RecordSet.GetRows(1)
       if NumberOfFields > 1 then
          s = Row(0,0)
          if b then
            s = quotestring(s)
          end if
          Outputfile.Write s
       end if
    
       for i=2 to NumberOfFields-1
           s = Row(i-1,0)
           if b then
             s = quotestring(s)
           end if
           Outputfile.Write "."
           Outputfile.Write s
       next
    
       s = Row(NumberOfFields-1,0)
       OutputFile.Write " "
       OutputFile.Writeline s
    
       eof = RecordSet.EOF
    loop
    
    OutputFile.Close
    
    Wscript.echo "Records read:"&NumberOfRows
    Wscript.echo "Elapsed time:"&DateDiff("s",starttime,time)&" seconds."
    
    
    function quotestring(s)
    has_single_quotes = false
    has_double_quotes = false
    needs_quoting = false
    
    '
    ' check input string for special characters
    '
    for j=1 to len(s)
       ch = Mid(s,j,1)
       select case ch
         case "'"
             has_single_quotes = true
         case """"
             has_double_quotes = true
         case " ","/",";",","
             needs_quoting = true
         case else
             k = asc(ch)
             if (k<=31) or (k>=127) then
                needs_quoting = true
             end if
       end select
    next
    
    '
    ' check if we have if gams keyword
    '
    kw = array("ABORT","ACRONYM","ACRONYMS","ALIAS","BINARY","DISPLAY","ELSE", _
                "EQUATION","EQUATIONS","EXECUTE","FILE","FILES","FOR","FREE",  _
                "IF","INTEGER","LOOP","MODEL","MODELS","NEGATIVE","OPTION",    _
                "OPTIONS","PARAMETER","PARAMETERS","POSITIVE","PROCEDURE",     _
                "PROCEDURES","PUT","PUTCLEAR","PUTCLOSE","PUTHD","PUTPAGE",    _
                "PUTTL","SCALAR","SCALARS","SEMICONT","SET","SETS","SOS1",     _
                "SOS2","TABLE","VARIABLE","VARIABLES","WHILE")
    
    if not needs_quoting then
       for j = 0 to Ubound(kw)
          if strcomp(s,kw(j),1)=0 then
            needs_quoting = true
            exit for
          end if
       next
    end if
    
    '
    ' already quoted?
    '
    ch = left(s,1)
    select case ch
       case "'", """"
           quotestring = s
           exit function
    end select
    
    ' check for special case
    if has_single_quotes and has_double_quotes then
       quotestring = """" & replace(s, """", "'") & """"
    elseif has_single_quotes then
       quotestring = """" & s & """"
    elseif has_double_quotes then
       quotestring = "'" & s & "'"
    elseif needs_quoting then
       quotestring = "'" & s & "'"
    else
       quotestring = s
    end if
    
    
    end function
    $offecho
    
    execute '=cscript sql2gms.vbs';
    

    1.9.5 SQL2GMS timeouts

    New time out options have been added:
    Command line parameter Description
    t1=ConnectionTimeOut Indicates how long to wait while establishing a connection before terminating the attempt and generating an error. The value sets, in sec