VOOZH about

URL: https://www.cdata.com/kb/tech/workday-odbc-foxpro.rst

⇱ Work with Workday Data in FoxPro


Work with Workday Data in FoxPro

👁 Jerod Johnson
Jerod Johnson
Director, Technology Evangelism
Load Workday data into a FoxPro database. This article includes full code and a walk-through of the process.

The CData ODBC driver for Workday enables you to access Workday data using the ODBC standard. You can use the CData ODBC Driver for Workday to integrate Workday data into your FoxPro project. The procedure below provides a walk-through of the included code sample, which saves Workday data into tables in a FoxPro database.

About Workday Data Integration

CData provides the easiest way to access and integrate live data from Workday. Customers use CData connectivity to:

  • Access the tables and datasets you create in Prism Analytics Data Catalog, working with the native Workday data hub without compromising the fidelity of your Workday system.
  • Access Workday Reports-as-a-Service to surface data from departmental datasets not available from Prism and datasets larger than Prism allows.
  • Access base data objects with WQL, REST, or SOAP, getting more granular, detailed access but with the potential need for Workday admins or IT to help craft queries.

Users frequently integrate Workday with analytics tools such as Tableau, Power BI, and Excel, and leverage our tools to replicate Workday data to databases or data warehouses. Access is secured at the user level, based on the authenticated user's identity and role.

For more information on configuring Workday to work with CData, refer to our Knowledge Base articles: Comprehensive Workday Connectivity through Workday WQL and Reports-as-a-Service & Workday + CData: Connection & Integration Best Practices.


Getting Started


Connect to Workday as an ODBC Data Source

If you have not already, first specify connection properties in an ODBC DSN (data source name). This is the last step of the driver installation. You can use the Microsoft ODBC Data Source Administrator to create and configure ODBC DSNs.

NOTE: Set the 'Map To WVarchar' connection property to FALSE (FoxPro uses the ODBC W API and returns the WCHAR for the value type).

To connect to Workday, users need to find the Tenant and BaseURL and then select their API type.

Obtaining the BaseURL and Tenant

To obtain the BaseURL and Tenant properties, log into Workday and search for "View API Clients." On this screen, you'll find the Workday REST API Endpoint, a URL that includes both the BaseURL and Tenant.

The format of the REST API Endpoint is: https://domain.com/subdirectories/mycompany, where:

  • https://domain.com/subdirectories/ is the BaseURL.
  • mycompany (the portion of the url after the very last slash) is the Tenant.
For example, in the REST API endpoint https://wd3-impl-services1.workday.com/ccx/api/v1/mycompany, the BaseURL is https://wd3-impl-services1.workday.com and the Tenant is mycompany.

Using ConnectionType to Select the API

The value you use for the ConnectionType property determines which Workday API you use. See our Community Article for more information on Workday connectivity options and best practices.

APIConnectionType Value
WQLWQL
Reports as a ServiceReports
RESTREST
SOAPSOAP

Authentication

Your method of authentication depends on which API you are using.

  • WQL, Reports as a Service, REST: Use OAuth authentication.
  • SOAP: Use Basic or OAuth authentication.

See the Help documentation for more information on configuring OAuth with Workday.

Connect and Transfer

To get started, add the code sample to a new project. You can execute the following command to save all tables without displaying them:

DO C:\Temp\sqldump.prg WITH "CData Workday Source", "TESTDB", .f.

