In my efforts to get more comfortable with Perl, I wrote the script below that converts a simple Excel spreadsheet into a simple Access table. It's a panless way to get some Excel data into an Access database, without having to open either app. I took the Win32::OLE tack since I'm pretty comfortable with ADODB and just wanted to get something up and running quickly. <digress> I had trouble finding an ODBC driver to use with DBI, e.g., "DBI->connect("dbi:ODBC:$DSN", '','')" would always give me an "install_driver(ODBC) failed:..." error message even after I installed the ODBC module. </digress>

The solution is not especially robust:
(1) all sheets are assumed to have the same columns
(2) all Excel data is rendered as of "text" (varchar) data type in Access
(3) the only error trapping happens, if at all, at the end with only the last error identified.

There are probably other flaws that people will spot. If you see one or experience one when you run it, I'd be interested to hear about it. If you spot any virtues in this, only my second Perl script, I'd like to hear about them too (:-).

Peace,

-- Jack

# Adapted from and inspired by # http://www.perlmonks.com/?node_id=514384, Dec 06, 2005, awohld use strict; use Spreadsheet::ParseExcel::Simple; use Win32::OLE; # --------------------------------------------------------- # Parameter 1: Name of Excel File to be Access-ized my $ExcelFile = $ARGV[0]; # Parameter 2: Name of Table to be created my $AccessTable = $ARGV[1]; # Parameter 3: Name of predefined DSN for preexisting Access .mdb file my $DSN = $ARGV[2]; # --------------------------------------------------------- my $first_row = 1; my @fields; my $SQL; my $conn = Win32::OLE->new('ADODB.Connection'); $conn->open($DSN); my $xls = Spreadsheet::ParseExcel::Simple->read($ExcelFile); foreach my $sheet ($xls->sheets) { while ($sheet->has_data) { my @data = $sheet->next_row; # For the first row, create a new table and use its data for +the header row if ($first_row) { foreach my $head (@data) { $head =~ s/[^a-zA-Z]//g; push(@fields, $head); } $SQL = "CREATE TABLE `". $AccessTable . "` (" . join( " varchar(255),", @fields) . " varchar(255))"; $conn->execute($SQL); $first_row = 0; } # Insert all other row data in the table else { $SQL = "INSERT INTO " . $AccessTable . " (" . join (',',@fields) . ") VALUES (\'" . join ('\',\'', @data) . "');"; $conn->execute($SQL); } } } print "That didn't go so well: ", Win32::OLE->LastError(), "\n" if (Win32::OLE->LastError()); $conn->close if ($conn); exit;

Edit: g0n - moved from SoPW to CUFP

Replies are listed 'Best First'.
Re: Transforming an Excel Spreadsheet into an Access Table
by holli (Abbot) on Dec 08, 2005 at 18:17 UTC
    ... I'm pretty comfortable with ADODB...
    Then you might be glad to here, there is DBD::ADO .
    1) all sheets are assumed to have the same columns
    You will find it hard to write a generic importer. at least you will have to declare the structure of the excel files, which fields to import etc. Import data into MS-Access is a textfile to access importer, that might give you some ideas.
    (2) all Excel data is rendered as of "text" (varchar) data type in Access
    Spreadsheet::ParseExcel's cell object supports a "Type" property that returns the kind of that cell ('Text', 'Numeric', 'Date'), so you could use this for your datatypes.


    holli, /regexed monk/
Re: Transforming an Excel Spreadsheet into an Access Table
by InfiniteSilence (Curate) on Dec 08, 2005 at 20:05 UTC
    Field names with more than one word (not suggested, but it happens) need to have the following syntax in Microsoft Access:
    create table foobie ([dog life] text ,[happystance] text);

    Celebrate Intellectual Diversity

Re: Transforming an Excel Spreadsheet into an Access Table
by jfroebe (Parson) on Dec 08, 2005 at 17:40 UTC
Re: Transforming an Excel Spreadsheet into an Access Table
by Anonymous Monk on Dec 28, 2005 at 13:44 UTC
    Hi Jack,
    Indeed, I can spot many virtues in your attempts to handle the somewhat bulky Win32 applications from the bright side of perl.
    It may be a digression, but reading your point (2) I wondered if in the meantime you may have managed to create fields with data type AutoIncrField?
    I've been trying this
    my $Access = Win32::OLE->new('Access.Application', 'Quit'); my $Workspace = $Access->DBEngine->CreateWorkspace('', 'Admin', ''); my $Database = $Workspace->CreateDatabase($Filename, dbLangGeneral); my $TableDef1 = $Database->CreateTableDef('_FilterDefinitions'); my $Field = $TableDef1->CreateField('AutoInc', dbAutoIncrField);
    but it just doesn't seem to work, although it works for all other data types (dbText, dbInteger, dbDouble etc.).
    I also admit it's perl-related, but may be seen as an Access question rather than perl...
    Could it be, because dbAutoIncrField is only a DAO, but not an ADO constant?
    Would be grateful for any ideas in this direction...
    Cheers,
    Thomas
    mailto:engel_thomas@gmx.net