“If you want more effective programmers, you will discover that they should not waste their time debugging, they should not introduce the bugs to start with.”
– Edsger Dijkstra
During the software development process, the more non-deterministic processes that enter into your workflow the greater chance of introducing unintended bugs or functional regression. There’s nothing more frustrating than to fix a bug (or make an improvement) only to have something else in your app break. Thus, it’s generally considered good practice to automate as much of your pipeline (from build to asset creation) as possible. If you can automate something, do so! It’ll save you time and effort later.
If you decide to use SQLite in your iPhone app, there are a few steps to follow in order to automate re-creation of your database.
For Daily Value, I used a couple of tools to construct and later manipulate the database. On the PC, the process started with Microsoft Access to transform the relational database from the USDA into a number of Excel spreadsheets – one for each table. From Access, this was accomplished by right clicking the tables and selecting “Export | Excel”.
Microsoft Excel 2007 was used heavily to manipulate and process the input data before it was ready to export into SQLite. There are some subtle and sometimes frustrating differences between Excel 2007 and 2003. It felt to me like exporting was more flexible in the earlier version. Basically, the “standard” CSV is “comma separated values” which created an input parsing problem for both SQLite Manager for Firefox and the command line tool, sqlite3, because the commas used for field delimiters.
I dimly thought that in older versions of Excel, when exporting to CSV, a series of dialogs took you through the process and allowed you to specify a custom delimiter. In a file full of strings with commas already, the ability to set the token was great. In my case, I wanted to export the data using the pipe (|) symbol. It took some digging but exporting to CSV in 2007 to a flavor that SQLite liked required changing the output separator token via the Control Panel!
Here’re the basic steps:
- With Excel closed, open the Control Panel
- Double click the Regional and Language Options
- On the Regional Options tab, click on the Customize button
- On the Numbers tab, change the List separator to “|” (without the quotes)
Now you can “Save As” in Excel using CSV with the custom separator.
I used SQLite Manager early in the development process because it was very convenient to not only import data, but it was nice working in a visual environment as the tables continued to undergo design changes. Even after I automated the database creation, the tool was useful to inspect run-time changes from the Simulator. It was also nice to see the SQL the tool generated when creating tables, indices, or other operations on the data.
Once the table structure solidified, I wrote a simple “text input file” to re-create the database using the sqlite3 schema command.
- Gather up the structure of your tables by using either SQLite Manager or sqlite3. In the Firefox plug-in, SQLite Manager has a tab that describes the table structure. Or, launch the Terminal, and open your database with sqlite3, then type “.schema <table_name>” to get the structure.
- Copy this information to TextEdit (or an editor of your preference). The top portion of this file should issue all the table creation commands required to setup your database structure.
- Then add the sqlite3 import commands to import the CSV files.
.import table_1.csv table_1
And so on. If you need to insert data into the tables, or create indices on any tables, you can insert these commands at the end of the file. My input file, named schema.txt, looked something like this:
CREATE TABLE “food” (“pk” INTEGER PRIMARY KEY NOT NULL, “group” INTEGER, “name” TEXT, “desc” TEXT);
CREATE TABLE “version” (“ver” INTEGER);
.import food.csv food
CREATE INDEX idx_food_pk ON food (“pk” ASC);
INSERT INTO version (ver) VALUES (“2”);
A couple notes on the file format. You can span SQL commands on multiple lines in order to make the file more human readable. The semi-colon is important for any SQL statements used in the file. You should remove any column header information from the CSV file prior to using the “.import” command as the column types most likely won’t match and cause the import to fail. Also, the CSV files reside in the same directory as where you’ll create the database and issue the sqlite3 command as shown below:
%sqlite3 database.sqlite < schema.txt
If you really wanted to get more sophisticated, you could hook running (and copying) this freshly created database into Xcode as a build step. In another entry, I’ll talk about how I use something similar to auto version builds based on the repository revision.