Below is the process that the program follows:

  1. Create a new FoxPro database.
  2. Open a connection to Workday data with the line below:

    m.hSQLconnection = SQLCONNECT(m.cODBCDSN)
    
  3. If the connection was successful, you can now retrieve the list of tables using the SQLTABLES function. The code below saves the list of tables in sys_tables.dbf:

    WAIT WINDOW "Fetching tables for data source '" + m.cODBCDSN + "'..." NOWAIT NOCLEAR
    m.nSQLTABLES = SQLTABLES(m.hSQLconnection)
    
    IF lUseDistinctConnections
     WAIT WINDOW "Closing ODBC Connection for data source '" + m.cODBCDSN + "'..." NOWAIT NOCLEAR
     SQLDISCONNECT(m.hSQLconnection)
     m.hSQLconnection = 0 * SQLCONNECT needs to be called again
    ENDIF
    
    IF m.nSQLTABLES > 0
     * create local table containing list of tables in db
     COPY TO (m.cImportData + "sys_tables")
     USE
    
     * convert each table to DBF
     USE (m.cImportData + "sys_tables")
     ALTER TABLE DBF("sys_tables") ;
     ADD COLUMN records i ;
     ADD COLUMN dbfname m
    
  4. Scan over each table, saving it to a DBF file. The function ODBCtoDBF stores the table in a DBF file and then opens a grid if the lBrowse parameter is set to true:
    FUNCTION ODBCtoDBF (cTableName as String, cTableType as String, lBrowse as Logical, lhSQLConnection as Integer)
    
     WAIT WINDOW ;
     "Converting " + m.cTableType + ' "' + m.cTableName + '" to DBF...' ;
     NOWAIT NOCLEAR
    
     ACTIVATE SCREEN
    
     * strip characters incompatible with FoxPro out of the name of the DBF file
     m.cTableAlias		= ""
     m.nTableNameLen		= LEN(m.cTableName)
     m.nTableNameStart	= 1
     
     FOR m.nTableNameStart = 1 TO m.nTableNameLen
     m.cCharacter = SUBSTR(m.cTableName, m.nTableNameStart, 1)	
     IF !ISALPHA(m.cCharacter) .and. (m.nTableNameStart = 1 .or. !ISDIGIT(m.cCharacter))
     m.cTableAlias = m.cTableAlias + "_"
     ELSE
     m.cTableAlias = m.cTableAlias + m.cCharacter
     ENDIF
     ENDFOR
    
     m.cFromTable = m.cTableName
     m.cTempViewAlias	= m.cTableType + "_" + m.cTableAlias
    
     LOCAL loException as Exception
     LOCAL lnResultSets
     
     TRY
     * run query
     m.lnResultSets = SQLEXEC(m.lhSQLConnection, ;
     "SELECT * FROM " + m.cFromTable, ;
     m.cTempViewAlias, ;
     aSQLResult)
    	 
     IF m.lnResultSets#1
     SET STEP ON
     ENDIF
    	
     ACTIVATE SCREEN
    
     CATCH TO m.loException
     ACTIVATE SCREEN
     ? "Error opening " + m.cTempViewAlias + ":"
     ? m.loException.Message
     ? m.loException.Details
     ENDTRY
    
     IF !USED(m.cTempViewAlias)
     RETURN
     ENDIF
    
     * copy records from view cursor to disk
     SELECT * FROM (m.cTempViewAlias) ;
     INTO TABLE (m.cImportData + m.cTableAlias)
    
     IF USED(m.cTableAlias)
    
     ACTIVATE SCREEN
    
     FLUSH	&& flush the buffer to write the data to disk
    
     IF m.lBrowse
     * pop the table up on screen
     SELECT (m.cTableAlias)
     BROWSE NORMAL NOMODIFY NOWAIT
     ACTIVATE SCREEN
     ELSE
     * close on-disk table for now
     USE IN (m.cTableAlias)
     ACTIVATE SCREEN
     ENDIF
     ENDIF
    
     IF USED(m.cTempViewAlias)
     USE IN &cTempViewAlias && close SQL view
     ACTIVATE SCREEN
     ENDIF
    
     WAIT CLEAR
    
    ENDFUNC
    
  5. You can now save tables of Workday data as DBF files.

Below is the full code, in FoxPro 9 syntax:

PARAMETERS cODBCDSN, cDatabaseName, lBrowseAfterConvert

*	cODBCDSN				The ODBC data source name, used for the name of the folder where the DBF tables are stored.
*	cDatabaseName			The name of the FoxPro database to use. This database is created if it does not exist. The default is DATABASE_NAME.
*								
*	lBrowseAfterConvert		If ".t." display each table with the BROWSE command after importing it. If ".f." close each table before moving on to the next one.

#define		ODBC_DATASOURCE		"DataSourceName"
#define		DATABASE_NAME		"odbcdata"

m.m_tpath = ".\" && root directory for data

ON ERROR
SET SAFETY OFF

IF VARTYPE(m.cODBCDSN)#"C" .or. EMPTY(m.cODBCDSN)
 m.cODBCDSN = ODBC_DATASOURCE
ENDIF
IF VARTYPE(m.cDatabaseName)#"C" .or. EMPTY(m.cDatabaseName)
 m.cDatabaseName = DATABASE_NAME
ENDIF

m.cImportData = m.cODBCDSN + "\"

CLOSE TABLES ALL
CLOSE DATABASES ALL

IF !DIRECTORY(m.cImportData)
	MKDIR (m.cImportData)
ENDIF

CREATE DATABASE (m.cDatabaseName)
CREATE CONNECTION (m.cDatabaseName) DATASOURCE (m.cODBCDSN) DATABASE (m.cDatabaseName)

WAIT WINDOW "Opening ODBC Connection for data source '" + m.cODBCDSN + "'..." NOWAIT NOCLEAR
m.hSQLconnection = SQLCONNECT(m.cODBCDSN)

