sqlite

Agregar columna a tabla si no existe en SQLite3 con Golang

En el tutorial de hoy te mostraré una pequeña función que te permite agregar una columna a una tabla solo si la misma no existe.

El motor de base de datos que vamos a usar será SQLite3 pero me imagino que debe funcionar para otros como PostgreSQL o MySQL.

Esto es necesario porque en ocasiones el cliente no puede hacer los cambios a la base de datos (no puede ejecutar sentencias SQL) y además se desean conservar los datos ya existentes.

Por ello es que hoy veremos cómo agregar una columna a una tabla conservando sus datos, y agregarla solo si no existe, verificando la tabla con PRAGMA en SQLite3.

La salida de PRAGMA table_info

Podemos consultar los detalles de una tabla de SQLite3 con PRAGMA. Para ello la sintaxis es:

PRAGMA table_info("nombre_de_la_tabla")

Eso será como hacer una consulta normal, pero ahora en lugar de datos traerá información de la tabla. La salida es algo así:

cid|name|type|notnull|dflt_value|pk
"0" "id" "integer" "0"  "1"
"1" "id_grupo" "integer" "0"  "0"
"2" "nombre" "text" "1"  "0"
"3" "direccion" "text" "1"  "0"
"4" "genero" "text" "1"  "0"
"5" "edad" "integer" "1"  "0"
"6" "nombre_tutor" "text" "1"  "0"
"7" "numero_tutor" "text" "1"  "0"

Como puedes ver, en la columna name tenemos cada columna existente en la tabla. Entonces con esto ya podemos saber si la columna existe en la tabla, y si no existe entonces la creamos.

Leyendo información de columnas existentes en tabla de SQLite3

Entonces podemos conectar a la base de datos y hacer una consulta, luego iterar las columnas y comparar si existe esa columna para crearla en caso de que no.

Todo eso lo he encerrado en una función de Golang, aunque obviamente tú puedes usar cualquier otro lenguaje de programación:

func existeColumnaEnTabla(tabla string, columna string) (bool, error) {
 bd, err := obtenerBaseDeDatos()
 if err != nil {
  return false, err
 }
 defer bd.Close()
 filas, err := bd.Query(`PRAGMA table_info("` + tabla + `")`)
 /*
  Lo de PRAGMA regresa algo así:
  cid|name|type|notnull|dflt_value|pk
  "0" "id" "integer" "0"  "1"
  "1" "id_grupo" "integer" "0"  "0"
  "2" "nombre" "text" "1"  "0"
  "3" "direccion" "text" "1"  "0"
  "4" "genero" "text" "1"  "0"
  "5" "edad" "integer" "1"  "0"
  "6" "nombre_tutor" "text" "1"  "0"
  "7" "numero_tutor" "text" "1"  "0"
 */ if err != nil {
  return false, err
 }
 defer filas.Close()
 var cid string
 var name string
 var _type string // Con _ porque "type" es reservada
 var notnull string
 var dflt_value *string // Apuntador porque puede ser nulo, igual no no importa
 var pk string

 for filas.Next() {
  err := filas.Scan(&cid, &name, &_type, &notnull, &dflt_value, &pk)
  if err != nil {
   return false, err
  }
  if name == columna {
   return true, nil
  }
 }
 return false, nil
}

Nota: ten cuidado con el nombre de la tabla, pues se podría hacer una inyección SQL. Yo la he dejado así porque el usuario no tiene acceso a esa función, solo el programador.

Entonces esa función nos devolverá un booleano que nos dirá si existe esa columna. Los demás datos no nos interesan pero igualmente los leemos para que el compilador no se queje.

Crear columna solo si no existe

Con lo mostrado anteriormente ya podemos crear cualquier columna en cualquier tabla de SQLite3 usando Golang.

Recuerda que para agregar una columna usamos ALTER TABLE y colocamos un DEFAULT para que los datos se conserven. Por ejemplo tenemos la agregación de la columna curp a la tabla de alumnos:

func crearCurpSiNoExiste() error {
 existeCurp, err := existeColumnaEnTabla("alumnos", "curp")
 if err != nil {
  return err
 }
 if existeCurp {
  // Si ya existe no es necesario continuar
  return nil
 }
 bd, err := obtenerBaseDeDatos()
 if err != nil {
  return err
 }
 defer bd.Close()
 _, err = bd.Exec(`ALTER TABLE alumnos ADD curp TEXT NOT NULL DEFAULT "";`)
 return err
}

Compruebo si existe, y en caso de que no, ejecuto un ALTER TABLE a la base de datos. De este modo no importa cuántas veces se invoque a esta función pues la columna se va a crear únicamente la primera vez, haciendo una “migración” de la base de datos automáticamente.

Por aquí te dejo más tutoriales de SQLite3 y Go.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Entradas recientes

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

3 días hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

3 días hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

3 días hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

3 días hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

3 días hace

Solución: Apache – Server unable to read htaccess file

Ayer estaba editando unos archivos que son servidos con el servidor Apache y al visitarlos…

3 días hace

Esta web usa cookies.