Tecnolack - blog de cultura geek

Bash Script: conectarse a DB2 y hacer un reporte

account_circle Por Sagara access_time 21 de junio del 2013

ibm-db2

  • Vamos a crear un Bash Script que se conecte localmente a una base de datos DB2 y envié un reporte vía email

Veamos el siguiente escenario: una universidad esta capturando inasistencias por materia de los alumnos de primer año. Por políticas universitarias la tolerancia máxima es de tres faltas y cuatro en algunas materias. El requerimiento podría ser mandar un reporte semanal al asesor con el total de candidatos por materia que están por alcanzar el máximo de faltas hasta el momento.

Empecemos con un ejemplo de una tabla que esta guardando inasistencias de estudiantes por materia:

"ALUMNO_ID" BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY (
 ...
 ... )
"MATERIA" VARCHAR(10000) NOT NULL ,
"INASISTENCIA" INTEGER NOT NULL ,
 ...
 

Ejecutar queries en DB2

Primero vamos a crear la función que ejecute SQL queries en la base de datos, los guarde en un archivo de texto y la mandamos llamar con unos cuantos ejemplos:

#!/bin/bash

_file="reportCandidates2fail.txt"

_db="UNIVERSITY_DB"
_table="STUDENTS_ABSENCES"

# Funcion para ejecutar sql queries en db2
# necesita dos parametros: SQL ("$1") y MATERIA ("$2")
function runQuery(){
        query=$(db2 -x "$1")
        EXIT_CODE=$?

        if [ $EXIT_CODE -ne 0 ] ; then
                echo "Error : $query"
        else
                echo "$2, $query" >> ${_file}
        fi
}

# Connect to the database
db2 connect to $_db

_SQL="SELECT COUNT(*) FROM ${_table} WHERE MATERIA='MATEMATICAS' AND INASISTENCIA=2"
runQuery "${_SQL}" "MATEMATICAS"

_SQL2="SELECT COUNT(*) FROM ${_table} WHERE MATERIA='REDES' AND INASISTENCIA=2"
runQuery "${_SQL2}" "REDES"

_SQL3="SELECT COUNT(*) FROM ${_table} WHERE MATERIA='DEPORTE' AND INASISTENCIA=3"
runQuery "${_SQL3}" "DEPORTE"

#SQL here
#SQL here
#And more funny SQL here

 

Arrays y loops

Para ahorrarnos lineas de código y no tener que estar escribiendo un SQL por por cada materia vamos a hacer unos arreglos y unos ciclos:

#!/bin/bash

_file="reportCandidates2fail.txt"

_db="UNIVERSITY_DB"
_table="STUDENTS_ABSENCES"

# Arrays of 3 and 4 absences 
_4absencesClass=('DEPORTE' 'CULTURA' 'ETICA' );
_3absencesClass=('MATEMATICAS' 'PROGRAMACION' 'BD' 'REDES' 'SO');


# Funcion para ejecutar sql queries en db2
# necesita dos parametros: SQL ("$1") y MATERIA ("$2")
function runQuery(){
        query=$(db2 -x "$1")
        EXIT_CODE=$?

        if [ $EXIT_CODE -ne 0 ] ; then
                echo "Error : $query"
        else
                echo "$2, $query" >> ${_file}
        fi
}

# Connect to the database
db2 connect to $_db

# 4 absences classes 
for x in "${_4absencesClass[@]}"; do
        _sql="SELECT COUNT(*) FROM ${_table} WHERE MATERIA=${x} AND INASISTENCIA=3"
        runQuery "$_sql" "$x"
done

# 3 absences classes
for y in "${_3absencesClass[@]}"; do
        _sql="SELECT COUNT(*) FROM ${_table} WHERE MATERIA=${y} AND INASISTENCIA=2"
        runQuery "$_sql" "$y"
done

 

Mail

Ahora nomas agregamos la siguiente linea al final del script para mandar el correo, siempre es bueno ponernos en bcc para saber si se mando correctamente:

# mail id
_mail="tutor@universidad.com"
_mailAdmin="sagara@tecnolack.com"

# mail notification
cat ${_file} | mail -s "$Candidatos a fallar la materia" -b $_mailAdmin $_mail
 

Contador

También podemos agregarle un contador, para notificar el numero total de estudiantes en esta situación:

# Counter function to display total of candidates documents
function getTotal(){
        _total=$(expr $_total + $1)
}

# to call the counter
# getTotal NUMBER
 

Versión final

El contador lo mandamos llamar cada vez que ejecutemos un query, dentro de la función runQuery lo veo mas practico y fácil. La versión final del código podría ser así ya con unos detalles incluidos, como documentar el script para que alguien que lo vea entienda que hace:

#!/bin/bash
#
# ################################################
#
# Simple bash script to create a report with total 
# of candidates to fail each class
# Usage: sh runReports.sh
# Version: 1.0 Date: 20-June-2013
#
# Contact: sagara@tecnolack.com
#
# ################################################

_now=$(date +"%m_%d_%Y")
_file="reportCandidates2fail_${_now}.txt"
# mail id
_mail="tutor@universidad.com"
_mailAdmin="sagara@tecnolack.com"

_db="UNIVERSITY_DB"
_table="STUDENTS_ABSENCES"

# Arrays of 3 and 4 absences 
_4absencesClass=('DEPORTE' 'CULTURA' 'ETICA' );
_3absencesClass=('MATEMATICAS' 'PROGRAMACION' 'BD' 'REDES' 'SO');

# Counter function to display total of candidates 
function getTotal(){
        _total=$(expr $_total + $1)
}

# Funcion para ejecutar sql queries en db2
# necesita dos parametros: SQL ("$1") y MATERIA ("$2")
function runQuery(){
        query=$(db2 -x "$1")
        EXIT_CODE=$?

        if [ $EXIT_CODE -ne 0 ] ; then
                echo "Error : $query"
        else
                echo "$2, $query" >> ${_file}
                getTotal "$query"
        fi
}

# Header to report file
echo "MATERIA, COUNT" > ${_file}

# Connect to the database
db2 connect to $_db

# 4 absences classes 
for x in "${_4absencesClass[@]}"; do
        _sql="SELECT COUNT(*) FROM ${_table} WHERE MATERIA=${x} AND INASISTENCIA=3"
        runQuery "$_sql" "$x"
done

# 3 absences classes
for y in "${_3absencesClass[@]}"; do
        _sql="SELECT COUNT(*) FROM ${_table} WHERE MATERIA=${y} AND INASISTENCIA=2"
        runQuery "$_sql" "$y"
done


# mail notification
cat ${_file} | mail -s "${_total} candidatos a fallar la materia" -b $_mailAdmin $_mail

Para terminar agregamos «${_total}» en el subject del correo. No hace falta mencionar que los archivos o logs seguirán siendo almacenados en el directorio actual con la nomenclatura: «reportCandidates2fail_MM_DD_YYYY.txt» (e.g. reportCandidates2fail_06_20_2013.txt).

Le damos permisos de ejecución y lo ejecutamos:

chmod +x runReports.sh
sh runReports.sh

Listo. Espero les sea de utilidad.

Documentación | IBM

@Mail
Recibe actualizaciones vía email.