IF m.hSQLconnection > 0
 * Connection successful; get list of tables
 WAIT WINDOW "Fetching tables for data source '" + m.cODBCDSN + "'..." NOWAIT NOCLEAR
 m.nSQLTABLES = SQLTABLES(m.hSQLconnection)

 IF m.nSQLTABLES > 0
 * Create local table containing list of tables in db
 COPY TO (m.cImportData + "sys_tables")
 USE

 * Convert each table to DBF
 USE (m.cImportData + "sys_tables")
 ALTER TABLE DBF("sys_tables") ;
 ADD COLUMN records	i ;
 ADD COLUMN dbfname	m

 SCAN	
 m.cCurrentTable	= TRIM(sys_tables.table_name)
 m.cCurrentTableType	= TRIM(sys_tables.table_type) && Valid values are "SYSTEMTABLE", "TABLE", and "VIEW".
 IF m.cCurrentTableType = "TABLE" or m.cCurrentTableType = "VIEW"

 ODBCtoDBF(m.cCurrentTable, m.cCurrentTableType, m.lBrowseAfterConvert, m.hSQLConnection)
 ELSE
 ACTIVATE SCREEN
 ? "ERROR:", m.cCurrentTable, "Couldn't open ODBC connection."
 =MESSAGEBOX("couldn't open data source " + m.cODBCDSN + " for table " + m.cCurrentTable + ".")
 ENDIF

 ENDSCAN
 BROWSE NORMAL NOWAIT

 ELSE
 =MESSAGEBOX("No tables found in data source " + m.cODBCDSN + ".")
 SET STEP ON
 ENDIF
 
 SQLDISCONNECT(m.hSQLconnection)
 
ELSE
 =MESSAGEBOX("Could not open data source " + m.cODBCDSN + ".")
 SET STEP ON
ENDIF

FUNCTION ODBCtoDBF (cTableName as String, cTableType as String, lBrowse as Logical, lhSQLConnection as Integer)

 WAIT WINDOW ;
 "Converting " + m.cTableType + ' "' + m.cTableName + '" to DBF...' ;
 NOWAIT NOCLEAR

 ACTIVATE SCREEN

 * Strip characters incompatible with FoxPro out of the name of the DBF file
 m.cTableAlias		= ""
 m.nTableNameLen		= LEN(m.cTableName)
 m.nTableNameStart	= 1
 
 FOR m.nTableNameStart = 1 TO m.nTableNameLen
 m.cCharacter = SUBSTR(m.cTableName, m.nTableNameStart, 1)	
 IF !ISALPHA(m.cCharacter) .and. (m.nTableNameStart = 1 .or. !ISDIGIT(m.cCharacter))
 m.cTableAlias = m.cTableAlias + "_"
 ELSE
 m.cTableAlias = m.cTableAlias + m.cCharacter
 ENDIF
 ENDFOR

 m.cFromTable = m.cTableName
 m.cTempViewAlias	= m.cTableType + "_" + m.cTableAlias

 LOCAL loException as Exception
 LOCAL lnResultSets
 
 TRY
 * Run query
 m.lnResultSets = SQLEXEC(m.lhSQLConnection, ;
 "SELECT * FROM " + m.cFromTable, ;
 m.cTempViewAlias, ;
 aSQLResult)
	 
 IF m.lnResultSets#1
 SET STEP ON
 ENDIF
	
 ACTIVATE SCREEN

 CATCH TO m.loException
 ACTIVATE SCREEN
 ? "Error opening " + m.cTempViewAlias + ":"
 ? m.loException.Message
 ? m.loException.Details
 ENDTRY

 IF !USED(m.cTempViewAlias)
 RETURN
 ENDIF

 * Copy records from view cursor to disk
 SELECT * FROM (m.cTempViewAlias) ;
 INTO TABLE (m.cImportData + m.cTableAlias)

 IF USED(m.cTableAlias)

 ACTIVATE SCREEN

 FLUSH	&& Flush the buffer to write the data to disk

 IF m.lBrowse
 * Display the table on screen
 SELECT (m.cTableAlias)
 BROWSE NORMAL NOMODIFY NOWAIT
 ACTIVATE SCREEN
 ELSE
 * Close on-disk table
 USE IN (m.cTableAlias)
 ACTIVATE SCREEN
 ENDIF
 ENDIF

 IF USED(m.cTempViewAlias)
 USE IN &cTempViewAlias && Close SQL view
 ACTIVATE SCREEN
 ENDIF

 WAIT CLEAR

ENDFUNC

Ready to get started?

Download a free trial of the Workday ODBC Driver to get started:

 Download Now

Learn more:

👁 Workday Icon
Workday ODBC Driver

The Workday ODBC Driver is a powerful tool that allows you to connect with live data from Workday, directly from any applications that support ODBC connectivity.

Access Workday data like you would a database - read, write, and update Workday Cash Management, Compensation, Financial Management, Payroll, etc. through a standard ODBC Driver interface.