jueves, marzo 25, 2010

Construcción masiva de consultas SQL desde una consulta SQL

Nota: Como ha sido habitual desde mis últimos artículos, y para que los que misteriosamente me leen sigan creyendo que trabajo en mis horas laborales comprendan lo difícil de las labores que desempeño, he aquí otro problema técnico y su correspondiente solución.
Nuevamente, si no le interesa el tema, simplemente pase a saludar, y será retribuido con mi eterno agradecimiento temporal.

Supuesto a priori: El lector tienen mediano entendimiento y nociones de SQL.

Problema: Se tiene cierta información distribuida en 2 tablas distintas dentro de una base de datos y se desea hacer un cruce de esta, actualizando los datos de la tabla 1 con ciertos datos de la tabla 2.
En el caso particular de la problemática enfrentada, se tiene la codificación estándar de enfermedades y se desea agregar una sup-clasificación que permita agruparlas según ciertos criterios, también estandarizados.

Solución: Lo más lógico sería hacer un update utilizando los datos de un select. El problema es que la consulta arroja más de un resultado.
Por ello se debe recurrir a la segunda opción, que es construir los updates necesarios a partir de los resultados del select que entrega la información que se va a actualizar.

Para ello:
  1. Rescatar la información desde las tablas correspondientes hacia un archivo, ejecutando:
    psql -h servidorbasedatos -U usuariobasedatos basedatos -c 'select tipodiagnostico.idtipodiagnostico, care_icd10_bg.diagnosis_code from care_icd10_bg, tipodiagnostico where substring(care_icd10_bg.diagnosis_code, 1, 3) between tipodiagnostico.rangoini and tipodiagnostico.rangofin' -t > archivo_resultados.txt
    Notar la sutilezas:
    • -c indica al comando psql que ejecute la consulta SQL escrita entre las comillas simples.
    • -t indica que el resultado de la ejecución sea presentado sin las cabeceras que indican los nombres de las columnas involucradas.
    • Dentro de la consulta la llamada a la función substring se asegura que los códigos de diagnóstico se encuentren dentro de los rangos expresados en la tabla tipodiagnostico. Al respecto, los códigos de diagnóstico se representan con 3 caracteres . Hay casos particulares en que este código va precedido por un punto y otro código numérico, o un signo de suma, o un asterisco. dado que los rangos están expresados sólo en 3 caracteres, es necesario usar la función substring.
  2. Construir los updates que sea necesario ejecutar. Para ello se debe ejecutar el toxi-comando:
    cat archivo_resultados.txt | awk -v q="'" -F'|' '{ gsub(/[[:space:]]*/,"",$1); gsub(/[[:space:]]*/,"",$2); print "update care_icd10_bg set type =", q $1 q, " where diagnosis_code=", q $2 q, "\;" }' > archivo_consultas.sql
    Las sutilezas de esta maravilla de la concatenación y del copiar-pegar:
    • -v q="'" le indica al comando awk que el caracter comilla simple (que tantos dolores de cabeza nos da cuando lo queremos usar dentro del awk), sea representado por una q. La otra solución es usar \x27 como caracter al escribirla, pero al menos a mi me resulta más clara la q.
    • -F'|' le indica al comando awk que el caracter pipe (|) es el separador de campos, para cada línea a procesar. Esto es debido a que la salida del comando psql entrega resultados como:
      207 | A01
      207 | A01.0
      207 | A01.1
    • Dentro de la secuencia de instrucciones awk, la función gsub(/[[:space:]]*/,"",$1); aplicada sobre $1 y $2 se encargará de eliminar los espacios sobrantes en $1 y $2 (207 y A01 en el ejemplo).
    El resultado de la ejecución de este comando es algo como:
    update care_icd10_bg set type = '207' where diagnosis_code= 'A01' ;
    update care_icd10_bg set type = '207' where diagnosis_code= 'A01.0' ;
    update care_icd10_bg set type = '207' where diagnosis_code= 'A01.1' ;
  3. Ejecutar la consultas recién creadas, ejecutando:
    psql -h servidorbasedatos -U usuariobasedatos basedatos -f archivo_consultas.sql
  4. Y esperar. Utilizando la base de datos de códigos de diagnósticos de http://www.care2x.com/ , se deben actualizar del orden de 13 mil registros lo que en una máquina medianamente actualizada (Athlon x64, 4GB de RAM) se demora alrededor de 2 minutos.

Y eso sería. Que les vaya bonito.

No hay comentarios.: