JDBC Importer

JDBC Importer Logo

JDBC Importer Tutorial 2 : Multiple Tables, CSV Delimited Files

Please make sure you have the appropriate libraries in your classpath (including the JDBC driver used to connect to your database) before starting the tutorials.

In this tutorial, you'll learn the basics of creating a JDBCImporter import XML config file and running the import from the command line. You'll be importing data into three tables :

department
NameType
idnumber(6)
namevarchar(20)
officevarchar(20)
employee
NameType
idnumber(6)
firstnamevarchar(10)
lastnamevarchar(10)
jobdescriptionvarchar(10)
manageridnumber(6)
startdatedate
salarynumber(9,2)
departmentnumber(6)
salarygrade
NameType
gradenumber(2)
minimumnumber(9,2)
maximumnumber(9,2)

Make sure that these table(s) are created in the database that you'll be importing data. You can find the oracle creation script in the samples directory under the filename : 'tutorial2/createtable_ora.sql'.

If you have read through the first tutorial then you may wish to skip to the entity definitions section. The other sections are the same as the first tutorial.

Now that the database is setup, you can examine the import XML config file that will be used (in the samples directory under the filename : 'tutorial2/import.xml'). The file begins with the standard XML document declaration followed by the '<import>' tag. This tag indicates that there is an import to be processed. There are seven attributes specified on the '<import>' tag: the 'log' attribute, the 'bad' attribute, the 'commitCount', the 'batchCount' attribute, the 'preSQLFile' attribute, the 'postSQLFile' attribute and the 'trimValues' attribute. The 'log' attribute specifies a filename into which JDBCImporter writes all audit, error, and warnings that occur during the import. The 'bad' attribute specifies a filename into which JDBCImporter writes data that was not properly imported into the database. The 'commitCount' attribute specifies how many rows to import before calling commit on the JDBC Connection. The 'batchCount' attribute specifies how many rows to import before calling executeBatch on the import engine (when the JDBC driver supports batch mode). By default, the 'commitCount' and 'batchCount' attributes are set 1, auto commit is turned on and batch mode is not used. The 'preSQLFile' and the 'postSQLFile' attributes specify filenames that contain sql statements to be executed before and after the import , respectively. The 'trimValues' attribute specifies whether strings values read from the Delimiter Parser are trimmed (ie. remove leading and trailing whitespace). By default, it is set to false.

There are two parts inside the '<import>' tag that define how and where the data is imported: the connection definition and the entity definitions.

Connection Definition

The connection definition begins with '<connection>' tag and contains the information needed to connect to the database. In this tutorial, you will be using the JDBC DriverManager to initialize a connection to the database. To indicate this, the 'type' attribute's value, inside the '<connection>' tag, is 'jdbc'. The specific connection information is found inside the '<connection>' tag as '<property>' tags. A '<property>' tag has two attributes: 'name' specifies the name of the property and 'value' specifies the string value of the property. For the JDBC DriverManager, you will need to specify the following information: the driver class name (with the property name 'driver'), the connection url (with the property name 'url'), the username (with the property name 'username'), the password (with the property name 'password'). The following is an example of the connection definition :

 <connection type="jdbc"> 
    <property name="driver" value="oracle.jdbc.driver.OracleDriver"/> 
    <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/> 
    <property name="username" value="scott"/> 
    <property name="password" value="tiger"/> 
 </connection> 
Sample XML for Connection Definition

Entity Definition

Since you will be importing data into three tables, there will be only three entity definitions. The 'employee' table has a foreign key that references the 'department' table. Therefore, the data for the 'department' table should be imported first, the data for the 'employee' table second, and finally the data for the 'salarygrade' table (since it doesn't have any foreign keys and no other tables reference it).In general, you will need an entity definition for each table that you will be importing data. Remember to specify the entity definitions in the order that the import should occur. For example, if table 'ingredient' depends on table 'recipe' (ie. has a foreign key), the entity definition of table 'recipe' should be placed before the entity definition of table 'ingredient'. Every entity definition begins with '<entity>' tag.

The 'table' attribute must contain the name of the table. Optionally, you can further specify the table by providing values for the 'schema' and the 'catalog' attributes.

To specify a custom import engine to process the entity, you may add the 'engine' attribute, whose value is the classname of the import engine.In this tutorial, you will be using the default import engine.

The 'source' attribute must contain the data file location. From looking at the sample data for the 'department' table (found under 'samples/tutorial2/department.csv'), you will see that there are 3 columns that are separated by the ',' character. Each column may also be enclosed by the "'" character.

There are three parts inside the '<entity>' tag : the delimiter parser definition, row translator definition, and the list of columns found in the data file.

Delimiter Parser

The delimiter parser definition begins with the '<delimiter>' tag and contains the information needed to parse the input file into a set of rows that will be imported into the table. In this tutorial, you will be using the CSV Delimiter Parser. To indicate this, the 'type' attribute's value, inside the '<delimiter>' tag, is 'csv'. The specific delimiter parser information is found inside the '<delimiter>' tag.

For the CSV Delimiter Parser, you will need to specify the following information (as '<property>' tags): the string that delimits a column (in the property named 'columnDelimiter'), the string that encloses a column (optional, in the property named 'enclosedDelimiter'), whether the string that encloses a column is optional (in the property named 'enclosedOptional', it must have a value of 'true' or 'false'). Since, the data file for the 'department' table has a column delimiter (',' is the string separating the columns) and an optional enclosed deliimter ("'" is the character that encloses some columns) the delimiter parser definition will look like this :

  <delimiter type="csv"> 
    <property name="columnDelimiter" value=","/> 
    <property name="enclosedDelimiter" value="'"/> 
    <property name="enclosedOptional" value="true"/> 
  </delimiter> 
Sample XML for CSV Delimiter Parser

Row Translator

The row translator definition is optional and begins with the '<translator>' tag. It contains the information needed to translate each row's values and may add, remove column values or skip the whole row. In this tutorial, you will not be using a row translator. Therefore the '<translator>' does not appear as a child inside the '<entity>' tag.

List of Columns

The final portion of the entity definition is the list of columns that are to be imported from the input file into the database. The list of columns should be the same order as they appear in the input file. Each column is defined inside the '<column>' tag. The name of the column must appear in the 'name' attribute of the '<column>' tag. Optionally, the java.sql.Type may be specified in the 'SQLType' attribute of the '<column>'.You will be letting the JDBC Importer figure out most of the column types (except for dates) in the database, so the 'SQLType' attribute is omitted except for the 'startdate' column. Here is an example of how the list of columns are defined in the import definition:

  <column name="id"></column>
  <column name="name"></column>
  <column name="office"></column>
Sample XML for List of Columns

Running the Import

By now, the import definition should look like this (with your appropriate connection information):

<import log="import.log bad="import.bad"> 
  <connection type="jdbc"> 
     <property name="driver" value="oracle.jdbc.driver.OracleDriver"/> 
     <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/> 
     <property name="username" value="scott"/> 
     <property name="password" value="tiger"/> 
  </connection> 
  <entity table="department" source="department.csv">
    <delimiter type="csv"> 
      <property name="columnDelimiter" value=","/> 
      <property name="enclosedDelimiter" value="'"/> 
      <property name="enclosedOptional" value="true"/> 
    </delimiter> 
    <column name="id"></column>
    <column name="name"></column>
    <column name="office"></column>
  </entity> 
  <entity table="employee" source="employee.csv">
    <delimiter type="csv"> 
      <property name="columnDelimiter" value=","/> 
    </delimiter> 
    <column name="id"></column>
    <column name="firstname"></column>
    <column name="lastname"></column>
    <column name="jobdescription"></column>
    <column name="managerid"></column>
    <column name="startdate" SQLType="DATE"></column>
    <column name="salary"></column>
    <column name="department"></column>
  </entity> 
  <entity table="salarygrade" source="salarygrade.csv">
    <delimiter type="csv"> 
      <property name="columnDelimiter" value=","/> 
    </delimiter> 
    <column name="grade"></column>
    <column name="minimum"></column>
    <column name="maximum"></column>
  </entity> 
</import> 
Sample XML for Tutorial 2

Since there are no custom connections, delimiters or translators, you can run the import by issuing the following command (assuming that the import definition is in the current directory and is called 'import.xml'):

java net.sourceforge.jdbcimporter.Importer import.xml

If all goes well then the two log files should be created. In the normal log file there should be an informational message indicating that all rows were imported. In the bad log file there should be a heading for the import table.

Generating an Error

Because all rows were imported successfully, there was no error messages. To generate an error message, change the department.csv file so that the employee.csv file will have invalid records. For example, if you change line 1, so that the first column is '1996' instead of '1994', the import will fail for several lines in the employee.csv. After running the import, the normal log file should contain a message indicating that 62 out of 75 rows were imported and a linenumber/stack trace for the invalid rows. The invalid lines should be written into the bad log file.