## Converting data from Microsoft Access (mdb) format to MySQL

Slovenian “National Interoperability Framework” (NIO) publishes some interesting data every now and then, but most data is usually in MS Access ‘mdb’ format and/or ‘csv’. Working with csv files is painful, since you have to do everything by hand (no selects, filters etc, you have to go through each and every line and check the conditions in a giant loop), and using Microsoft Access on Linux is an even bigger NO.

So, i decided to download some data (anonymized data on drivers licences in Slovenia), and convert it from mdb to MySQL (and insert it into the database). I could have done the same with parsing the csv file, but doing it from mdb autogenerates the database schema, (with csv, you have to do that yourself, by hand).

For converting the data i used mdbtools. The data i used can be found here (zipped mdb).

The first thing after downloading and unzipping the data, was to check which (and how many) tables are inside – you can do this with the “mdb-tables” command.

mulaz@x ~/vd \$ mdb-tables Vozniki2013.mdb
Vozniki_2013

So, there is one table in the database named “Vozniki_2013” (old data, I know).

To generate the schema I used the “mdb-schema” command (with MySQL output):

mulaz@x ~/vd \$ mdb-schema Vozniki2013.mdb mysql
-- ----------------------------------------------------------
-- MDB Tools - A library for reading MS Access database files
-- Copyright (C) 2000-2011 Brian Bruns and others.
-- Files in libmdb are licensed under LGPL and the utilities under
-- the GPL, see COPYING.LIB and COPYING files respectively.
-- Check out http://mdbtools.sourceforge.net
-- ----------------------------------------------------------

-- That file uses encoding UTF-8

CREATE TABLE `Vozniki_2013`
(
`VIR_PODATKOV`                  varchar (510),
`STAROST`                       varchar (510),
`SPOL`                  varchar (510),
`PODVRSTA_VD`                   varchar (510),
`DATUM_IZDAJE`                  varchar (510),
`DATUM_VELJAVNOSTI`                     varchar (510),
`OMEJITEV_220`                  varchar (510),
`OMEJITEV_70`                   varchar (510),
`OMEJITEV_71`                   varchar (510),
`AM_DATUM_PRIDOBITVE`                   varchar (510),
`AM_DATUM_VELJAVNOSTI`                  varchar (510),
`A1_DATUM_PRIDOBITVE`                   varchar (510),
`A1_DATUM_VELJAVNOSTI`                  varchar (510),
`AM2_DATUM_PRIDOBITVE`                  varchar (510),
`AM2_DATUM_VELJAVNOSTI`                 varchar (510),
`A_DATUM_PRIDOBITVE`                    varchar (510),
`A_DATUM_VELJAVNOSTI`                   varchar (510),
`B1_DATUM_PRIDOBITVE`                   varchar (510),
`B1_DATUM_VELJAVNOSTI`                  varchar (510),
`B_DATUM_PRIDOBITVE`                    varchar (510),
`B_DATUM_VELJAVNOSTI`                   varchar (510),
`C1_DATUM_PRIDOBITVE`                   varchar (510),
`C1_DATUM_VELJAVNOSTI`                  varchar (510),
`C1_95`                 varchar (510),
`C_DATUM_PRIDOBITVE`                    varchar (510),
`C_DATUM_VELJAVNOSTI`                   varchar (510),
`C_95`                  varchar (510),
`D1_DATUM_PRIDOBITVE`                   varchar (510),
`D1_DATUM_VELJAVNOSTI`                  varchar (510),
`D1_95`                 varchar (510),
`D_DATUM_PRIDOBITVE`                    varchar (510),
`D_DATUM_VELJAVNOSTI`                   varchar (510),
`D_95`                  varchar (510),
`BE_DATUM_PRIDOBITVE`                   varchar (510),
`BE_DATUM_VELJAVNOSTI`                  varchar (510),
`C1E_DATUM_PRIDOBITVE`                  varchar (510),
`C1E_DATUM_VELJAVNOSTI`                 varchar (510),
`C1E_95`                        varchar (510),
`CE_DATUM_PRIDOBITVE`                   varchar (510),
`CE_DATUM_VELJAVNOSTI`                  varchar (510),
`CE_95`                 varchar (510),
`D1E_DATUM_PRIDOBITVE`                  varchar (510),
`D1E_DATUM_VELJAVNOSTI`                 varchar (510),
`D1E_95`                        varchar (510),
`DE_DATUM_PRIDOBITVE`                   varchar (510),
`DE_DATUM_VELJAVNOSTI`                  varchar (510),
`DE_95`                 varchar (510),
`F_DATUM_PRIDOBITVE`                    varchar (510),
`F_DATUM_VELJAVNOSTI`                   varchar (510),
`G_DATUM_PRIDOBITVE`                    varchar (510),
`G_DATUM_VELJAVNOSTI`                   varchar (510),
`ID`                    int
);

