MySQL ya no es completamente libre. Sólo era un producto libre, no un proyecto. Sin embargo aun nos queda Drizzle.
Category: MySQL
Hace ya unos años estoy trabajando fuertemente con Drupal 6, sólo hace unas semanas he empezado a usar la versión 7 y me parece un avance excelente. Poco a poco estaré publicando información relacionada a Drupal.
Instalando Drupal 7 bajo Windows y Apache he encontrado que no me da la opción de usar MySQL:
Esto es porque ahora Drupal 7 tiene como requerimiento el uso de la extensión PDO, además que requiere MySQL 5.015 o mayor.
Para solucionarlo, sólo debemos abrir el archivo php.ini
, buscar y descomentar las líneas que permiten el uso de estas extensiones:
;extension=php_openssl.dll
extension=php_pdo.dll
;extension=php_pdo_firebird.dll
;extension=php_pdo_mssql.dll
extension=php_pdo_mysql.dll
Reiniciamos Apache y listo:
Es posible que tengas algunos otros errores, si es así, los comentarios están abiertos
Reiniciar auto_increment cada año en MySQL
Alguna vez vamos a necesitar reiniciar el contador del auto_increment cada año. Por ejemplo si tenemos una tabla recibos
quisieramos que el número de recibo empieze desde 1 el año siguiente.
Para esto hay un pequeño artificio en MySQL que nos puede ayudar:
`anio` year(4) NOT NULL,
`ID` int(5) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`anio`,`ID`)
) ENGINE=MyISAM;
El truco está en que el campo primario debe ser la composición de dos campos; donde la columna con AUTO_INCREMENT
es la segunda columna del índice.
INSERT INTO `recibos` (`anio`) VALUES ('2010'), ('2010'), ('2010'), ('2011'), ('2011');
/* Mostramos los datos */
SELECT * FROM `recibos`;
El resultado sería:
| anio | ID |
+------+----+
| 2010 | 1 |
| 2010 | 2 |
| 2010 | 3 |
| 2011 | 1 |
| 2011 | 2 |
+------+----+
La limitación es que este tipo artificio sólo funciona en tablas del tipo MyISAM.
En general prefiero realizar los backups desde scripts, pero muchas veces esta tarea se debe realizar desde la misma aplicación. Algo a tomar muy en cuenta si opta por este camino, es que los backups -- en lo posible -- deben ser generados con las herramientas que el motor de base de datos trae para este fin.
En los ejemplos se muestra el uso de mysqldump
y la clase Process, que según MSDN proporciona acceso a procesos locales y remotos, y permite iniciar y detener procesos del sistema local
:
{
ProcessStartInfo psi = new ProcessStartInfo(ConfigurationManager.AppSettings["MysqlDump"], args);
string filename = Path.Combine(workingDir, DateTime.Now.ToString(@"yyyy-MM-dd.\sql"));
using (StreamWriter writer = new StreamWriter(filename, false, Encoding.UTF8))
{
using(Process process = new Process())
{
psi.CreateNoWindow = true; // Evita que el proceso se inicie en una nueva ventana.
psi.UseShellExecute = false; // Evita que se use el shell del sistema operativo para iniciar el proceso.
psi.RedirectStandardOutput = true; // Escribir la salida en Process.StandarOuput
psi.StandardOutputEncoding = Encoding.UTF8; // Codificación de los datos de salida
process.StartInfo = psi;
process.OutputDataReceived += delegate(object sender, DataReceivedEventArgs e)
{
writer.WriteLine(e.Data);
};
process.Start();
process.BeginOutputReadLine(); // Lectura asincrónica del stream de salida
process.WaitForExit(); // Esperar a que el proceso termine.
}
}
}
Aunque en el código mostrado es más sencillo realizar algún proceso sobre los datos generados, hay que tener muy en cuenta la codificación de los datos en los backups, puesto que por un descuido se puede generar fácilmente basura.
Si se quiere evitar estos problemas de codificación, se podría usar algo como:
{
string filename = Path.Combine(workingDir, DateTime.Now.ToString(@"yyyy-MM-dd.\sql"));
ProcessStartInfo psi = new ProcessStartInfo("cmd.exe",
string.Format("/c \"\"{0}\" {1} > \"{2}\"\"",
ConfigurationManager.AppSettings["MysqlDump"], args,
filename));
psi.CreateNoWindow = true;
psi.UseShellExecute = false;
using (Process process = new Process())
{
process.StartInfo = psi;
process.Start();
process.WaitForExit();
}
}
En fin, usar uno u otro método va a depender de los requerimientos de la aplicación.
Antes que nada, un poco de teoría sobre conjuntos de caracteres (charset) y colaciones (collations):
Un conjunto de caracteres es un
conjunto de símbolos y codificaciones. Una
colación es un conjunto de
reglas para comparar caracteres en un conjunto de caracteres.
Vamos a dejar clara la distinción con un ejemplo de un conjunto
de caracteres imaginario.Supongamos que tenemos un alfabeto con cuatro letras:
'A
', 'B
',
'a
', 'b
'. Damos a cada letra
un número: 'A
' = 0, 'B
' =
1, 'a
' = 2, 'b
' = 3. La
letra 'A
' es un símbolo, el número 0 es la
codificación para
'A
', y la combinación de las cuatro letras y
sus codificaciones es un conjunto de
caracteres.Suponga que queremos comparar dos cadenas de caracteres,
'A
' y 'B
'. La forma más
fácil de hacerlo es mirar las codificaciones: 0 para
'A
' y 1 para 'B
'. Ya que 0
es menor a 1, decimos que 'A
' es menor que
'B
'. Lo que acabamos de hacer es aplicar una
colación a un conjunto de caracteres. La colación es un conjunto
de reglas (sólo una en este caso): “compara las
codificaciones”. LLamamos a la más sencilla de todas las
colaciones una colación binaria.Pero, ¿qué pasa si queremos decir que las letras en mayúsculas
y minúsculas son equivalentes? Entonces tendríamos como mínimo
dos reglas: (1) tratar las letras minúsuclas
'a
' y 'b
' como equivalentes
a 'A
' y 'B
'; (2) luego
comparar las codificaciones. Llamamos a esto una colación
no sensible a mayúsuculas y minúsculas
(case-insensitive). Es un poco más compleja que una
colación binaria.
La forma más sencilla de que las comparaciones que se hacen sobre determinados campos distingan entre mayúsculas y minúsculas, es definir una colación binaria para éstas.
nick varchar(20) COLLATE utf8_bin,
name varchar(200)
) DEFAULT CHARACTER SET utf8 COLLATE utf8_spanish_ci
Query OK, 1 row affected (0.00 sec)
mysql> select nick from users where nick='alex';
+------+
| nick |
+------+
| alex |
+------+
1 row in set (0.00 sec)
mysql> select nick from users where nick='aleX';
Empty set (0.00 sec)
Pero existe un pequeño detalle con esa alternativa, porque por un motivo que desconozco, los espacios que existen en la parte de la derecha no son tomados en cuenta, es decir:
+------+
| nick |
+------+
| alex |
+------+
1 row in set (0.00 sec)
Para evitar este comportamiento en columnas que tengan o no colación binaria, se puede hacer uso del operador BINARY.
/*
De acuerdo a los comentarios de http://dev.mysql.com/doc/refman/5.0/en/charset-binary-op.html,
la siguiente consulta es mejor para los índices sean usados.
*/
SELECT nick FROM users WHERE nick = BINARY 'alex ';
Empty set (0.00 sec)
Debido a mi falta de conocimiento e interés en MySQL, es posible que en esta entrada -- inspirada en un bug de una aplicación que estoy desarrollando -- haya cometido más errores de los que normalmente cometo :). Tienen los comentarios abiertos por si quieren insultarme corregirme o aportar más información. 😉