martes, 23 de julio de 2024

Python (VIII): Accediendo a BD Access en Linux

 Damos créditos a pbdany

1. Instalar la libreria JayDeBeApi en el entorno virtual

# Activamos el entorno virtual (en mi caso es .venv)
source .venv/bin/activate

# Instalamos la librería
pip install JayDeBeApi 


2. Descargar la librería UCanAccess 

Para ello vamos a sourceforge y la descargamos en una carpeta. En mi caso la he descargado en la carpeta "jar" dentro del proyecto de python. Hay que tener cuidado a la hora de definir las rutas a dichas librerias

En mi caso se ha descargado así


3. Descargarse Java y crear la variable JAVA_PATH

Nos descargamos Java Open JDK por ejemplo de OpenLogic  ( y yo personalmente he descargado la version 17 en "/home/ximo/jdk/jdk17/") 

En mi caso el ejecutable java es "/home/ximo/jdk/jdk17/bin/java"

y creamos el JAVA_PATH a dicha localización 

# Creamos la variable de entorno JAVA_PATH
export JAVA_PATH=/home/ximo/jdk/jdk17/bin

# Comprobamos su valor
echo $JAVA_PATH


4. Código fuente del programa python

Se va a convertir un fichero ACCESS a CSV.

Hay que tener en cuenta lo siguiente:

  1. Comprobar todas las rutas a los jars. si hay algún error en alguna de ellas, dará un error como que no encuentra alguna librería para abrir dicho fichero de BD
  2. Dar correctamente los nombres de los ficheros de entrada (tipo mdb) como los de salida (tipo csv)
  3. Dar el nombre de tabla o vista correcto al pasar la sentencia SQL al cursor.
  4. Configurar el csv.writer para definirle el delimitador (en mi caso ";") y si queremos entrecomillar los campos de caracteres.
  5. Utilizar convenientement el csv.writer para escribir títulos y filas

import jaydebeapi
import sys
import os
import csv


# Access DB file
DBFile='/home/ximo/Baixades/EMCO_09_2024_0000000008.mdb'

# CSV output file
CSVFile='/home/ximo/Baixades/DATOS_PERS.csv'


# Initiate Java runtime file location
UCanVer='5.0.1'
lang3Ver='3.8.1'
logVer='1.2'
hsqlVer='2.5.0'
jackVer='3.0.1'

# Cpnfigure path for jar files
configPath = sys.path[0] + os.sep+".."+os.sep+'jars' + os.sep + 'UCanAccess-'+ UCanVer +os.sep
ucanaccess_jars = [
configPath+"ucanaccess-" +UCanVer +".jar",
configPath+"lib/commons-lang3-" +lang3Ver+".jar",
configPath+"lib/commons-logging-"+logVer +".jar",
configPath+"lib/hsqldb-" +hsqlVer +".jar",
configPath+"lib/jackcess-" +jackVer +".jar",
]

# classpath = $PATH$ parameters for Java runtime file location
classpath = ":".join(ucanaccess_jars)

# Initate connection to MS Access files
cnxn = jaydebeapi.connect(
"net.ucanaccess.jdbc.UcanaccessDriver",
"jdbc:ucanaccess://"+DBFile,
["", ""],
classpath
)

# From connection initiate cursor
cursor = cnxn.cursor()

# Run Query
cursor.execute("SELECT * FROM DATOS_PERS")
fieldNames= ",".join([i[0] for i in cursor.description])
with open(CSVFile,'w') as f:
writer = csv.writer(f,dialect='excel',delimiter=';',doublequote=True,quoting=csv.QUOTE_NONNUMERIC)
# Generamos cabecera de nombres de campos
    writer.writerow([i[0] for i in cursor.description])
# Generamos las filas de datos
writer.writerows(row for row in cursor.fetchall())

# Fetch Query result
#for row in cursor.fetchall():
# print(row)

# Close cursor
cursor.close()
# Close connection
cnxn.close()





jueves, 11 de julio de 2024

Python (VII): sqlite con regexp. Definición de funciones en SQLITE

1. Regexp con SQLITE 

Según aGueGu en stackoverflow podemos hacer búsquedas en sqlite y Python así


import sqlite3
import re

# Definimos una función con 2 parámetros 
def match(expr, item):
    return re.match(expr, item) is not None

conn = sqlite3.connect(':memory:')

#Le pasamos esta función y le indicamos que tiene 2 parámetros
conn.create_function("MATCHES", 2, match)
cursor = conn.cursor()
cursor.execute("SELECT MATCHES('^b', 'busy');")
print (cursor.fetchone()[0])

cursor.close()
conn.close()


2. Definición de funciones en SQLITE

En el apartado anterior hemos definido la función MATCHES, que usa regexp, ahora vamos a definir la función split de python donde le indicamos el delimitador. Pero a pesar que en geeksforgeeks.org dice que funciona, a mi no me funciona pues no deja que un campo sea tipo list, tupla o array!!!!!


import sqlite3

# Definimos una función con 2 parámetros 
def split_str(delimitedText, delimiter=','):
    return delimitedText.split(delimiter)


#Nos conectamos a sqlite, en este caso en memoria (sin fichero)
conn = sqlite3.connect(':memory:') #Le pasamos esta función y le indicamos que tiene 2 parámetros conn.create_function("SPLIT", 2, split_str)
cursor = conn.cursor() cursor.execute("SELECT SPLIT('Pepe;Juan;Ignacio', ';');")
print (cursor.fetchone()[0]) #FALLA!!!! cursor.close() conn.close()