Every field is “varchar (510)”, and that’s long. I’ve checked the data, and it fits into “varchar (50)”, so you can do a sed replace, to change the field size in the output. After that, you connect to the database, paste this output into the console (or pipe it directly from the command), and you will have an empty table created for your data.

This would also be a good time to create any indexes you need.

Now all we need is the actual data; we can get that using the “mdb-export” command (we have to tell it the table we want to export, and the output syntax).

mulaz@x ~/vd \$ mdb-export -I mysql Vozniki2013.mdb Vozniki_2013
INSERT INTO `Vozniki_2013` (`VIR_PODATKOV`, `STAROST`, `SPOL`, `PODVRSTA_VD`, `DATUM_IZDAJE`, `DATUM_VELJAVNOSTI`, `OMEJITEV_220`, `OMEJITEV_70`, `OMEJITEV_71`, `AM_DATUM_PRIDOBITVE`, `AM_DATUM_VELJAVNOSTI`, `A1_DATUM_PRIDOBITVE`, `A1_DATUM_VELJAVNOSTI`, `AM2_DATUM_PRIDOBITVE`, `AM2_DATUM_VELJAVNOSTI`, `A_DATUM_PRIDOBITVE`, `A_DATUM_VELJAVNOSTI`, `B1_DATUM_PRIDOBITVE`, `B1_DATUM_VELJAVNOSTI`, `B_DATUM_PRIDOBITVE`, `B_DATUM_VELJAVNOSTI`, `C1_DATUM_PRIDOBITVE`, `C1_DATUM_VELJAVNOSTI`, `C1_95`, `C_DATUM_PRIDOBITVE`, `C_DATUM_VELJAVNOSTI`, `C_95`, `D1_DATUM_PRIDOBITVE`, `D1_DATUM_VELJAVNOSTI`, `D1_95`, `D_DATUM_PRIDOBITVE`, `D_DATUM_VELJAVNOSTI`, `D_95`, `BE_DATUM_PRIDOBITVE`, `BE_DATUM_VELJAVNOSTI`, `C1E_DATUM_PRIDOBITVE`, `C1E_DATUM_VELJAVNOSTI`, `C1E_95`, `CE_DATUM_PRIDOBITVE`, `CE_DATUM_VELJAVNOSTI`, `CE_95`, `D1E_DATUM_PRIDOBITVE`, `D1E_DATUM_VELJAVNOSTI`, `D1E_95`, `DE_DATUM_PRIDOBITVE`, `DE_DATUM_VELJAVNOSTI`, `DE_95`, `F_DATUM_PRIDOBITVE`, `F_DATUM_VELJAVNOSTI`, `G_DATUM_PRIDOBITVE`, `G_DATUM_VELJAVNOSTI`, `ID`) VALUES ("SVD","42","Ž","S","06.12.2002","21.04.2051",NULL,NULL,NULL,"02.06.1987","21.04.2051",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,"21.12.1989","21.04.2051",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,"02.06.1987","21.04.2051","02.06.1987","21.04.2051",1);
INSERT INTO `Vozniki_2013` (`VIR_PODATKOV`, `STAROST`, `SPOL`, `PODVRSTA_VD`, `DATUM_IZDAJE`, `DATUM_VELJAVNOSTI`, `OMEJITEV_220`, `OMEJITEV_70`, `OMEJITEV_71`, `AM_DATUM_PRIDOBITVE`, `AM_DATUM_VELJAVNOSTI`, `A1_DATUM_PRIDOBITVE`, `A1_DATUM_VELJAVNOSTI`, `AM2_DATUM_PRIDOBITVE`, `AM2_DATUM_VELJAVNOSTI`, `A_DATUM_PRIDOBITVE`, `A_DATUM_VELJAVNOSTI`, `B1_DATUM_PRIDOBITVE`, `B1_DATUM_VELJAVNOSTI`, `B_DATUM_PRIDOBITVE`, `B_DATUM_VELJAVNOSTI`, `C1_DATUM_PRIDOBITVE`, `C1_DATUM_VELJAVNOSTI`, `C1_95`, `C_DATUM_PRIDOBITVE`, `C_DATUM_VELJAVNOSTI`, `C_95`, `D1_DATUM_PRIDOBITVE`, `D1_DATUM_VELJAVNOSTI`, `D1_95`, `D_DATUM_PRIDOBITVE`, `D_DATUM_VELJAVNOSTI`, `D_95`, `BE_DATUM_PRIDOBITVE`, `BE_DATUM_VELJAVNOSTI`, `C1E_DATUM_PRIDOBITVE`, `C1E_DATUM_VELJAVNOSTI`, `C1E_95`, `CE_DATUM_PRIDOBITVE`, `CE_DATUM_VELJAVNOSTI`, `CE_95`, `D1E_DATUM_PRIDOBITVE`, `D1E_DATUM_VELJAVNOSTI`, `D1E_95`, `DE_DATUM_PRIDOBITVE`, `DE_DATUM_VELJAVNOSTI`, `DE_95`, `F_DATUM_PRIDOBITVE`, `F_DATUM_VELJAVNOSTI`, `G_DATUM_PRIDOBITVE`, `G_DATUM_VELJAVNOSTI`, `ID`) VALUES ("SVD","44","Ž","S","12.07.2000","29.10.2049",NULL,NULL,NULL,"12.07.2000","29.10.2049",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,"12.07.2000","29.10.2049",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,"12.07.2000","29.10.2049",2);
INSERT INTO `Vozniki_2013` (`VIR_PODATKOV`, `STAROST`, `SPOL`, `PODVRSTA_VD`, `DATUM_IZDAJE`, `DATUM_VELJAVNOSTI`, `OMEJITEV_220`, `OMEJITEV_70`, `OMEJITEV_71`, `AM_DATUM_PRIDOBITVE`, `AM_DATUM_VELJAVNOSTI`, `A1_DATUM_PRIDOBITVE`, `A1_DATUM_VELJAVNOSTI`, `AM2_DATUM_PRIDOBITVE`, `AM2_DATUM_VELJAVNOSTI`, `A_DATUM_PRIDOBITVE`, `A_DATUM_VELJAVNOSTI`, `B1_DATUM_PRIDOBITVE`, `B1_DATUM_VELJAVNOSTI`, `B_DATUM_PRIDOBITVE`, `B_DATUM_VELJAVNOSTI`, `C1_DATUM_PRIDOBITVE`, `C1_DATUM_VELJAVNOSTI`, `C1_95`, `C_DATUM_PRIDOBITVE`, `C_DATUM_VELJAVNOSTI`, `C_95`, `D1_DATUM_PRIDOBITVE`, `D1_DATUM_VELJAVNOSTI`, `D1_95`, `D_DATUM_PRIDOBITVE`, `D_DATUM_VELJAVNOSTI`, `D_95`, `BE_DATUM_PRIDOBITVE`, `BE_DATUM_VELJAVNOSTI`, `C1E_DATUM_PRIDOBITVE`, `C1E_DATUM_VELJAVNOSTI`, `C1E_95`, `CE_DATUM_PRIDOBITVE`, `CE_DATUM_VELJAVNOSTI`, `CE_95`, `D1E_DATUM_PRIDOBITVE`, `D1E_DATUM_VELJAVNOSTI`, `D1E_95`, `DE_DATUM_PRIDOBITVE`, `DE_DATUM_VELJAVNOSTI`, `DE_95`, `F_DATUM_PRIDOBITVE`, `F_DATUM_VELJAVNOSTI`, `G_DATUM_PRIDOBITVE`, `G_DATUM_VELJAVNOSTI`, `ID`) VALUES ("SVD","55","Ž","S","29.06.1994","05.11.2038",NULL,NULL,NULL,"07.06.1990","05.11.2038",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,"07.06.1990","05.11.2038",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,"07.06.1990","05.11.2038",3);
INSERT INTO `Vozniki_2013` (`VIR_PODATKOV`, `STAROST`, `SPOL`, `PODVRSTA_VD`, `DATUM_IZDAJE`, `DATUM_VELJAVNOSTI`, `OMEJITEV_220`, `OMEJITEV_70`, `OMEJITEV_71`, `AM_DATUM_PRIDOBITVE`, `AM_DATUM_VELJAVNOSTI`, `A1_DATUM_PRIDOBITVE`, `A1_DATUM_VELJAVNOSTI`, `AM2_DATUM_PRIDOBITVE`, `AM2_DATUM_VELJAVNOSTI`, `A_DATUM_PRIDOBITVE`, `A_DATUM_VELJAVNOSTI`, `B1_DATUM_PRIDOBITVE`, `B1_DATUM_VELJAVNOSTI`, `B_DATUM_PRIDOBITVE`, `B_DATUM_VELJAVNOSTI`, `C1_DATUM_PRIDOBITVE`, `C1_DATUM_VELJAVNOSTI`, `C1_95`, `C_DATUM_PRIDOBITVE`, `C_DATUM_VELJAVNOSTI`, `C_95`, `D1_DATUM_PRIDOBITVE`, `D1_DATUM_VELJAVNOSTI`, `D1_95`, `D_DATUM_PRIDOBITVE`, `D_DATUM_VELJAVNOSTI`, `D_95`, `BE_DATUM_PRIDOBITVE`, `BE_DATUM_VELJAVNOSTI`, `C1E_DATUM_PRIDOBITVE`, `C1E_DATUM_VELJAVNOSTI`, `C1E_95`, `CE_DATUM_PRIDOBITVE`, `CE_DATUM_VELJAVNOSTI`, `CE_95`, `D1E_DATUM_PRIDOBITVE`, `D1E_DATUM_VELJAVNOSTI`, `D1E_95`, `DE_DATUM_PRIDOBITVE`, `DE_DATUM_VELJAVNOSTI`, `DE_95`, `F_DATUM_PRIDOBITVE`, `F_DATUM_VELJAVNOSTI`, `G_DATUM_PRIDOBITVE`, `G_DATUM_VELJAVNOSTI`, `ID`) VALUES ("SVD","34","Ž","S","03.12.2007","17.03.2059",NULL,NULL,NULL,"15.11.1999","17.03.2059",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,"15.11.1999","17.03.2059",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,"15.11.1999","17.03.2059",4);
...many more lines (~1.3M)

All you have to do now, is to redirect this to a file, and copy it to te server with the database, and import it (or pipe it directly, if you can use the MySQL client on the machine you’re using now).

If you have a large table with alot of lines/INSERTs, you will notice that the import takes alot of time. The main slowdown for me was because MySQL commits the data after every INSERT statement, and that takes time. If you want to speed it up, you can disable the autocommit, and manually commit at the end. Since i’ve exported the data to a text file first, I just added the two lines in the beginning and the end of the file:

SET autocommit=0;
INSERT ....;
INSERT ....;
....
COMMIT;

And voila, you have all the data in your MySQL database now.