Arma SQL
Cansado de lidiar con el armado de instrucciones de SQL con argumentos
variables, se me ocurrió hacer una función para manejarlo. Originalmente se
llamaba ArmaSql, estaba en Visual Basic, lo que me tocaba en ese
momento y funcionaba sobre MS-SQL. La versión más reciente está en PHP y
funciona sobre MySql y como la puse en algún foro en inglés por ahí, se llama
BuildSql(). Con muy pocos cambios se puede adaptar a cualquier otra base de datos, pero
no me ha tocado hacerlo.
Creo que lo más molesto es el manejo de las fechas y los cadenas nulos. Andar
dando vuelta a las fechas para que queden bien en el formato aceptado por la
base de datos y manejar la alternativa de que tanto una fecha o una cadena
pueda ser nulo siempre me dio dolor de cabeza, pues me ha ocurrido de insertar
inadvertidamente el texto 'null' en lugar del valor
null (sin comillas).
Hice entonces esta función que es una suerte de
sprintf()
orientado a SQL. El problema que se me presentaba con
sprintf()
era el de los valores en null, especialmente cadenas de
caracteres y fechas, pues en el string de formato de
sprintf()
ya ponía las comillas y si la variable estaba en
null, terminaba escribiendo el texto 'null' en la
base de datos.
sprintf()
no sabe que cuando el valor es null no debe incluir las comillas.
Yo uso mucho el valor null en la base de datos, significa `no sé´
o `no hay´, indica la falta de un dato. Otros prefieren usar un valor
convenido para indicar lo mismo, por ejemplo, cadenas vacías o importes en
cero o negativos o alguna otra convención arbitraria que, en mi opinión es
innecesaria pues SQL ya tiene previsto el valor null para eso. Es
por ello que el null me preocupa tanto.
Entonces, al igual que
sprintf(), la función
BuildSql()
acepta un primer argumento que es el modelo de la instrucción de SQL a armar y
luego una cantidad variable de argumentos cuyos valores serán insertados en la
primer cadena con el formato que le corresponda a cada uno. El lugar de
inserción de los valores va indicado por un signo de interrogación seguido de
varios modificadores, según se indica:
?[nn][m]t
Donde:
nn: opcional, indica la posición del argumento dentro de la lista de
argumentos. El argumento 0 es el modelo de la instrucción misma y no tiene
sentido usarlo. Si no se indica los argumentos se irán insertando
secuencialmente según aparecen. Cuando se indica el número de argumento a
usar, el puntero secuencial de argumentos no se incrementa.
m: opcional, puede ser una de dos opciones:
m: el argumento es obligatorio (en inglés: mandatory) el argumento no puede sernull. Dará error si lo fuera.
n: convertir a null si el argumento fuera 0 o una cadena vacía.
t: este es el único modificador obligatorio e indica el tipo del
argumento, que puede ser cualquiera de los siguientes:
s: string
i: integer
f: float
d: date, datetime, timestamp
t: time
b: boolean
p: prefijo
Todos estos modificadores pueden darse tanto en mayúsculas como en minúsculas. Lo mínimo requerido es el signo de interrogación seguido de una descripción del tipo de datos. En el caso de que el tipo de dato requiriera encerrar el valor entre comillas, la función las proveerá. No hay previsión para insertar un signo de interrogación en la salida pues, como es un carácter inválido en SQL, no tiene sentido, pero no hay problema en que cualquiera de los argumentos lo contenga.
El tipo de datos `p` es especial en cuanto a que no representa un
argumento sino el contenido de la variable
$table_prefix. Dependiendo del servicio contratado con un
proveedor de internet, es posible disponer de ilimitadas bases de datos o un
número limitado, en ocasiones una sola. En ese caso, es necesario llamar a
cada tabla con un prefijo que indique a qué aplicación corresponde. El
modificador p permite agregar automáticamente ese prefijo, tomándola de la
variable global $table_prefix (un nombre arbitrario que puede
cambiarse a gusto) supuestamente leído de la configuración de la aplicación.
La función está comentada en el fuente e incluye un ejemplo.
Esta función se complementa con ReadSqlDate(), más abajo en el
mismo
fuente
que permite convertir una fecha, fecha-hora o
timestamp al formato interno de PHP. Yo nunca he usado el tipo de
dato time de SQL, por lo que no he previsto una función equivalente para ese
tipo de dato. Vale la pena que advierta a quien quiera hacerlo que la función
mktime(), cuando no se le dan los argumentos mes, día y año, no los supone cero sino
que toma los valores actuales, por lo que al convertirlo, se deberá usar:
mktime($hora,$minuto,$segundos) - $mktime(0,0,0)
y no simplemente:
mktime($hora,$minuto,$segundos)