Tuesday, December 6, 2011

Ending your search for using command line data loader with MySQL, Oracle, MS-SQL Server

I find Cliq for command line data loader very handy as in you can get ready with the basic configuration in minutes. This post describes how you can use CLI to import, export, insert and update data to and fro between salesforce.com and databases like MySQL, Oracle 10g and MS-SQL Server.

It is useful when you have an existing website that generates leads in your internal database and you want to import those leads to salesforce.com.

First of all, use cliq to create a export process and use the sample database-conf.xml provided with the Apex Data Loader.
  1. Copy the database-conf.xml file from the samples directory in data loader setup folder and paste it in the same folder as process-conf.xml
  2. Now modify the following properties in the process-conf.xml file:
    1. Set dataAccess.type property in process-conf as databaseRead or databaseWrite(we are writing to our Access db here, so we will use databaseWrite)
    2. Set dataAccess.Name property as name of the bean called in the database-conf.xml file(we are calling the bean insertAccount)
  3. Create a DSN connection by going to control panel > Administrative Tools > Data Sources (ODBC)
  4. Go to Data Sources(ODBC) and double click on MS Access Database.
  5. Specify a Data Source Name, say dsn1.
  6. Click on Select and choose your MS-Access database file(.mdb) 
  7. Open database-conf.xml and modify as follows:
    1. In dbDataSource bean, change the url property to jdbc:odbc:dsn1, it will look like: <property name="url" value="jdbc:odbc:dsn1"/>
    2. Search for insertAccount bean in database-conf.xml and locate the ref for the property name(in our case it is insertAccountSql) as shown in the image.
    3. In insertAccountSql bean change the sqlString property to the insert SQL command for your database, for eg:
    4. INSERT INTO MyAccounts (Acc_id, ACCOUNT_NAME, BUSINESS_PHONE) VALUES (@ID@, @Name@, @phone)
Note: The values between @’s are the mapping values from .sdl file that would have come as the column headers in csv file, if we are not using dataAccess.type as databaseRead or databaseWrite.Also, since there is no SDL file being used in export process as in here, so the values will be the names of the fields in salesforce.

     8.  Okay!! We are almost done, now save all the files and go to command prompt.
     9.  Move to the folder for cliq process and run the DOS batch file(export_, in our case)
    10. Open your Access database table and check the values.

Here is how process-conf.xml will look like:
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean id="export_" class="com.salesforce.dataloader.process.ProcessRunner" singleton="false">
        <description>Created by Dataloader Cliq.</description>
        <property name="name" value="export_"/>
        <property name="configOverrideMap">
            <map>
                <entry key="dataAccess.name" value="D:\SF Tools\cliq_process\export_\write\export_.csv"/>
                <entry key="dataAccess.readUTF8" value="true"/>
                <entry key="dataAccess.type" value="databaseWrite"/>
                <entry key="dataAccess.name" value="insertAccountSql"/>
                <entry key="dataAccess.writeUTF8" value="true"/>
                <entry key="process.enableExtractStatusOutput" value="true"/>
                <entry key="process.enableLastRunOutput" value="true"/>
                <entry key="process.lastRunOutputDirectory" value="D:\SF Tools\cliq_process\export_\log"/>
                <entry key="process.operation" value="extract_all"/>
                <entry key="process.statusOutputDirectory" value="D:\SF Tools\cliq_process\export_\log"/>
                <entry key="sfdc.endpoint" value="https://www.salesforce.com/services/Soap/u/21.0"/>
                <entry key="sfdc.entity" value="Account"/>
                <entry key="sfdc.extractionRequestSize" value="500"/>
                <entry key="sfdc.extractionSOQL" value="select id, name, phone from account"/>
                <entry key="sfdc.password" value="4eb77947398ff3a5d2ea19c5ae2f606717b24e228a14afbe491654"/>
                <entry key="sfdc.username" value="sankalp.jhingran@paper.com"/>
            </map>
        </property>
    </bean>
</beans>


Here is how the database-conf.xml will look like:

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="dbDataSource"
      class="org.apache.commons.dbcp.BasicDataSource"
      destroy-method="close">
    <property name="driverClassName" value="sun.jdbc.odbc.JdbcOdbcDriver"/>
    <property name="url" value="jdbc:odbc:dsn1"/>
    <property name="username" value="user"/>
    <property name="password" value="password"/>
</bean>

<bean id="insertAccount"
      class="com.salesforce.dataloader.dao.database.DatabaseConfig"
      singleton="true">
    <property name="sqlConfig" ref="insertAccountSql"/>
    <property name="dataSource" ref="dbDataSource"/>
</bean>
<bean id="insertAccountSql"
      class="com.salesforce.dataloader.dao.database.SqlConfig" singleton="true">
    <property name="sqlString">
        <value>
            INSERT INTO MyAccounts (Acc_id, ACCOUNT_NAME, BUSINESS_PHONE)
            VALUES (@ID@, @Name@, @phone)
        </value>
    </property>
    <property name="sqlParams">
        <map>
            <entry key="id"    value="java.lang.String"/>
            <entry key="Name"  value="java.lang.String"/>
            <entry key="Phone" value="java.lang.String"/>
        </map>
    </property>
</bean>
</beans>

For connecting to MySQL:
  1. Download the MySQL JDBC connector http://www.mysql.com/downloads/connector/j/. Extract the jar file to the Data Loader home directory (the same dir as DataLoader.jar).
  2. Change the URL property of dbDataSource as:
    • <property name="url" value="jdbc:mysql://{MYSQL HOSTNAME}/{DATABASE NAME}"/>
    • <property name="url" value="jdbc:mysql://localhost:3306/MyDB"/>
     3.  Edit export_.bat and add the mysql connector to the path as follows:

replace
call %DLPATH%\_jvm\bin\java.exe -cp %DLPATH%\DataLoader.jar
-Dsalesforce.config.dir=%DLCONF% com.salesforce.dataloader.process.ProcessRunner process.name=my_process

with
call %DLPATH%\_jvm\bin\java.exe -cp %DLPATH%\DataLoader.jar:%DLPATH%\mysql-connector-java-5.1.18-bin.jar
-Dsalesforce.config.dir=%DLCONF% com.salesforce.dataloader.process.ProcessRunner process.name=export_

For Oracle, use:
“jdbc:oracle:thin:@{serverName}:{portNumber}:sid”

NOTE: Instead of downloading JDBC drivers for the databases, every DB provides its ODBC connector for windows, so, you can use create a DSN for every DB like MySQL, Oracle, MS-SQL Server etc. and specify name of the DSN in the URL property.

I tried to make it as simple as possible, however scope of improvement is also there and hence feedback is highly appreciated.

10 comments:

  1. Nice one, please keep posting them, very helpful :)

    ReplyDelete
  2. Thank you very much for breaking it down for newbies like me.

    ReplyDelete
  3. Thanks very much for the post. I have duplicated your process and database XML config above and table MyAccounts within a db on an instance of SQL Server 2005, create the dsn "dsn1" using the SQL Native Client driver, and I get the following error using Data Loader 25.0.2. Would you be able to identify the issue? Much appreciated, -john

    2012-09-28 13:35:27,386 FATAL [export_] controller.Controller createDao (Controller.java:185) - Error creating data access object
    java.lang.ClassCastException: com.salesforce.dataloader.dao.database.SqlConfig cannot be cast to com.salesforce.dataloader.dao.database.DatabaseConfig
    at com.salesforce.dataloader.dao.database.DatabaseConfig.getInstance(DatabaseConfig.java:48)
    at com.salesforce.dataloader.dao.database.DatabaseWriter.(DatabaseWriter.java:74)
    at com.salesforce.dataloader.dao.database.DatabaseWriter.(DatabaseWriter.java:58)
    at com.salesforce.dataloader.dao.DataAccessObjectFactory.getDaoInstance(DataAccessObjectFactory.java:60)
    at com.salesforce.dataloader.controller.Controller.createDao(Controller.java:183)
    at com.salesforce.dataloader.process.ProcessRunner.run(ProcessRunner.java:130)
    at com.salesforce.dataloader.process.ProcessRunner.run(ProcessRunner.java:100)

    ReplyDelete
    Replies
    1. Hi:

      Were you able to resolve this issue? I am getting the same error.

      Your feedback is greatly appreciated.

      Delete
  4. I was never able to get Sankalp's configuration to work against SQL Server 2005 using the reference "sun.jdbc.odbc.JdbcOdbcDriver" and my ODBC dsn. I just got my configuration to work, however, using the sqljdbc4 driver taking an approach similar to this post (below). I wanted to share this information in attempt to avoid the pain I just experienced over the last couple of days.

    http://boards.developerforce.com/t5/Java-Development/How-to-use-Data-Loader-Command-Line-extract-data-into-MS-SQL/td-p/69561

    Notable Difference: Add the full path to the *versioned* jar file: sqljdbc4.jar.

    And be aware of case sensitivity in your SQL SELECT/INSERT statements.

    If anyone got Sankalp's configuration working against SQL Server please let us know.

    Good luck,
    -john

    ReplyDelete
  5. Thanks for this blog. I tested the above code for oracle with ODBC connection and it worked for me. Just make sure we have "insertAccount" instead of "insertAccountSql" for the below line in process-conf.xml file



    Thanks,
    Hemant

    ReplyDelete
  6. Getting following exception:-
    Failed to write item to data access object: insertAccount. Error: Database error encountered while preparing row #1 for writing row #1 through row #18. Database configuration: insertAccount. Error: .

    ReplyDelete
  7. I also came across the error included below (bottom).

    When creating ODBC data sources on a 64 bit Windows, you may be creating a 64 bit data source instead of a 32 bit data source.

    64 bit version of ODBC: c:\windows\system32\odbcad32.exe
    32 bit version: c:\windows\sysWOW64\odbcad32.exe

    (This article details this with more detail: http://stackoverflow.com/questions/8895823/the-specified-dsn-contains-an-architecture-mismatch-between-the-driver-and-appli)

    You will need to create a 32 bit data source when your ODBC drivers are 32 bit or you are interacting with a 32 bit application.



    ERROR [extract_] database.DatabaseContext initConnection (DatabaseContext.java:87) - Database error encountered during connecting for database configuration: insertContactNames. Sql error: Cannot create PoolableConnectionFactory ([Microsoft][ODBC Driver Manager] The specified DSN contains an architecture mismatch between the Driver an
    d Application).
    org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory ([Microsoft][ODBC Driver Manager] The specified DSN contains an architecture mismatch between the Driver and Application)
    at org.apache.commons.dbcp.BasicDataSource.createPoolableConnectionFactory(BasicDataSource.java:1549)
    at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1388)
    at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)

    ReplyDelete

Your feedback is always appreciated, thanks!!