Connect to MS Access with Python

Posted by in Microsoft Access, Python

Since I started to program with #Python, one of the first objectives I have is to stop using MS Access. But, until them, I must work with it. Although I am surprised for the huge amount of modules and packages of Python, no one seems to fit with MS Access, and the few that I found doesn’t seem easy …. at first. So, let’s go!

I found a class on ActiveState (http://code.activestate.com/recipes/528868/) to connect to MS Access, by using Python for Windows Extension, but although it’s very powerful, you need to compile a few libraries before start. Too complicated for beginers, so I haven’t tried, because I am looking for something “simple”, and that’s not what I expected.

Adodb

Another option I found is adodb.py, an abstract library for databases, originally was developed for PHP, but it was migrated yo Python. The project seems not to be active, because since 2008 there is no update, but you can download it here.

The positive aspect of this classs is the hability to create a connection very easy with several types of databases, like MS Access, MySQL PostgreSQL, ORACLE, SQLite, … but one of the aspect I don’t like is that you need a connection string (and I already told you that I hate connection strings). Another issue is that the library is not included neither in Python Portable ni en Anaconda, so, you need to install it before.

Here you have a tutorial for Python … not very large. I should try, but I was not in the mood …. maybe other day ….

Trying adodbpy

Maybe, the best alternative I found is adodbpy, included on the Anaconda distribution, as you can see in the next image.

adodb y adodbapi en Anaconda

adodb y adodbapi en Anaconda

If you have only Python installed (no Python distribution), you can download the package here: adodbapi.sourceforge.net.

Adodbpy is a module close to Microsoft ADO, but specifically for Python, and to use it, you need connection strings.

Let’s try it with a small example I found on Github, just modifying the database path and the SQL query.

usando adodbapi

using adodbapi

and … in action:

probando adodbapi

trying adodbapi

And … I create my own class, based on adodbpy

Because I will use adodbpy a lot, and almost in the same way in several projects (and of course, because I’m starting with databases and Python), it’s a good idea to create my own class for working with MS Access and Python, and reuse it in several projects. You can download the class on my GitHub.


# coding: utf-8
__author__ = 'dtrillo'
import adodbapi

version = "0.8.3 - 20140605"
nl = "\n"

class MSAccessConnector():
    """ Clase para trabajar con bases de datos Microsoft Access en Python usando 'adodbapi'    """
    def __init__(self, fileMdb, debug=False):
        """ Inicializa OBJETO MSAccess """
        self.debug = debug
        self.ErrMsg, self.file, self.connString = '', '', ''
        self.consultas = []     # Listado de consultas realizadas
        self.isConnected = False
        self.openConnection(fileMdb)

    def openConnection(self, fileMdb):
        if fileMdb != self.file and len(fileMdb) > 0:
            if self.isConnected: self.close()
            self.file = fileMdb
            self.__createConnString()   # Crea conexion
            self.isConnected = self.__openConn()

    def __openConn(self):
        """ Abre Conexion con BdD para empezar a trabajar """
        if len(self.connString) == 0:
            self.ErrMsg = 'Sin Cadena de Conexion'
            self.conn = None
            return False
        if len(self.ErrMsg)>0: return False

        try:
            self.ErrMsg = ''
            self.conn = adodbapi.connect(self.connString, timeout=15) # connect to the database
            if self.debug: print "Conectado!"
            self.SQLList_empty()       # Reinicia Listado de consutlas SQL
            return True
        except Exception, e:
            self.ErrMsg = 'Error al abrir Conexion' + nl + str(e)
            self.conn = None
            return False

    def __createConnString(self):
        """ Crea Cadena de Conexion con MDB """
        if len(self.file) == 0:
            self.connString = ''
            return False
        else:
            #self.connString = 'Provider=Microsoft.Jet.OLEDB.4.0; Data Source=%s' % self.file
            self.connString = 'Provider=Microsoft.ACE.OLEDB.12.0; Data Source=%s;Persist Security Info=False;' % self.file
            return True

    def __del__(self):
        """ Al eliminar el OBJETO, cierra la conexion y elimina la conexion        """
        self.close()
        self.conn = None
        self.consultas = []

    def close(self):
        """ Cierra la conexion """
        try:
            self.conn.close()
        except:
            pass
        finally:
            self.SQLList_empty()
            self.isConnected = False
            if self.debug: print "Fin de Conexion!"

    @staticmethod
    def verificaSQLisSELECT(sql):
        word = "SELECT"
        tmp = sql[0:len(word)].upper()
        return True if word == tmp else False

    def query(self, sql):
        """ consultas SELECT """
        if self.isConnected == False or len(self.ErrMsg)>0:
            return [], True
        try:
            if self.verificaSQLisSELECT(sql) == False: # Versión 0.8.1
                self.ErrMsg = "Se esperaba una sentencia SELECT"
                return [], True

            self.ErrMsg = ''
            cur = self.conn.cursor()
            try:
                cur.execute(sql)
                result = cur.fetchall() # show the result
                cur.close() # close the cursor and connection
                self.__SQLList_add(sql)
                return result, False
            except Exception, f:
                self.ErrMsg = 'Error al ejecutar SQL ' + nl + str(f)
                return [], True
        except Exception, e:
            self.ErrMsg = 'Error al iniciar cursor!' + nl + str(e)
            return [], True
    def query2(self, sql):
        res, bln = self.query(sql)
        return res
    def query1value(self, sql, default = None):
        """ Devuelve el UNICO valor esperado de una consulta SQL """
        res = self.query2(sql)
        try:
            valor = res[0][0]
        except:
            valor = default
        return valor

    def execute(self, sql):
        """ consultas de accion """
        if self.isConnected == False or len(self.ErrMsg)>0: return False
        if len(sql) == 0: return False
        try:
            cur = self.conn.cursor()
            try:
                self.ErrMsg = ''
                cur.execute(sql)
                self.conn.commit()
                cur.close() # close the cursor and connection
                #self.__SQLList_add(sql)
                return True
            except Exception, f:
                self.ErrMsg = 'Error al ejecutar SQL ' + nl + str(f)
                return False
        except Exception, e:
            self.ErrMsg = 'Error al iniciar cursor!' + nl + str(e)
            return False

    # Trabajando con Lista de SQL realizadas
    def __SQLList_add(self, qsql):
        """ La consulta SQL se ha realizado con exito, y la guardo en el listado """
        if len(qsql) > 0:
            if not (qsql in self.consultas):
                self.consultas.append(qsql)
            else:
                self.consultas.remove(qsql)  # La quito de donde esta
                self.consultas.append(qsql)  # Pero la agrego al final

    def SQLList_last(self):
        """ Devuelve la ultima SQL realizada """
        return self.consultas[-1]

    def SQLList(self):
        """ Devuelve la lista de consultas SQL realizadas con la conexion ABIERTA """
        return self.consultas

    def SQLList_empty(self):
        """ Vacia el contenido de consultas SQL """
        self.consultas = []

And of course, a small examples: connect to a MS Access database and show the records based on a SQL query. The code is also available on GitHub.


# coding: utf-8
""" Ejemplo de Conexion con MS Access """
miVersion = "Test de Conexion con MS Access"
nl = "\n"

from MSAccessConnector import *

database = "l:/sef_py2/sef2.8.mdb"
access = MSAccessConnector(database)
sql = "select * from equipos3 where equipo like 'd%'"

lista, error = access.query(sql)

if error:
print access.ErrMsg
else:
print "Encontrados %s equipos!!" % (len(lista))
for equipo in lista:
print equipo.equipo

And .. running:

Conectando Python con MS Access

Conectando Python con MS Access

If you got an error on Windows 7 when working with MS Access, here you can read how I fixed it!

I hope it helps you, and have a nice day!