Uploaded by juanbussines

INF424 MySQL tutorial es

advertisement
Capítulo 3. Curso (tutorial) de MySQL
Tabla de contenidos
3.1. Conectarse al y desconectarse del servidor .............................................................................. 161
3.2. Entrar consultas ....................................................................................................................... 162
3.3. Crear y utilizar una base de datos ............................................................................................ 165
3.3.1. Crear y seleccionar una base de datos .......................................................................... 166
3.3.2. Crear una tabla ............................................................................................................. 167
3.3.3. Cargar datos en una tabla ............................................................................................. 168
3.3.4. Extraer información de una tabla ................................................................................... 170
3.4. Obtener información sobre bases de datos y tablas ................................................................... 183
3.5. Usar mysql en modo batch ..................................................................................................... 184
3.6. Ejemplos de consultas comunes ............................................................................................... 185
3.6.1. El valor máximo de una columna ................................................................................... 186
3.6.2. El registro que tiene el valor máximo de determinada columna ........................................ 186
3.6.3. Máximo de columna por grupo ...................................................................................... 186
3.6.4. Los registros de un grupo que tienen el máximo valor en alguna columna ........................ 186
3.6.5. Utilización de variables de usuario ................................................................................. 187
3.6.6. Usar claves foráneas (foreign keys) ............................................................................... 187
3.6.7. Buscar usando dos claves ............................................................................................. 189
3.6.8. Calcular visitas diarias ................................................................................................... 189
3.6.9. Utilización de AUTO_INCREMENT ................................................................................... 189
3.7. Consultas del proyecto Mellizos (Twin) ..................................................................................... 191
3.7.1. Encontrar todos los mellizos no repartidos ..................................................................... 191
3.7.2. Mostrar una tabla de estado de mellizos ........................................................................ 193
3.8. Usar MySQL con Apache ......................................................................................................... 194
Este capítulo le brinda una introducción de aprendizaje a MySQL, a través del uso de mysql, el programa
cliente de MySQL para crear y utilizar una base de datos simple. mysql (a veces denominado “monitor
de terminal” o solamente “monitor”) es un programa interactivo que le permite conectarse a un servidor de
bases de datos MySQL, ejecutar consultas, y ver los resultados. mysql puede usarse también en modo
por lotes: se colocan las consultas en un archivo previamente armado, y se le dice a mysql que ejecute el
contenido del archivo. En este capítulo se tratan ambas formas de uso.
Para ver una lista de las opciones utilizadas con mysql, ejecútelo con la opción --help:
shell> mysql --help
Este capítulo asume que mysql está instalado en el ordenador y que está disponible un servidor MySQL
al cual conectarse. Si no es así, consulte con su administrador MySQL. (Si Usted es el administrador,
necesitará consultar otras secciones de este manual).
Se describe el proceso de configurar y utilizar una base de datos. Si sólo le interesa acceder a una base
de datos existente, es posible que quiera omitir las secciones que muestran cómo crear una base de datos
y las tablas que contiene.
Dado que este capítulo es una guía de aprendizaje, muchos detalles son necesariamente omitidos. Para
información detallada sobre los temas que se tratan, consulte las secciones relevantes del manual.
3.1. Conectarse al y desconectarse del servidor
161
Entrar consultas
Para conectarse al servidor, generalmente se le porporcionará a mysql un nombre de usuario y una
contraseña. Si el servidor se está ejecutando en un ordenador distinto a donde está estableciendo la
conexión, también se deberá especificar el nombre de host. Consulte con su administrador para saber los
parámetros de conexión (nombre de usuario, contraseña y host) que debe emplear. Una vez que conozca
los parámetros apropiados, debería poder conectarse de este modo:
shell> mysql -h host -u user -p
Enter password: ********
host y user representan el nombre del ordenador donde se está ejecutando el servidor de bases de
datos MySQL y el nombre de usuario de la cuenta que se usará para conectarse. Reemplácelos por los
valores apropiados para elcaso. Los asteriscos (********) representan la contraseña, debe ingresarse
cuando mysql muestra Enter password:.
Si todo funciona bien, se verá una información de ingreso seguida por el prompt mysql>:
shell> mysql -h host -u user -p
Enter password: ********
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 25338 to server version: 5.0.9-beta-standard
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql>
El prompt anuncia que mysql está listo para procesar comandos.
Algunas instalaciones de MySQL permiten conectarse como usuario anónimo (sin nombre) si el servidor
se está ejecutando en el ordenador local. Si esto sucede en su caso, deberia poder conectarse al servidor
ejecutando mysql sin ningún parámetro:
shell> mysql
Después de haberse conectado, puede desconectarse en cualquier momento escribiendo QUIT (o \q) en
el prompt mysql>:
mysql> QUIT
Bye
En Unix, también puede desconectarse presionando Control-D.
La mayoría de los ejemplos en las secciones siguientes asumen que ya se ha conectado al servidor. Por
eso muestran el prompt mysql>.
3.2. Entrar consultas
Cerciórese de haberse conectado al servidor, tal como se describe en la sección anterior. Esto en sí
mismo no selecciona ninguna base de datos para trabajar. En este punto es más importante aprender
un poco más acerca de cómo realizar consultas que ir directamente a crear tablas, cargar datos, y
recuperarlos. Esta sección describe los principios básicos del ingreso de comandos, empleando varias
consultas que puede realizar para familiarizarse con la forma en que funciona mysql.
Aquí tiene un comando simple que ordena al servidor que muestre su número de versión y la fecha actual.
Ingréselo a continuación del prompt mysql> y presione Enter:
mysql> SELECT VERSION(), CURRENT_DATE;
+----------------+--------------+
| VERSION()
| CURRENT_DATE |
162
Entrar consultas
+----------------+--------------+
| 5.0.7-beta-Max | 2005-07-11
|
+----------------+--------------+
1 row in set (0.01 sec)
mysql>
Esta consulta le muestra varias cosas acerca de mysql:
• Un comando normalmente consiste en una sentencia SQL seguida de punto y coma. (Hay excepciones
donde el punto y coma puede omitirse. QUIT, mencionado anteriormente, es una de ellas. Luego
conocerá otras.)
• Cuando ingresa un comando, mysql lo envía al servidor para ser ejecutado e imprime los resultados. A
continuación muestra de nuevo el prompt mysql> para informarle que está listo para otro comando.
• mysql imprime los resultados de la consulta en forma tabulada (filas y columnas). La primera
fila contiene etiquetas para las columnas. Las filas siguientes son los resultados de la consulta.
Generalmente, el nombre de cada columna es el nombre del campo que trae desde la base de datos.
Si está trayendo el valor de una expresión, en lugar del contenido de un campo o columna de una tabla
(como en el ejemplo anterior), mysql etiqueta la columna usando el texto de la expresión.
• mysql informa cuántas filas fueron devueltas y cuánto tiempo le tomó ejecutarse a la consulta, lo cual
da una idea aproximada del rendimiento del servidor. Estos valores son imprecisos porque representan
tiempo de reloj corriente (no tiempo de CPU), y además porque están afectados por factores como la
carga del servidor o la latencia de red. (Para simplificar los ejemplos de este capitulo, a partir de ahora
no se mostrará la línea “rows in set”.)
Las palabras clave pueden ingresarse en cualquier combinación de minúsculas y mayúsculas. Las
siguientes consultas son equivalentes:
mysql> SELECT VERSION(), CURRENT_DATE;
mysql> select version(), current_date;
mysql> SeLeCt vErSiOn(), current_DATE;
Aqui tiene otra consulta que demuestra que mysql puede usarse como calculadora:
mysql> SELECT SIN(PI()/4), (4+1)*5;
+------------------+---------+
| SIN(PI()/4)
| (4+1)*5 |
+------------------+---------+
| 0.70710678118655 |
25 |
+------------------+---------+
1 row in set (0.02 sec)
Las consultas mostradas hasta ahora han sido relativamente cortas, sentencias de una sola línea. Se
puede inclusive ingresar múltiples sentencias en una misma línea. Solamente deben separarse con punto
y coma:
mysql> SELECT VERSION(); SELECT NOW();
+----------------+
| VERSION()
|
+----------------+
| 5.0.7-beta-Max |
+----------------+
1 row in set (0.00 sec)
+---------------------+
| NOW()
|
+---------------------+
| 2005-07-11 17:59:36 |
+---------------------+
163
Entrar consultas
1 row in set (0.00 sec)
No es necesario que un comando sea ingresado en una sola línea, de ese modo, comandos extensos
que requieren varias lineas no son un problema. mysql determina cuando una sentencia ha llegado a l
final observando si termina en un punto y coma, no si se llegó al final de la línea física. (En otras palabras,
mysql acepta un formato libre para las entradas: recolecta lineas pero no las ejecuta hasta que encuentra
el punto y coma.)
Aqui tiene una sentencia de múltiples líneas:
mysql> SELECT
-> USER()
-> ,
-> CURRENT_DATE;
+---------------+--------------+
| USER()
| CURRENT_DATE |
+---------------+--------------+
| jon@localhost | 2005-07-11
|
+---------------+--------------+
1 row in set (0.00 sec)
Observe en este ejemplo que el prompt cambia de mysql> a -> después que se ha ingresado la
primera línea de una consulta de múltiples líneas. Esta es la forma en que mysql advierte que no se
ha completado la sentencia y aún espera por el resto. El prompt es un aliado, puesto que suministra
información valiosa. Si se emplea, siempre se sabrá lo que mysql está esperando.
Si durante el ingreso de un comando decide que no quiere ejecutarlo, cancélelo tipeando \c:
mysql> SELECT
-> USER()
-> \c
mysql>
Una vez más observe el prompt. Cambia a mysql> después de que ingresa \c, informándole que mysql
está listo para un nuevo comando.
La siguiente tabla muestra cada uno de los indicadores que podrá ver y sintetiza lo que dicen acerca del
estado en que se encuentra mysql:
Prompt
Significado
mysql>
Listo para un nuevo comando.
->
Esperando la siguiente línea en un comando de múltiples líneas.
'>
Esperando la siguiente línea, se encuentra abierta una cadena que comienza con apostrofo
(''').
">
Esperando la siguiente línea, se encuentra abierta una cadena que comienza con comillas
dobles ('"').
`>
Esperando la siguiente línea, se encuentra abierta una cadena que comienza con tilde ('`').
/*>
Esperando la siguiente línea, se encuentra abierto un comentario que comienza con /*.
El prompt /*> fue introducido en la serie 5.0 a partir de MySQL 5.0.6.
Es frecuente que se origine una sentencia de múltiples lineas cuando accidentalmente le da entrada a un
comando de una sola línea pero olvida terminarlo con punto y coma. En ese caso, mysql aguarda por
más caracteres:
mysql> SELECT USER()
->
164
Crear y utilizar una base de datos
Si esto le ocurre (considera que ha ingresado una sentencia completa pero solamente obtiene un prompt
->), la mayoría de las veces es porque mysql está esperando por el punto y coma. Si no advierte lo que
el indicador trata de decirle, podría demorar un buen tiempo en hacer lo que necesita. Ingrese un punto y
coma para completar la sentencia, y mysql la ejecutará:
mysql> SELECT USER()
-> ;
+--------------------+
| USER()
|
+--------------------+
| joesmith@localhost |
+--------------------+
Los prompts '> y "> aparecen durante el ingreso de cadenas. Puede escribir cadenas delimitadas por
''' o '"' (por ejemplo, 'hola' o "adios"), y mysql le permite ingresar cadenas divididas en múltiples
líneas. Cuando ve un prompt '> o "> significa que ha comenzado a ingresar una cadena comenzando
con ''' o '"' pero no ha ingresado el correspondiente caracter de terminación. A menudo esto significa que
inadvertidamente omitió este carácter. Por ejemplo:
mysql> SELECT * FROM my_table WHERE name = 'Smith AND age < 30;
'>
Si ingresa esta sentencia SELECT, presiona ENTER y espera por el resultado, nada ocurrirá. En lugar de
asombrarse por el tiempo que consume la consulta, note lo que el prompt '> le está diciendo. Indica que
mysql espera por el final de una cadena inconclusa. (¿Ve el error en la sentencia? La cadena 'Smith no
tiene el apóstrofo de cierre.)
¿Qué hacer llegado a este punto? Lo más simple es cancelar el comando. No obstante, no puede
simplemente teclear \c en este caso, porque mysql interpretaría que es parte de la cadena que está
introduciendo. En lugar de eso, teclee el carácter de cierre que falta y entonces escriba \c.>:
mysql> SELECT * FROM my_table WHERE name = 'Smith AND age < 30;
'> '\c
mysql>
El prompt cambia de nuevo a mysql>, informando que mysql está listo para un nuevo comando.
El prompt `> es similar a '> y "> , pero informa que está pendiente de completar un identificador
delimitado por tildes.
Es importante conocer el significado de estos indicadores, ya que si por error se ingresa una cadena
incompleta, todo lo que se ingrese posteriormente será aparentemente ignorado por mysql — incluyendo
el comando QUIT. Esto puede ser sumamente desconcertante, en particular si no se conoce lo que debe
hacer para terminar la línea y cancelar el comando.
3.3. Crear y utilizar una base de datos
Una vez que se sabe la forma de ingresar comandos, es el momento de acceder a una base de datos.
Suponga que en su hogar posee varias mascotas y desea registrar distintos tipos de información sobre
ellas. Puede hacerlo si crea tablas para almacenar sus datos e introduce en ellas la información deseada.
Entonces, podrá responder una variedad de preguntas acerca de sus mascotas recuperando datos desde
las tablas. Esta sección le muestra como:
• Crear una base de datos
• Crear una tabla
• Introducir datos en la tabla
165
Crear y seleccionar una base de datos
• Recuperar datos desde la tabla de varias maneras
• Emplear múltiples tablas
La base de datos menagerie (palabra inglesa que en español significa "colección de animales") se ha
hecho deliberadamente simple, pero no es difícil imaginar situaciones del mundo real donde podría usarse
un tipo similar de base de datos. Por ejemplo, para un granjero que desee hacer el seguimiento de su
hacienda, o para los registros de los pacientes de un veterinario. En el sitio web de MySQL pueden
descargarse archivos de texto con datos de ejemplo y algunas de las sentencias empleadas en las
siguientes secciones. Se encuentran disponibles en formato tar (http://downloads.mysql.com/docs/
menagerie.tar.gz) y Zip (http://downloads.mysql.com/docs/menagerie.zip).
Mediante la sentencia SHOW se encuentran las bases de datos que existen actualmente en el servidor:
mysql> SHOW DATABASES;
+----------+
| Database |
+----------+
| mysql
|
| test
|
| tmp
|
+----------+
Probablemente la lista obtenida sea distinta en su ordenador, pero es casi seguro que tendrá las bases de
datos mysql y test. La base de datos mysql es necesaria porque es la que describe los privilegios de
acceso de los usuarios. La base de datos test se provee para que los usuarios hagan pruebas.
Tenga en cuenta que si no tiene el privilegio SHOW DATABASES, no podrá ver todas las bases de datos
que hay en el servidor. Consulte Sección 13.5.1.3, “Sintaxis de GRANT y REVOKE”.
Si la base de datos test existe, intente acceder a ella:
mysql> USE test
Database changed
Advierta que, al igual que QUIT, USE no necesita que ponga un punto y coma al final (aunque puede
hacerlo si lo desea). La sentencia USE tiene otra particularidad: debe escribirse en una sola linea.
Puede colocar los ejemplos siguientes en la base de datos test, si tiene acceso a ella, pero si trabaja en
un ambiente compartido, lo que deposite allí puede ser fácilmente borrado por alguien más que tenga el
acceso. Por este motivo, debería pedirle a su administrador permiso para usar una base de datos propia.
Suponga que quiere llamarla menagerie. El administrador necesitará ejecutar un comando como este:
mysql> GRANT ALL ON menagerie.* TO 'su_nombre_mysql'@'su_host_cliente';
Donde su_nombre_mysql es el nombre de usuario que se le asignó, y su_host_cliente es el host u
ordenador desde donde se conectará.
3.3.1. Crear y seleccionar una base de datos
Si el administrador crea su base de datos en el mismo momento que le otorga privilegios, puede comenzar
a utilizarla, de lo contrario necesitará crearla:
mysql> CREATE DATABASE menagerie;
En ambientes Unix, los nombres de las bases de datos son case sensitive (al contrario que las palabras
clave), de modo que siempre debe referirse a su base de datos como menagerie, y no Menagerie,
MENAGERIE, o una variante similar. Esto también se aplica a los nombres de tablas. Esta restricción no
166
Crear una tabla
existe en Windows, aunque puede utilizar el mismo esquema de mayúsculas cuando se refiera a bases de
datos y tablas en una consulta dada.
Al crear una base de datos, ésta no se selecciona para su uso, debe hacerlo explicitamente. Para
convertir a menagerie en la base de datos actual, use este comando:
mysql> USE menagerie
Database changed
Las bases de datos sólo necesitan ser creadas una sola vez, pero deben ser seleccionadas cada vez que
se inicia una sesión de mysql. Puede hacerse a través del comando USE como se muestra en el ejemplo,
o puede indicar la base de datos en la linea de comandos al ejecutar mysql. Simplemente debe indicar el
nombre de la base de datos a continuación de los parámetros que necesite ingresar. Por ejemplo:
shell> mysql -h host -u user -p menagerie
Enter password: ********
Advierta en el comando anterior que menagerie no es la contraseña. Si se quisiera suministrar la
contraseña en la linea de comandos, después de la opción -p, debe hacerse sin dejar espacios en blanco
(por ejemplo, -pmypassword, no -p mypassword). De todos modos, colocar la contraseña en la linea
de comandos no es recomendable porque lo expone a la vista de otros usuarios.
3.3.2. Crear una tabla
La creación de la base de datos ha sido una tarea sencilla, pero hasta ahora permanece vacía, como le
muestra SHOW TABLES:
mysql> SHOW TABLES;
Empty set (0.00 sec)
La parte difícil es decidir cómo debería ser la estructura de su base de datos: qué tablas necesitará, y qué
columnas habrá en cada tabla.
Querrá una tabla para contener un registro por cada mascota. Esta tabla puede llamarse pet, y debería
contener, como mínimo, el nombre de cada animal. Dado que el nombre no es muy relevante por sí
mismo, tendría que tener más información. Por ejemplo, si más de una persona en su familia tendrá
mascotas, querrá listar también el dueño de cada animal. Y algunos otros datos descriptivos básicos,
como especie y sexo.
¿Qué hacer con la edad? Podría ser de interés, pero no es un buen dato para almacenar en una base
de datos. La edad cambia a medida que pasa el tiempo, lo cual significa que debería actualizar la base
de datos a menudo. En lugar de esto, es mejor almacenar un valor fijo, como la fecha de nacimiento. De
este modo, cada vez que requiera saber la edad, podrá calcularla como la diferencia entre la fecha de
nacimiento y la fecha actual. MySQL provee funciones para realizar cálculos con fechas, por lo que no es
dificultoso. Almacenar la fecha de nacimiento en lugar de la edad tiene otras ventajas:
• Puede usar la base de datos para tareas como generar recordatorios para los próximos cumpleaños
de mascotas. (Si piensa que este tipo de consultas no es importante, considere que es lo mismo que
haría en un contexto de base de datos de negocios para identificar aquellos clientes a los que habrá
que enviar una tarjeta por su cumpleaños, para conseguir ese toque personal con la asistencia del
ordenador).
• Puede calcular edades en relación a otras fechas además de la actual. Por ejemplo, almacenar la fecha
de muerte de una mascota le posibilita calcular la edad que tenía a ese momento.
Probablemente pensará en otros tipos de información que resultarían útiles dentro de la tabla pet pero
los identificados hasta ahora son suficientes: name (nombre), owner (propietario), species (especie), sex
(sexo), birth (nacimiento) y death (muerte).
167
Cargar datos en una tabla
Debe usar la sentencia CREATE TABLE para especificar la estructura de una tabla:
mysql> CREATE TABLE pet (name VARCHAR(20), owner VARCHAR(20),
-> species VARCHAR(20), sex CHAR(1), birth DATE, death DATE);
El tipo de dato VARCHAR es una buena elección para las columnas name, owner, y species porque
los datos que allí se almacenan no son de longitud uniforme. En realidad no es necesario que todas
estas columnas tengan la misma longitud ni que ésta sea 20. En MySQL 5.0.3 y versiones posteriores,
normalmente se puede adoptar cualquier longitud entre 1 y 65535, según lo que se crea más razonable.
(Nota: Anteriormente a MySQL 5.0.3, el límite de longitud era 255.) Si en el futuro debiera aumentar la
longitud de estos campos, MySQL tiene la sentencia ALTER TABLE.
Hay varios tipos de datos que podrían usarse para representar el sexo en los registros de animales, tal
como 'm' y 'f', o 'male' (masculino) y 'female' (femenino). Lo más simple es usar los caracteres
'm' y 'f'.
Es obvio el uso del tipo de dato DATE para las columnas birth y death.
Luego de crear una tabla, SHOW TABLES debería producir una salida:
mysql> SHOW TABLES;
+---------------------+
| Tables in menagerie |
+---------------------+
| pet
|
+---------------------+
Para verificar que la tabla ha sido creada en la forma esperada, utilice la sentencia DESCRIBE:
mysql> DESCRIBE pet;
+---------+-------------+------+-----+---------+-------+
| Field
| Type
| Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| name
| varchar(20) | YES |
| NULL
|
|
| owner
| varchar(20) | YES |
| NULL
|
|
| species | varchar(20) | YES |
| NULL
|
|
| sex
| char(1)
| YES |
| NULL
|
|
| birth
| date
| YES |
| NULL
|
|
| death
| date
| YES |
| NULL
|
|
+---------+-------------+------+-----+---------+-------+
DESCRIBE puede ser utilizada en cualquier momento, por ejemplo, si olvida los nombres o el tipo de dato
de las columnas de la tabla.
3.3.3. Cargar datos en una tabla
Luego de crear la tabla, necesitará completarla con datos. Para esto, le serán de utilidad las sentencias
LOAD DATA e INSERT.
Suponga que los registros de mascotas fueran como los mostrados a continuación. (Observe que MySQL
espera que las fechas tengan el formato 'AAAA-MM-DD', esto puede ser diferente a lo que acostumbra
utilizar).
name
owner
species
sex
birth
Fluffy
Harold
cat
f
1993-02-04
Claws
Gwen
cat
m
1994-03-17
Buffy
Harold
dog
f
1989-05-13
Fang
Benny
dog
m
1990-08-27
168
death
Cargar datos en una tabla
Bowser
Diane
dog
m
1979-08-31
Chirpy
Gwen
bird
f
1998-09-11
Whistler
Gwen
bird
Slim
Benny
snake
1995-07-29
1997-12-09
m
1996-04-29
Dado que está comenzando con una tabla vacía, una forma fácil de completarla es creando un fichero
de texto que contenga una línea por cada animal, y luego insertando el contenido del fichero en la tabla
mediante una sola sentencia.
Para esto, debería crear un fichero de texto llamado pet.txt, conteniendo un registro por linea, con
cada valor separado por un carácter de tabulación, y dispuestos en el orden en el cual se especificaron
las columnas en la sentencia CREATE TABLE. Para valores ausentes (como sexo desconocido o fechas
de muerte de animales con vida), puede usar valores NULL. Para representar estos valores en el archivo
de texto, utilice \N (barra diagonal y N mayúscula). Por ejemplo, el registro de Whistler se vería del modo
siguiente (el espacio en blanco entre cada valor es un solo carácter de tabulación):
name
owner
species
sex
birth
death
Whistler
Gwen
bird
\N
1997-12-09
\N
Para cargar el fichero pet.txt dentro de la tabla pet, utilice este comando:
mysql> LOAD DATA LOCAL INFILE '/path/pet.txt' INTO TABLE pet;
Si trabaja en Windows, con un editor que emplea \r\n (retorno de carro + nueva linea) como caracteres
de fin de línea, debería usar:
mysql> LOAD DATA LOCAL INFILE '/path/pet.txt' INTO TABLE pet
-> LINES TERMINATED BY '\r\n';
(En un ordenador Apple bajo OS X, probablemente quiera utilizar LINES TERMINATED BY '\r'.)
Opcionalmente puede especificar en la sentencia LOAD DATA los caracteres que actuarán como
separador de campo y fin de línea, pero los valores por defecto son tabulación y nueva línea. Estos son
suficientes para que la sentencia lea correctamente el fichero pet.txt
Si ocurre un error al ejecutar la sentencia, probablemente se deba a que su instalación de MySQL no
tiene habilitada por defecto la capacidad de manejar archivos locales. Consulte Sección 5.5.4, “Cuestiones
relacionadas con la seguridad y LOAD DATA LOCAL” para obtener información sobre cómo cambiar esto.
Cuando lo que desea es agregar nuevos registros de a uno por vez, la sentencia INSERT resulta de
utilidad. De esta sencilla manera, se suministran valores para cada columna, dispuestos en el orden en
el cual se especificaron las columnas en la sentencia CREATE TABLE statement. Suponga que Diane
obtiene un nuevo hamster llamado "Puffball". Se podría agregar un nuevo registro, usando la sentencia
INSERT de este modo:
mysql> INSERT INTO pet
-> VALUES ('Puffball','Diane','hamster','f','1999-03-30',NULL);
Observe que las cadenas alfanuméricas y las fechas son representados como cadenas delimitadas por
apóstrofos. También, con INSERT, se pueden insertar valores NULL directamente, para indicar un valor
ausente. No se debe utilizar \N como se hace con LOAD DATA.
A partir de este ejemplo queda demostrado que lleva mucho más trabajo realizar una carga inicial de
registros empleando varias sentencias INSERT que si se hace mediante la sentencia LOAD DATA.
169
Extraer información de una tabla
3.3.4. Extraer información de una tabla
La sentencia SELECT es utilizada para traer información desde una tabla. La sintaxis general de esta
sentencia es:
SELECT seleccionar_Esto
FROM desde_tabla
WHERE condiciones;
seleccionar_esto es lo que se quiere ver. Puede ser una lista de columnas, o * para indicar “todas
las columnas.” desde_tablaindica la tabla donde están los datos a recuperar. La cláusula WHERE es
opcional. Si está presente, condiciones representa las condiciones que cada registro debe cumplir para
retornar como resultado.
3.3.4.1. Seleccionar todos los datos
La forma más simple de SELECT recupera todo lo que hay en la tabla:
mysql> SELECT * FROM pet;
+----------+--------+---------+------+------------+------------+
| name
| owner | species | sex | birth
| death
|
+----------+--------+---------+------+------------+------------+
| Fluffy
| Harold | cat
| f
| 1993-02-04 | NULL
|
| Claws
| Gwen
| cat
| m
| 1994-03-17 | NULL
|
| Buffy
| Harold | dog
| f
| 1989-05-13 | NULL
|
| Fang
| Benny | dog
| m
| 1990-08-27 | NULL
|
| Bowser
| Diane | dog
| m
| 1979-08-31 | 1995-07-29 |
| Chirpy
| Gwen
| bird
| f
| 1998-09-11 | NULL
|
| Whistler | Gwen
| bird
| NULL | 1997-12-09 | NULL
|
| Slim
| Benny | snake
| m
| 1996-04-29 | NULL
|
| Puffball | Diane | hamster | f
| 1999-03-30 | NULL
|
+----------+--------+---------+------+------------+------------+
Esta forma de SELECT es útil si se quiere revisar la tabla completa, por ejemplo, despues de haberla
cargado con un conjunto de datos inicial. Por ejemplo, puede ocurrir que la fecha de nacimiento de
Bowser no parezca correcta. Consultando los papeles de pedigri, se descubre que el año correcto de
nacimiento es 1989, no 1979.
Existen al menos dos formas de solucionarlo:
• Editando el fichero pet.txt para corregir el error, vaciando la tabla y volviendola a llenar con los datos.
Para esto se usan las sentencias DELETE y LOAD DATA:
mysql> DELETE FROM pet;
mysql> LOAD DATA LOCAL INFILE 'pet.txt' INTO TABLE pet;
No obstante, si opta por esto, deberá volver a cargar el registro de Puffball.
• Corrigiendo únicamente el registro erróneo. Para esto se usa la sentencia UPDATE:
mysql> UPDATE pet SET birth = '1989-08-31' WHERE name = 'Bowser';
UPDATE modifica solo el registro en cuestión y no requiere que se vuelva a llenar la tabla.
3.3.4.2. Seleccionar registros específicos
Como se ha visto en la sección anterior, es fácil recuperar una tabla en su totalidad. Sólo debe omitir
la cláusula WHERE en la sentencia SELECT. Pero, generalmente, no se desea ver la tabla completa,
especialmente cuando alcanza un gran tamaño. En cambio, usualmente, se tiene interés en obtener una
respuesta para una consulta en particular, en cuyo caso se especifican algunas restricciones para la
170
Extraer información de una tabla
información que se traerá. A continuación se verán algunas consultas que responden preguntas acerca de
las mascotas.
Se pueden seleccionar sólo algunos registros de la tabla. Por ejemplo, si quisiera verificar los cambios
realizados sobre la fecha de nacimiento de Bowser, seleccione el registro de Bowser de esta manera:
mysql> SELECT * FROM pet WHERE name = 'Bowser';
+--------+-------+---------+------+------------+------------+
| name
| owner | species | sex | birth
| death
|
+--------+-------+---------+------+------------+------------+
| Bowser | Diane | dog
| m
| 1989-08-31 | 1995-07-29 |
+--------+-------+---------+------+------------+------------+
La salida confirma que el año fue correctamente registrado como 1989, ya no es 1979.
Normalmente, las comparaciones de cadenas no son case sensitive, por eso puede escribir el nombre
como 'bowser', 'BOWSER', etc. El resultado de la consulta será el mismo.
Se pueden indicar condiciones a cumplir por cualquier columna, no solamente por name. Por ejemplo, si
quisiera saber qué animales han nacido luego de 1998, necesita evaluar la columna birth:
mysql> SELECT * FROM pet WHERE birth > '1998-1-1';
+----------+-------+---------+------+------------+-------+
| name
| owner | species | sex | birth
| death |
+----------+-------+---------+------+------------+-------+
| Chirpy
| Gwen | bird
| f
| 1998-09-11 | NULL |
| Puffball | Diane | hamster | f
| 1999-03-30 | NULL |
+----------+-------+---------+------+------------+-------+
Se pueden combinar condiciones, por ejemplo para localizar perros hembra:
mysql> SELECT * FROM pet WHERE species = 'dog' AND sex = 'f';
+-------+--------+---------+------+------------+-------+
| name | owner | species | sex | birth
| death |
+-------+--------+---------+------+------------+-------+
| Buffy | Harold | dog
| f
| 1989-05-13 | NULL |
+-------+--------+---------+------+------------+-------+
La consulta anterior emplea el operador lógico AND. También existe el operador OR:
mysql> SELECT * FROM pet WHERE species = 'snake' OR species = 'bird';
+----------+-------+---------+------+------------+-------+
| name
| owner | species | sex | birth
| death |
+----------+-------+---------+------+------------+-------+
| Chirpy
| Gwen | bird
| f
| 1998-09-11 | NULL |
| Whistler | Gwen | bird
| NULL | 1997-12-09 | NULL |
| Slim
| Benny | snake
| m
| 1996-04-29 | NULL |
+----------+-------+---------+------+------------+-------+
AND and OR pueden ser combinadas, si bien AND tiene mayor precedencia que OR. Si utiliza ambos
operadores, es buena idea emplear paréntesis para indicar explicitamente la forma en que las condiciones
deben agruparse:
mysql> SELECT * FROM pet WHERE (species = 'cat' AND sex = 'm')
-> OR (species = 'dog' AND sex = 'f');
+-------+--------+---------+------+------------+-------+
| name | owner | species | sex | birth
| death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen
| cat
| m
| 1994-03-17 | NULL |
| Buffy | Harold | dog
| f
| 1989-05-13 | NULL |
+-------+--------+---------+------+------------+-------+
3.3.4.3. Seleccionar columnas concretas
171
Extraer información de una tabla
Si no se quieren ver filas completas, solo hace falta indicar las columnas en las que se está interesado,
separadas por comas. Por ejemplo, si desea saber cuándo nació cada animal, seleccione las columnas
name y birth:
mysql> SELECT name, birth FROM pet;
+----------+------------+
| name
| birth
|
+----------+------------+
| Fluffy
| 1993-02-04 |
| Claws
| 1994-03-17 |
| Buffy
| 1989-05-13 |
| Fang
| 1990-08-27 |
| Bowser
| 1989-08-31 |
| Chirpy
| 1998-09-11 |
| Whistler | 1997-12-09 |
| Slim
| 1996-04-29 |
| Puffball | 1999-03-30 |
+----------+------------+
Para saber quien posee mascotas, utilice esta consulta:
mysql> SELECT owner FROM pet;
+--------+
| owner |
+--------+
| Harold |
| Gwen
|
| Harold |
| Benny |
| Diane |
| Gwen
|
| Gwen
|
| Benny |
| Diane |
+--------+
Observe que esta sentencia retorna el campo owner de cada registro, y algunos de ellos aparecen más
de una vez. Para reducir la salida, recupere solamente una vez cada registro repetido, agregando la
palabra clave DISTINCT:
mysql> SELECT DISTINCT owner FROM pet;
+--------+
| owner |
+--------+
| Benny |
| Diane |
| Gwen
|
| Harold |
+--------+
Puede emplearse una clásula WHERE para combinar la selección de ciertas filas y de ciertas columnas. Por
ejemplo, para obtener únicamente la fecha de nacimiento de perros y gatos, ejecute esta consulta:
mysql> SELECT name, species, birth FROM pet
-> WHERE species = 'dog' OR species = 'cat';
+--------+---------+------------+
| name
| species | birth
|
+--------+---------+------------+
| Fluffy | cat
| 1993-02-04 |
| Claws | cat
| 1994-03-17 |
| Buffy | dog
| 1989-05-13 |
| Fang
| dog
| 1990-08-27 |
| Bowser | dog
| 1989-08-31 |
172
Extraer información de una tabla
+--------+---------+------------+
3.3.4.4. Ordenar registros
Quizá advirtió, en los ejemplos anteriores, que las filas resultantes se mostraron sin ningún orden en
particular. A menudo es más fácil examinar la salida de una consulta cuando las filas se ordenan de algún
modo significativo. Para ordenar un resultado, se usa la clásula ORDER BY.
Aqui tiene las fechas de cumpleaños de los animales, ordenadas por fecha:
mysql> SELECT name, birth FROM pet ORDER BY birth;
+----------+------------+
| name
| birth
|
+----------+------------+
| Buffy
| 1989-05-13 |
| Bowser
| 1989-08-31 |
| Fang
| 1990-08-27 |
| Fluffy
| 1993-02-04 |
| Claws
| 1994-03-17 |
| Slim
| 1996-04-29 |
| Whistler | 1997-12-09 |
| Chirpy
| 1998-09-11 |
| Puffball | 1999-03-30 |
+----------+------------+
Por lo general, cuando se trata de columnas de tipo carácter, la ordenación, — al igual que otras
operaciones de comparación — no es case-sensitive. Significa que el orden permanece indefinido para las
columnas que son idénticas excepto por sus mayúsculas y minúsculas. Puede no obstante forzar a que
una columna se ordene en forma sensible a mayúsculas empleando el modificador BINARY: ORDER BY
BINARY columna.
El sentido de ordenación, por defecto, es ascendente, con los valores más pequeños primero. Para
ordenar en sentido inverso (descendente), agregue la palabra clave DESC luego del nombre de la columna
por la que ordena:
mysql> SELECT name, birth FROM pet ORDER BY birth DESC;
+----------+------------+
| name
| birth
|
+----------+------------+
| Puffball | 1999-03-30 |
| Chirpy
| 1998-09-11 |
| Whistler | 1997-12-09 |
| Slim
| 1996-04-29 |
| Claws
| 1994-03-17 |
| Fluffy
| 1993-02-04 |
| Fang
| 1990-08-27 |
| Bowser
| 1989-08-31 |
| Buffy
| 1989-05-13 |
+----------+------------+
Puede ordenar basándose en varias columnas, y cada columna en un sentido diferente. Por ejemplo,
para ordenar por tipo de animal en sentido ascendente y, dentro de cada tipo, ordenar por nacimiento en
sentido descendente (los animales más jóvenes primero) utilice la siguiente consulta:
mysql> SELECT name, species, birth FROM pet
-> ORDER BY species, birth DESC;
+----------+---------+------------+
| name
| species | birth
|
+----------+---------+------------+
| Chirpy
| bird
| 1998-09-11 |
| Whistler | bird
| 1997-12-09 |
| Claws
| cat
| 1994-03-17 |
173
Extraer información de una tabla
| Fluffy
| cat
| 1993-02-04 |
| Fang
| dog
| 1990-08-27 |
| Bowser
| dog
| 1989-08-31 |
| Buffy
| dog
| 1989-05-13 |
| Puffball | hamster | 1999-03-30 |
| Slim
| snake
| 1996-04-29 |
+----------+---------+------------+
Advierta que la palabra clave DESC se aplica sobre la columna inmediatamente anterior (birth); no afecta
el sentido de ordenación de la columna species.
3.3.4.5. Cálculos sobre fechas
MySQL provee varias funciones que se aplican a cálculos entre fechas, por ejemplo, para calcular edades
u obtener partes de una fecha.
Para determinar cuántos años de edad tiene cada mascota, hay que calcular la diferencia entre el año de
la fecha actual y el de la fecha de nacimiento, y luego restar 1 al resultado si el dia y mes actuales son
anteriores al día y mes indicados por la fecha de nacimiento. La siguiente consulta devuelve, para cada
mascota, el nombre, la fecha de nacimiento, la fecha actual, y la edad en años.
mysql> SELECT name, birth, CURDATE(),
-> (YEAR(CURDATE())-YEAR(birth))
-> - (RIGHT(CURDATE(),5)<RIGHT(birth,5))
-> AS age
-> FROM pet;
+----------+------------+------------+------+
| name
| birth
| CURDATE() | age |
+----------+------------+------------+------+
| Fluffy
| 1993-02-04 | 2003-08-19 |
10 |
| Claws
| 1994-03-17 | 2003-08-19 |
9 |
| Buffy
| 1989-05-13 | 2003-08-19 |
14 |
| Fang
| 1990-08-27 | 2003-08-19 |
12 |
| Bowser
| 1989-08-31 | 2003-08-19 |
13 |
| Chirpy
| 1998-09-11 | 2003-08-19 |
4 |
| Whistler | 1997-12-09 | 2003-08-19 |
5 |
| Slim
| 1996-04-29 | 2003-08-19 |
7 |
| Puffball | 1999-03-30 | 2003-08-19 |
4 |
+----------+------------+------------+------+
En el ejemplo anterior, YEAR() trae la parte correspondiente al año de una fecha, y RIGHT() trae los 5
primeros caracteres contando desde la derecha, que representan la parte MM-DD de la fecha. La porción
de la expresión que compara los valores MM-DD devuelve 1 o 0, lo cual se corresponde con la diferencia
de 1 año a restar de la edad si el dia de la fecha devuelto por CURDATE() ocurre antes que la fecha de
nacimiento birth. La expresión completa es un tanto confusa para usar como encabezado, por lo que se
emplea un alias (age) para que el encabezado sea más comprensible.
La consulta funciona bien, pero los resultados podrían revisarse más fácilmente si las filas se presentaran
en algún orden. Esto puede hacerse agregando la cláusula ORDER BY name para ordenar por nombre la
salida:
mysql> SELECT name, birth, CURDATE(),
-> (YEAR(CURDATE())-YEAR(birth))
-> - (RIGHT(CURDATE(),5)<RIGHT(birth,5))
-> AS age
-> FROM pet ORDER BY name;
+----------+------------+------------+------+
| name
| birth
| CURDATE() | age |
+----------+------------+------------+------+
| Bowser
| 1989-08-31 | 2003-08-19 |
13 |
| Buffy
| 1989-05-13 | 2003-08-19 |
14 |
| Chirpy
| 1998-09-11 | 2003-08-19 |
4 |
174
Extraer información de una tabla
| Claws
| 1994-03-17 | 2003-08-19 |
9 |
| Fang
| 1990-08-27 | 2003-08-19 |
12 |
| Fluffy
| 1993-02-04 | 2003-08-19 |
10 |
| Puffball | 1999-03-30 | 2003-08-19 |
4 |
| Slim
| 1996-04-29 | 2003-08-19 |
7 |
| Whistler | 1997-12-09 | 2003-08-19 |
5 |
+----------+------------+------------+------+
Para ordenar la salida por edad (age) en lugar de por nombre (name), solo hay que utilizar una cláusula
ORDER BY diferente:
mysql> SELECT name, birth, CURDATE(),
-> (YEAR(CURDATE())-YEAR(birth))
-> - (RIGHT(CURDATE(),5)<RIGHT(birth,5))
-> AS age
-> FROM pet ORDER BY age;
+----------+------------+------------+------+
| name
| birth
| CURDATE() | age |
+----------+------------+------------+------+
| Chirpy
| 1998-09-11 | 2003-08-19 |
4 |
| Puffball | 1999-03-30 | 2003-08-19 |
4 |
| Whistler | 1997-12-09 | 2003-08-19 |
5 |
| Slim
| 1996-04-29 | 2003-08-19 |
7 |
| Claws
| 1994-03-17 | 2003-08-19 |
9 |
| Fluffy
| 1993-02-04 | 2003-08-19 |
10 |
| Fang
| 1990-08-27 | 2003-08-19 |
12 |
| Bowser
| 1989-08-31 | 2003-08-19 |
13 |
| Buffy
| 1989-05-13 | 2003-08-19 |
14 |
+----------+------------+------------+------+
Una consulta similar se utiliza para determinar la edad a la fecha de muerte de los animales. Se
determinan los animales que han muerto verificando si el valor de la columna death es NULL. Entonces,
para todos los valores no NULL calcula la diferencia entre las fechas de muerte (death) y nacimiento
(birth):
mysql> SELECT name, birth, death,
-> (YEAR(death)-YEAR(birth)) - (RIGHT(death,5)<RIGHT(birth,5))
-> AS age
-> FROM pet WHERE death IS NOT NULL ORDER BY age;
+--------+------------+------------+------+
| name
| birth
| death
| age |
+--------+------------+------------+------+
| Bowser | 1989-08-31 | 1995-07-29 |
5 |
+--------+------------+------------+------+
La consulta utiliza la expresión death IS NOT NULL en lugar de death <> NULL porque NULL es un
valor especial, que no puede ser comparado mediante los operadores lógicos habituales. Este tema se
trata más extensamente más adelante. Consultar Sección 3.3.4.6, “Trabajar con valores NULL”.
¿Qué tal si se quisiera saber qué animales cumplen años el próximo mes? Para esta clase de cálculos, el
año y el día son irrelevantes; simplemente se desea extraer de la columna birth la parte correspondiente
al mes. MySQL cuenta con varias funciones para extraer partes de fechas, como YEAR(), MONTH(), y
DAYOFMONTH(). MONTH() es la función apropiada para este caso. Para verla en funcionamiento, ejecute
una consulta que muestra tanto el valor de birth como el de MONTH(birth):
mysql> SELECT name, birth, MONTH(birth) FROM pet;
+----------+------------+--------------+
| name
| birth
| MONTH(birth) |
+----------+------------+--------------+
| Fluffy
| 1993-02-04 |
2 |
| Claws
| 1994-03-17 |
3 |
| Buffy
| 1989-05-13 |
5 |
| Fang
| 1990-08-27 |
8 |
| Bowser
| 1989-08-31 |
8 |
175
Extraer información de una tabla
| Chirpy
| 1998-09-11 |
9 |
| Whistler | 1997-12-09 |
12 |
| Slim
| 1996-04-29 |
4 |
| Puffball | 1999-03-30 |
3 |
+----------+------------+--------------+
Encontrar los animales que cumplen años el mes siguiente es también sencillo. Suponga que el mes
actual es abril. De modo que su número es 4, y se buscan los animales nacidos en Mayo (mes 5), de esta
forma:
mysql> SELECT name, birth FROM pet WHERE MONTH(birth) = 5;
+-------+------------+
| name | birth
|
+-------+------------+
| Buffy | 1989-05-13 |
+-------+------------+
Esto se complica ligeramente cuando el mes actual es Diciembre. No se puede simplemente sumarle 1 al
número del mes (12) y buscar animales nacidos en el mes 13, porque no existe tal mes. En lugar de eso,
se debe buscar por animales nacidos en Enero (mes 1).
Se puede incluso escribir la consulta de forma que funcione sin importar cual es el mes actual. Así, no
se necesitará indicar un mes en particular en la consulta. DATE_ADD() sirve para sumar un intervalo de
tiempo a una fecha dada. Si se adiciona un mes al valor de CURDATE(), y se extrae el mes mediante
MONTH(), el resultado será el mes en el que se buscarán cumpleaños:
mysql> SELECT name, birth FROM pet
-> WHERE MONTH(birth) = MONTH(DATE_ADD(CURDATE(),INTERVAL 1 MONTH));
Una manera alternativa de alcanzar el mismo resultado es sumar 1 al mes actual para obtener el mes
siguiente (después de emplear la función módulo (MOD) para dejar el número de mes en 0 si resultara ser
12:
mysql> SELECT name, birth FROM pet
-> WHERE MONTH(birth) = MOD(MONTH(CURDATE()), 12) + 1;
Advierta que MONTH devuelve un número entre 1 y 12. Y MOD(algun_valor,12) devuelve un número
entre 0 y 11. La suma debe ser realizada después de MOD(), en otro caso se estaría pasando de
Noviembre (11) a Enero (1).
3.3.4.6. Trabajar con valores NULL
El valor NULL puede resultar un poco desconcertante hasta que se comienza a utilizar. Conceptualmente,
NULL significa valor inexistente o desconocido, y es tratado de forma diferente a otros valores. Para
verificar que un valor es NULL, no se pueden emplear operadores de comparación aritmética como =, <, o
<>. Para comprobar esto, intente la siguiente consulta:
mysql> SELECT 1 = NULL, 1 <> NULL, 1 < NULL, 1 > NULL;
+----------+-----------+----------+----------+
| 1 = NULL | 1 <> NULL | 1 < NULL | 1 > NULL |
+----------+-----------+----------+----------+
|
NULL |
NULL |
NULL |
NULL |
+----------+-----------+----------+----------+
Claramente, no se obtienen valores significtivos a partir de estas comparaciones. Use en su lugar los
operadores IS NULL y IS NOT NULL:
mysql> SELECT 1 IS NULL, 1 IS NOT NULL;
+-----------+---------------+
| 1 IS NULL | 1 IS NOT NULL |
176
Extraer información de una tabla
+-----------+---------------+
|
0 |
1 |
+-----------+---------------+
Observe que en MySQL, 0 o NULL se intepretan como falso, y cualquier otro valor, como verdadero. El
valor por defecto para una operación booleana es 1.
Este tratamiento especial de NULL es debido a que, en la sección anterior, fue necesario determinar qué
animales ya no estaban vivos utilizando death IS NOT NULL en lugar de death <> NULL.
Dos valores NULL son considerados iguales por la cláusula GROUP BY.
Cuando se realiza un ORDER BY, los valores NULL se presentan en primer lugar si se emplea ORDER
BY ... ASC, y al final si se ordena con ORDER BY ... DESC.
Un error muy común cuando se trabaja con valores NULL es asumir que es imposible insertar un valor
cero o una cadena vacía en una columna definida como NOT NULL, pero no es así. Los mencionados son
efectivamente valores, mientras que NULL significa "no hay un valor". Puede comprobar esto fácilmente
empleando IS [NOT] NULL como se muestra aquí:
mysql> SELECT 0 IS NULL, 0 IS NOT NULL, '' IS NULL, '' IS NOT NULL;
+-----------+---------------+------------+----------------+
| 0 IS NULL | 0 IS NOT NULL | '' IS NULL | '' IS NOT NULL |
+-----------+---------------+------------+----------------+
|
0 |
1 |
0 |
1 |
+-----------+---------------+------------+----------------+
Por lo tanto, es totalmente posible insertar cadenas vacias o ceros en columnas marcadas como NOT
NULL, ya que son valores NOT NULL. Consultar Sección A.5.3, “Problemas con valores NULL”.
3.3.4.7. Coincidencia de patrones
MySQL posee capacidades estándar para utilizar patrones así como también una forma de patrones
basada en expresiones regulares extendidas similares a las que se encuentran en utilidades de UNIX,
como ser vi, grep, y sed.
Los patrones SQL permiten emplear el carácter '_' para representar coincidencia con un carácter individual
y '%' En MySQL, por defecto, los patrones SQL no son case-sensitive. Abajo se muestran algunos
ejemplos. Advierta que no se emplean los operadores = o <> para trabajar con patrones SQL, en lugar de
eso se usan los operadores de comparación LIKE o NOT LIKE.
Para encontrar nombres que comiencen con 'b':
mysql> SELECT * FROM pet WHERE name LIKE 'b%';
+--------+--------+---------+------+------------+------------+
| name
| owner | species | sex | birth
| death
|
+--------+--------+---------+------+------------+------------+
| Buffy | Harold | dog
| f
| 1989-05-13 | NULL
|
| Bowser | Diane | dog
| m
| 1989-08-31 | 1995-07-29 |
+--------+--------+---------+------+------------+------------+
Para encontrar nombres que terminen con 'fy':
mysql> SELECT * FROM pet WHERE name LIKE '%fy';
+--------+--------+---------+------+------------+-------+
| name
| owner | species | sex | birth
| death |
+--------+--------+---------+------+------------+-------+
| Fluffy | Harold | cat
| f
| 1993-02-04 | NULL |
| Buffy | Harold | dog
| f
| 1989-05-13 | NULL |
+--------+--------+---------+------+------------+-------+
177
Extraer información de una tabla
Para encontrar nombres que contengan 'w':
mysql> SELECT * FROM pet WHERE name LIKE '%w%';
+----------+-------+---------+------+------------+------------+
| name
| owner | species | sex | birth
| death
|
+----------+-------+---------+------+------------+------------+
| Claws
| Gwen | cat
| m
| 1994-03-17 | NULL
|
| Bowser
| Diane | dog
| m
| 1989-08-31 | 1995-07-29 |
| Whistler | Gwen | bird
| NULL | 1997-12-09 | NULL
|
+----------+-------+---------+------+------------+------------+
Para encontrar nombres que contengan exactamente 5 caracteres, use 5 veces el carácter patrón '_':
mysql> SELECT * FROM pet WHERE name LIKE '_____';
+-------+--------+---------+------+------------+-------+
| name | owner | species | sex | birth
| death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen
| cat
| m
| 1994-03-17 | NULL |
| Buffy | Harold | dog
| f
| 1989-05-13 | NULL |
+-------+--------+---------+------+------------+-------+
Los otros patrones que pueden emplearse con MySQL usan expresiones regulares extendidas. Cuando
busque coincidencias con este tipo de patrones, use los operadores REGEXP y NOT REGEXP (o bien los
sinónimos RLIKE y NOT RLIKE).
Algunas características de las expresiones regulares extendidas:
• '.' detecta coincidencia con cualquier carácter individual.
• Una clase de carácter '[...]' detecta coincidencia con cualquier carácter entre los corchetes. Por
ejemplo, '[abc]' coincidirá con 'a', 'b', o 'c'. Para hacer referencia a un rango de caracteres, use un
guión. '[a-z]' detecta coincidencia con cualquier letra, mientras que '[0-9]' lo hace con cualquier
dígito.
• '*' detecta coincidencia con cero o más apariciones de los caracteres que lo preceden. Por ejemplo,
'x*' detecta cualquier número de caracteres 'x', '[0-9]*' detecta cualquier cantidad de dígitos, y '.*'
coincidirá con cualquier número de cualquier carácter.
• REGEXP tendrá éxito si el patrón suministrado encuentra coincidencia en cualquier parte del valor
examinado (esto difiere de LIKE en que este último solo tiene éxito si el patrón concuerda con todo el
valor).
• Para lograr que un patrón detecte coincidencias solamente al principio o al final del valor examinado,
utilice '^' al principio o '$' al final del patrón.
Para demostrar el funcionamiento de las expresiones regulares extendidas, las consultas con LIKE
expuestas anteriormente se han reescrito utilizando REGEXP.
Para hallar nombres que comiencen con 'b', use '^' para buscar coincidencia al principio del valor:
mysql> SELECT * FROM pet WHERE name REGEXP '^b';
+--------+--------+---------+------+------------+------------+
| name
| owner | species | sex | birth
| death
|
+--------+--------+---------+------+------------+------------+
| Buffy | Harold | dog
| f
| 1989-05-13 | NULL
|
| Bowser | Diane | dog
| m
| 1989-08-31 | 1995-07-29 |
+--------+--------+---------+------+------------+------------+
En MySQL 5.0, si realmente quiere forzar a que la comparación realizada por REGEXP sea case sensitive,
utilice la palabra clave BINARY para convertir a una de las cadenas en una cadena binaria. Esta consulta
solamente encontrará coincidencia con 'b' minúsculas al comienzo de un nombre:
178
Extraer información de una tabla
mysql> SELECT * FROM pet WHERE name REGEXP BINARY '^b';
Para hallar nombres finalizados en 'fy', emplee '$' para buscar la coincidencia en el final del nombre:
mysql> SELECT * FROM pet WHERE name REGEXP 'fy$';
+--------+--------+---------+------+------------+-------+
| name
| owner | species | sex | birth
| death |
+--------+--------+---------+------+------------+-------+
| Fluffy | Harold | cat
| f
| 1993-02-04 | NULL |
| Buffy | Harold | dog
| f
| 1989-05-13 | NULL |
+--------+--------+---------+------+------------+-------+
Para encontrar nombres conteniendo una 'w', utilice esta consulta:
mysql> SELECT * FROM pet WHERE name REGEXP 'w';
+----------+-------+---------+------+------------+------------+
| name
| owner | species | sex | birth
| death
|
+----------+-------+---------+------+------------+------------+
| Claws
| Gwen | cat
| m
| 1994-03-17 | NULL
|
| Bowser
| Diane | dog
| m
| 1989-08-31 | 1995-07-29 |
| Whistler | Gwen | bird
| NULL | 1997-12-09 | NULL
|
+----------+-------+---------+------+------------+------------+
Debido a que un patrón de expresión regular encuentra coincidencia sin importar el lugar del valor donde
se produce, en la consulta previa no es necesario colocar un comodín a cada lado del patrón para obtener
coincidencia en cualquier parte del valor, como hubiera sucedido de utilizar un patrón SQL
Para hallar nombres conteniendo exactamente cinco caracteres, use '^' y '$' para obligar a que la
coincidencia deba estar al principio y al final del nombre, y cinco instancias de '.' entre ellas.
mysql> SELECT * FROM pet WHERE name REGEXP '^.....$';
+-------+--------+---------+------+------------+-------+
| name | owner | species | sex | birth
| death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen
| cat
| m
| 1994-03-17 | NULL |
| Buffy | Harold | dog
| f
| 1989-05-13 | NULL |
+-------+--------+---------+------+------------+-------+
La consulta anterior también se podría haber escrito empleando el operador '{n}' “repetir-n-veces”:
mysql> SELECT * FROM pet WHERE name REGEXP '^.{5}$';
+-------+--------+---------+------+------------+-------+
| name | owner | species | sex | birth
| death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen
| cat
| m
| 1994-03-17 | NULL |
| Buffy | Harold | dog
| f
| 1989-05-13 | NULL |
+-------+--------+---------+------+------------+-------+
3.3.4.8. Contar registros
Una pregunta frecuente que deben responder las bases de datos es: “¿qué tan a menudo aparece en la
tabla un cierto tipo de dato?” Por ejemplo, se podría querer averiguar la cantidad de mascotas de que se
dispone, o cuantas mascotas tiene cada propietario, o varios otros recuentos sobre los animales.
Contar la cantidad total de animales es la misma pregunta que “¿cuántos registros hay en la tabla pet?”,
ya que hay un registro por mascota. COUNT(*) cuenta el número de filas, por ello, la consulta para contar
animales luce así:
mysql> SELECT COUNT(*) FROM pet;
+----------+
| COUNT(*) |
+----------+
179
Extraer información de una tabla
|
9 |
+----------+
Anteriormente se recuperaban los nombres de la gente que poseía mascotas. Se puede usar COUNT()
para hallar cuantas mascotas tiene cada propietario:
mysql> SELECT owner, COUNT(*) FROM pet GROUP BY owner;
+--------+----------+
| owner | COUNT(*) |
+--------+----------+
| Benny |
2 |
| Diane |
2 |
| Gwen
|
3 |
| Harold |
2 |
+--------+----------+
Observe el uso de GROUP BY para agrupar todos los registros de cada propietario. Sin dicha cláusula,
todo lo que se hubiera obtenido sería un mensaje de error:
mysql> SELECT owner, COUNT(*) FROM pet;
ERROR 1140 (42000): Mixing of GROUP columns (MIN(),MAX(),COUNT(),...)
with no GROUP columns is illegal if there is no GROUP BY clause
COUNT() y GROUP BY son útiles para presentar datos en varias formas. Los siguientes ejemplos
muestran diferentes operaciones:
Cantidad de animales por especies:
mysql> SELECT species, COUNT(*) FROM pet GROUP BY species;
+---------+----------+
| species | COUNT(*) |
+---------+----------+
| bird
|
2 |
| cat
|
2 |
| dog
|
3 |
| hamster |
1 |
| snake
|
1 |
+---------+----------+
Cantidad de animales por sexo:
mysql> SELECT sex, COUNT(*) FROM pet GROUP BY sex;
+------+----------+
| sex | COUNT(*) |
+------+----------+
| NULL |
1 |
| f
|
4 |
| m
|
4 |
+------+----------+
(En esta salida, NULL indica "sexo desconocido")
Cantidad de animales por combinación de especies y sexo:
mysql> SELECT species, sex, COUNT(*) FROM pet GROUP BY species, sex;
+---------+------+----------+
| species | sex | COUNT(*) |
+---------+------+----------+
| bird
| NULL |
1 |
| bird
| f
|
1 |
| cat
| f
|
1 |
| cat
| m
|
1 |
| dog
| f
|
1 |
| dog
| m
|
2 |
180
Extraer información de una tabla
| hamster | f
|
1 |
| snake
| m
|
1 |
+---------+------+----------+
No es necesario examinar una tabla entera cuando se emplea COUNT(). Por ejemplo, la consulta anterior,
se podria limitar a perros y gatos de esta manera:
mysql> SELECT species, sex, COUNT(*) FROM pet
-> WHERE species = 'dog' OR species = 'cat'
-> GROUP BY species, sex;
+---------+------+----------+
| species | sex | COUNT(*) |
+---------+------+----------+
| cat
| f
|
1 |
| cat
| m
|
1 |
| dog
| f
|
1 |
| dog
| m
|
2 |
+---------+------+----------+
O si desea la cantidad de animales de cada sexo contando solamente los que tienen sexo conocido:
mysql> SELECT species, sex, COUNT(*) FROM pet
-> WHERE sex IS NOT NULL
-> GROUP BY species, sex;
+---------+------+----------+
| species | sex | COUNT(*) |
+---------+------+----------+
| bird
| f
|
1 |
| cat
| f
|
1 |
| cat
| m
|
1 |
| dog
| f
|
1 |
| dog
| m
|
2 |
| hamster | f
|
1 |
| snake
| m
|
1 |
+---------+------+----------+
3.3.4.9. Utilizar más de una tabla
La tabla pet mantiene el registro de las mascotas que se poseen. Si quisiera registrar otros datos acerca
de ellas, como eventos de su vida tales como visitas al veterinario o nacimiento de crías, necesitaría otra
tabla. ¿Cómo debería ser esta tabla? Se necesita:
• Un campo con el nombre de la mascota para saber a quien pertenece cada evento registrado.
• La fecha en que ocurrió el evento.
• Un campo con la descripción del evento.
• Un campo con el tipo de evento, a fin de poder clasificarlo.
Teniendo en cuenta estas consideraciones, la sentencia CREATE TABLE para la tabla event ("eventos",
en inglés) podría ser así:
mysql> CREATE TABLE event (name VARCHAR(20), date DATE,
-> type VARCHAR(15), remark VARCHAR(255));
Como se hizo con la tabla pet, es más fácil realizar la carga inicial de datos si se crea un archivo de texto
delimitado con tabulaciones que contenga la información a agregar:
name
date
type
remark
Fluffy
1995-05-15
litter
4 kittens, 3 female, 1 male
181
Extraer información de una tabla
Buffy
1993-06-23
litter
5 puppies, 2 female, 3 male
Buffy
1994-06-19
litter
3 puppies, 3 female
Chirpy
1999-03-21
vet
needed beak straightened
Slim
1997-08-03
vet
broken rib
Bowser
1991-10-12
kennel
Fang
1991-10-12
kennel
Fang
1998-08-28
birthday
Gave him a new chew toy
Claws
1998-03-17
birthday
Gave him a new flea collar
Whistler
1998-12-09
birthday
First birthday
Los registros se cargan así:
mysql> LOAD DATA LOCAL INFILE 'event.txt' INTO TABLE event;
Con base en lo que se ha aprendido a partir de las consultas efectuadas sobre la tabla pet, se debería
poder recuperar registros de la tabla event; los principios son los mismos. Pero en un momento dado la
tabla event por sí sola es insuficiente para responder las preguntas que pueden formularse.
Suponga que se desea saber a qué edad tuvo sus crías cada mascota. Anteriormente se aprendió a
calcular edades a partir de dos fechas. La fecha en que la mascota tuvo sus crias está en la tabla event,
pero para calcular su edad, se necesita su fecha de nacimiento, la cual está localizada en la tabla pet.
Esto significa que la consulta requiere ambas tablas:
mysql> SELECT pet.name,
-> (YEAR(date)-YEAR(birth)) - (RIGHT(date,5)<RIGHT(birth,5)) AS age,
-> remark
-> FROM pet, event
-> WHERE pet.name = event.name AND event.type = 'litter';
+--------+------+-----------------------------+
| name
| age | remark
|
+--------+------+-----------------------------+
| Fluffy |
2 | 4 kittens, 3 female, 1 male |
| Buffy |
4 | 5 puppies, 2 female, 3 male |
| Buffy |
5 | 3 puppies, 3 female
|
+--------+------+-----------------------------+
Hay varias cosas para observar en esta consulta:
• La cláusula FROM menciona dos tablas porque la consulta necesita traer datos de ambas
• Cuando se combina (también se denomina join -unión, en inglés-) información desde múltiples tablas,
se necesita indicar qué registro de una tabla se combinará con qué registro de la otra. Esto es sencillo
porque ambas tablas tienen una columna name. La consulta emplea la cláusula WHERE para hacer
coincidir registros de las dos tablas basándose en el valor de name.
• Dado que la columna name aparece en ambas tablas, se debe especificar a cuál tabla pertenece la
columna al hacer referencia a ella. Esto se hace anteponiendo el nombre de la tabla al nombre de la
columna.
No es necesario tener dos tablas diferentes para establecer una unión. A veces es útil combinar una tabla
consigo misma, si se desea comparar entre sí registros de una misma tabla. Por ejemplo, para formar
parejas de mascotas para reproducción, podría unir la tabla pet consigo misma para generar pares de
animales macho y hembra de la misma especie:
mysql> SELECT p1.name, p1.sex, p2.name, p2.sex, p1.species
182
Obtener información sobre bases de datos y tablas
-> FROM pet AS p1, pet AS p2
-> WHERE p1.species = p2.species AND p1.sex = 'f' AND p2.sex = 'm';
+--------+------+--------+------+---------+
| name
| sex | name
| sex | species |
+--------+------+--------+------+---------+
| Fluffy | f
| Claws | m
| cat
|
| Buffy | f
| Fang
| m
| dog
|
| Buffy | f
| Bowser | m
| dog
|
+--------+------+--------+------+---------+
En la consulta anterior se especificaron alias para la tabla con el fin de indicar a qué instancia de la tabla
pertenece cada columna referenciada.
3.4. Obtener información sobre bases de datos y tablas
¿Qué tal si no se recuerda el nombre de una base de datos o una tabla, o cómo es su estructura (por
ejemplo, nombres de columnas)? MySQL aborda este problema a través de varias sentencias que
proveen información acerca de las bases de datos y tablas que soporta.
Ya se ha visto SHOW DATABASES, la cual informa las bases de datos gestionadas por el servidor. Para
conocer la base de datos actualmente seleccionada, se utiliza la funcion DATABASE():
mysql> SELECT DATABASE();
+------------+
| DATABASE() |
+------------+
| menagerie |
+------------+
Si aún no se hubiese seleccionado ninguna base de datos, el resultado sería NULL.
Para conocer las tablas contenidas en la base de datos actual (por ejemplo, si no se está seguro del
nombre de una tabla) se usa el siguiente comando:
mysql> SHOW TABLES;
+---------------------+
| Tables in menagerie |
+---------------------+
| event
|
| pet
|
+---------------------+
Si lo que se desea es ver la estructura de una tabla, el comando DESCRIBE es útil; muestra información
acerca de cada columna de la tabla:
mysql> DESCRIBE pet;
+---------+-------------+------+-----+---------+-------+
| Field
| Type
| Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| name
| varchar(20) | YES |
| NULL
|
|
| owner
| varchar(20) | YES |
| NULL
|
|
| species | varchar(20) | YES |
| NULL
|
|
| sex
| char(1)
| YES |
| NULL
|
|
| birth
| date
| YES |
| NULL
|
|
| death
| date
| YES |
| NULL
|
|
+---------+-------------+------+-----+---------+-------+
Field contiene el nombre de la columna, Type es el tipo de dato, NULL señala si la columna puede
contener valores NULL, Key indica si la columna está indexada, y Default informa el valor por defecto de
la columna.
Si una tabla tiene índices, SHOW INDEX FROM tbl_name muestra información sobre ellos.
183
Usar mysql en modo batch
3.5. Usar mysql en modo batch
En las secciones previas mysql se utilizó interactivamente para ejecutar consultas y ver resultados.
También se puede ejecutar en un modo por lotes. Para ello, los comandos que se desea ejecutar deben
colocarse en un archivo, y posteriormente indicarle a mysql que acepte como entrada el contenido del
mismo.
shell> mysql < batch-file
Si está ejecutando mysql en Windows y el archivo contiene algunos caracteres que causan problemas, el
comando es así:
C:\> mysql -e "source batch-file"
Si se necesitara incluir parámetros de conexión en la línea de comandos, el comando podría verse así:
shell> mysql -h host -u user -p < batch-file
Enter password: ********
Cuando se procede de este modo lo que se está haciendo es crear un archivo script, que luego es
ejecutado.
Si se desea que el script continúe su ejecución aunque alguna de sus sentencias produzca errores, se
debe usar la opción de línea de comandos --force.
¿Por qué usar scripts? Algunas razones:
• Si se utiliza una consulta repetidamente (por ejemplo cada día o cada semana), hacer un script evitará
volver a teclearla cada vez que se desea ejecutarla.
• Se pueden crear nuevas consultas a partir de otras existentes que se le parezcan, copiando y editando
el archivo de script.
• El modo por lotes también puede ser útil cuando se está creando una consulta, en especial si tiene
comandos de múltiples líneas o múltiples sentencias. Si se comete un error, no se necesita reteclearlo
todo, sino sólo editar el script para corregir el error, y volver a ejecutarlo mediante mysql.
• Si se ejecuta una consulta que produce una salida muy extensa, se puede ejecutar a traves de un
paginador en lugar de verla desaparecer rápidamente por la parte superior de la pantalla:
shell> mysql < batch-file | more
• Se puede enviar la salida a un archivo, para posterior proceso:
shell> mysql < batch-file > mysql.out
• Se puede distribuir el script a otras personas, para que puedan tambien ejecutar los comandos.
• Algunas situaciones no permiten la interactividad, por ejemplo, cuando se ejecuta una consulta a través
de una tarea de cron (en Unix). En este caso, debe emplearse el modo por lotes.
El formato de salida es más breve cuando se usa modo por lotes que cuando se utiliza mysql
interactivamente. Por ejemplo, la salida devuelta para SELECT DISTINCT species FROM pet se ve
así cuando se ejecuta en modo interactivo:
+---------+
| species |
+---------+
| bird
|
184
Ejemplos de consultas comunes
| cat
|
| dog
|
| hamster |
| snake
|
+---------+
Mientras que, en modo por lotes, presenta este aspecto:
species
bird
cat
dog
hamster
snake
Si desea obtener el formato por lotes para una salida producida interactivamente, utilice mysql -t. Para
incluir en la salida los comandos que se ejecutan, utilice mysql -vvv.
También pueden ejecutarse archivos de script desde el prompt mysql utilizando los comandos source o
\.
mysql> source filename;
mysql> \. filename
3.6. Ejemplos de consultas comunes
Aquí tiene ejemplos de como resolver algunos problemas comunes mediante MySQL.
Algunos de los ejemplos emplean la tabla shop para contener el precio de cada artículo (número de item)
para ciertos distribuidores (dealers). Suponiendo que cada distribuidor tiene un único precio fijo por cada
artículo, entonces (article, dealer) es una clave primaria para los registros.
Inicie la utilidad de línea de comandos mysql y seleccione una base de datos:
shell> mysql base-de-datos
(En la mayoría de las instalaciones de MySQL, podrá emplear la base de datos test).
Puede crear e ingresar datos a la tabla del ejemplo utilizando estas sentencias:
mysql>
->
->
->
->
mysql>
->
->
CREATE TABLE shop (
article INT(4) UNSIGNED ZEROFILL DEFAULT '0000' NOT NULL,
dealer CHAR(20)
DEFAULT ''
NOT NULL,
price
DOUBLE(16,2)
DEFAULT '0.00' NOT NULL,
PRIMARY KEY(article, dealer));
INSERT INTO shop VALUES
(1,'A',3.45),(1,'B',3.99),(2,'A',10.99),(3,'B',1.45),
(3,'C',1.69),(3,'D',1.25),(4,'D',19.95);
Luego de ejecutar estas sentencias, la tabla debería tener el siguiente contenido:
mysql> SELECT * FROM shop;
+---------+--------+-------+
| article | dealer | price |
+---------+--------+-------+
|
0001 | A
| 3.45 |
|
0001 | B
| 3.99 |
|
0002 | A
| 10.99 |
|
0003 | B
| 1.45 |
|
0003 | C
| 1.69 |
|
0003 | D
| 1.25 |
|
0004 | D
| 19.95 |
185
El valor máximo de una columna
+---------+--------+-------+
3.6.1. El valor máximo de una columna
“¿Cuál es el número de ítem más alto?”
SELECT MAX(article) AS article FROM shop;
+---------+
| article |
+---------+
|
4 |
+---------+
3.6.2. El registro que tiene el valor máximo de determinada columna
Tarea: Encontrar el número, distribuidor y precio del artículo más costoso.
En MySQL 5.0 (y en SQL estándar), esto se hace fácilmente con una subconsulta:
SELECT article, dealer, price
FROM
shop
WHERE price=(SELECT MAX(price) FROM shop);
Otra solución es ordenar las columnas por precio, en forma descendente, y obtener solamente el primer
registro utilizando la cláusula LIMIT, específica de MySQL:
SELECT article, dealer, price
FROM
shop
ORDER BY price DESC
LIMIT 1;
Nota: Si hubiera varios artículos que presenten el precio más alto, cada uno a 19.95, la solución LIMIT
sólo mostraría el primero de ellos.
3.6.3. Máximo de columna por grupo
Tarea: Encontrar el precio más alto por artículo.
SELECT article, MAX(price) AS price
FROM
shop
GROUP BY article
+---------+-------+
| article | price |
+---------+-------+
|
0001 | 3.99 |
|
0002 | 10.99 |
|
0003 | 1.69 |
|
0004 | 19.95 |
+---------+-------+
3.6.4. Los registros de un grupo que tienen el máximo valor en alguna
columna
Tarea: Para cada artículo, encontrar el o los distribuidores con el precio más alto.
En MySQL 5.0 (y en SQL estándar), este problema puede resolverse con una subconsulta como esta:
SELECT article, dealer, price
186
Utilización de variables de usuario
FROM
WHERE
shop s1
price=(SELECT MAX(s2.price)
FROM shop s2
WHERE s1.article = s2.article);
3.6.5. Utilización de variables de usuario
Se pueden emplear variables de usuario de MySQL para retener resultados sin necesidad de
almacenarlos en variables del lado del cliente. (Consulte Sección 9.3, “Variables de usuario”.)
Por ejemplo, para encontrar los artículos con el precio más alto y más bajo se puede hacer lo siguiente:
mysql> SELECT @min_price:=MIN(price),@max_price:=MAX(price) FROM shop;
mysql> SELECT * FROM shop WHERE price=@min_price OR price=@max_price;
+---------+--------+-------+
| article | dealer | price |
+---------+--------+-------+
|
0003 | D
| 1.25 |
|
0004 | D
| 19.95 |
+---------+--------+-------+
3.6.6. Usar claves foráneas (foreign keys)
En MySQL, las tablas InnoDB soportan restricciones de claves foráneas. Consulte Capítulo 15, El motor
de almacenamiento InnoDB. Consulte también Sección 1.7.5.5, “Claves foráneas (foreign keys)”.
No se requiere una restricción de clave foránea para simplemente unir dos tablas. Para otros tipos
de tabla que no sean InnoDB, es posible, al momento de definir una columna, utilizar una cláusula
REFERENCEStbl_name (col_name), la cual no tiene efecto real y funciona solamente como un
recordatorio o comentario de que la columna que se está definiendo está dirigida a hacer referencia a una
columna en otra tabla. Al emplear esta sintaxis es muy importante comprender que:
• MySQL no efectúa ningún tipo de CHECK o comprobación para asegurarse de que col_name realmente
existe en tbl_name (o incluso que tbl_name existe).
• MySQL no realiza ningún tipo de acción sobre tbl_name tal como borrar filas en respuesta a acciones
ejecutadas sobre filas en la tabla que se está definiendo; en otras palabras, esta sintaxis no produce
por sí misma un comportamiento ON DELETE u ON UPDATE. (Inclusive cuando se puede escribir
una cláusula ON DELETE u ON UPDATE como parte de la cláusula REFERENCES, estas son también
ignoradas).
• Esta sintaxis crea una columna; no crea ninguna clase de índice o campo clave.
• Esta sintaxis causará un error si se la emplea durante la definición de una tabla InnoDB.
Una columna creada de esta forma se puede utilizar como columna de unión, como se muestra aquí:
CREATE TABLE person (
id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
name CHAR(60) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE shirt (
id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
style ENUM('t-shirt', 'polo', 'dress') NOT NULL,
color ENUM('red', 'blue', 'orange', 'white', 'black') NOT NULL,
owner SMALLINT UNSIGNED NOT NULL REFERENCES person(id),
PRIMARY KEY (id)
);
187
Usar claves foráneas (foreign keys)
INSERT INTO person VALUES (NULL, 'Antonio Paz');
SELECT @last := LAST_INSERT_ID();
INSERT
(NULL,
(NULL,
(NULL,
INTO shirt VALUES
'polo', 'blue', @last),
'dress', 'white', @last),
't-shirt', 'blue', @last);
INSERT INTO person VALUES (NULL, 'Lilliana Angelovska');
SELECT @last := LAST_INSERT_ID();
INSERT
(NULL,
(NULL,
(NULL,
(NULL,
INTO shirt VALUES
'dress', 'orange', @last),
'polo', 'red', @last),
'dress', 'blue', @last),
't-shirt', 'white', @last);
SELECT * FROM person;
+----+---------------------+
| id | name
|
+----+---------------------+
| 1 | Antonio Paz
|
| 2 | Lilliana Angelovska |
+----+---------------------+
SELECT * FROM shirt;
+----+---------+--------+-------+
| id | style
| color | owner |
+----+---------+--------+-------+
| 1 | polo
| blue
|
1 |
| 2 | dress
| white |
1 |
| 3 | t-shirt | blue
|
1 |
| 4 | dress
| orange |
2 |
| 5 | polo
| red
|
2 |
| 6 | dress
| blue
|
2 |
| 7 | t-shirt | white |
2 |
+----+---------+--------+-------+
SELECT
WHERE
AND
AND
s.* FROM person p, shirt s
p.name LIKE 'Lilliana%'
s.owner = p.id
s.color <> 'white';
+----+-------+--------+-------+
| id | style | color | owner |
+----+-------+--------+-------+
| 4 | dress | orange |
2 |
| 5 | polo | red
|
2 |
| 6 | dress | blue
|
2 |
+----+-------+--------+-------+
Cuando se usa de esta manera, la cláusula REFERENCES no es mostrada en la salida de SHOW CREATE
TABLE o DESCRIBE:
SHOW CREATE TABLE shirt\G
*************************** 1. row ***************************
Table: shirt
Create Table: CREATE TABLE `shirt` (
`id` smallint(5) unsigned NOT NULL auto_increment,
`style` enum('t-shirt','polo','dress') NOT NULL,
`color` enum('red','blue','orange','white','black') NOT NULL,
`owner` smallint(5) unsigned NOT NULL,
PRIMARY KEY (`id`)
188
Buscar usando dos claves
) ENGINE=MyISAM DEFAULT CHARSET=latin1
El uso de REFERENCES como comentario o "recordatorio" en la definición de una columna funciona en
tablas MyISAM y BerkeleyDB.
3.6.7. Buscar usando dos claves
Un OR empleando una única clave es bien optimizado, como es el manejo de AND
El único caso difícil es la búsqueda sobre dos diferentes claves combinadas con OR:
SELECT field1_index, field2_index FROM test_table
WHERE field1_index = '1' OR field2_index = '1'
Esto se ha optimizado a partir de MySQL 5.0.0. Consulte Sección 7.2.6, “Index Merge Optimization”.
En MySQL 5.0 tambien se puede resolver eficientemente este problema utilizando una UNION que
combine la salida de dos sentencias SELECT separadas. Consulte Sección 13.2.7.2, “Sintaxis de UNION”.
Cada sentencia SELECT busca en solamente una clave y puede ser optimizada:
SELECT field1_index, field2_index
FROM test_table WHERE field1_index = '1'
UNION
SELECT field1_index, field2_index
FROM test_table WHERE field2_index = '1';
3.6.8. Calcular visitas diarias
El siguiente ejemplo muestra cómo se pueden utilizar las funciones de bits para calcular la cantidad de
dias de un mes que un usuario ha visitado una página Web.
CREATE TABLE t1 (year YEAR(4), month INT(2) UNSIGNED ZEROFILL,
day INT(2) UNSIGNED ZEROFILL);
INSERT INTO t1 VALUES(2000,1,1),(2000,1,20),(2000,1,30),(2000,2,2),
(2000,2,23),(2000,2,23);
La tabla del ejemplo contiene valores de año, mes y dia que representan las visitas de los usuarios a la
página. Para determinar en cuántos días diferentes del mes se produjeron las visitas, se emplea esta
consulta:
SELECT year,month,BIT_COUNT(BIT_OR(1<<day)) AS days FROM t1
GROUP BY year,month;
La cual devuelve:
+------+-------+------+
| year | month | days |
+------+-------+------+
| 2000 |
01 |
3 |
| 2000 |
02 |
2 |
+------+-------+------+
La consulta calcula cuantos días diferentes aparecen en la tabla para cada combinación de año y mes,
removiendo automáticamente las entradas duplicadas.
3.6.9. Utilización de AUTO_INCREMENT
El atributo AUTO_INCREMENT puede utilizarse para generar un identificador único para cada nueva fila:
CREATE TABLE animals (
189
Utilización de AUTO_INCREMENT
id MEDIUMINT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (id)
);
INSERT INTO animals (name) VALUES ('dog'),('cat'),('penguin'),
('lax'),('whale'),('ostrich');
SELECT * FROM animals;
Lo cual devuelve:
+----+---------+
| id | name
|
+----+---------+
| 1 | dog
|
| 2 | cat
|
| 3 | penguin |
| 4 | lax
|
| 5 | whale
|
| 6 | ostrich |
+----+---------+
Para obtener el valor AUTO_INCREMENT más recientemente generado se puede utilizar la funcion SQL
LAST_INSERT_ID() o la función del API de C mysql_insert_id(). Estas funciones son específicas
de cada conexión, de modo que su valor de retorno no es afectado por las inserciones realizadas a través
de otras conexiones.
Nota: Para una inserción de múltiples filas, LAST_INSERT_ID()/mysql_insert_id() retornan el valor
AUTO_INCREMENT de la primera de las filas insertadas. Esto permite que las inserciones de múltiples filas
sean reproducidas correctamente en otros servidores en una configuración de replicación.
Para tablas MyISAM y BDB se puede especificar AUTO_INCREMENT sobre una columna secundaria en
un índice de múltiples columnas. En este caso, el valor generado para la columna AUTO_INCREMENT es
calculado como MAX(auto_increment_column)+1 WHERE prefix=given-prefix. Esto es útil
cuando se desea colocar datos en grupos ordenados.
CREATE TABLE animals (
grp ENUM('fish','mammal','bird') NOT NULL,
id MEDIUMINT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (grp,id)
);
INSERT INTO animals (grp,name) VALUES('mammal','dog'),('mammal','cat'),
('bird','penguin'),('fish','lax'),('mammal','whale'),
('bird','ostrich');
SELECT * FROM animals ORDER BY grp,id;
Lo cual devuelve:
+--------+----+---------+
| grp
| id | name
|
+--------+----+---------+
| fish
| 1 | lax
|
| mammal | 1 | dog
|
| mammal | 2 | cat
|
| mammal | 3 | whale
|
| bird
| 1 | penguin |
| bird
| 2 | ostrich |
+--------+----+---------+
Nótese que en este caso (cuando la columna AUTO_INCREMENT es parte de un índice de
múltiples columnas), los valores AUTO_INCREMENT son reutilizados si se elimina la fila con el valor
AUTO_INCREMENT más alto en cualquier grupo. Esto ocurre incluso para tablas MyISAM, en las que los
valores AUTO_INCREMENT normalmente no son reutilizados
190
Consultas del proyecto Mellizos (Twin)
Si la columna AUTO_INCREMENT es parte de varios índices, MySQL generará valores secuenciales
empleando el índice que comienza con la columna AUTO_INCREMENT, si hay uno. Por ejemplo, si la
tabla animals contiene los índices PRIMARY KEY (grp, id) e INDEX (id), MySQL ignoraría el
índice PRIMARY KEY al generar valores secuenciales. Como resultado, la tabla contendría una secuencia
simple, sin considerar el valor grp.
3.7. Consultas del proyecto Mellizos (Twin)
En Analytikerna y Lentus, hemos estado realizando los sistemas y el trabajo de campo para un gran
proyecto de investigación. Este proyecto es en colaboración entre el Institute of Environmental Medicine
del Karolinska Institutet Stockholm y la Sección de Investigación Clínica sobre Envejecimiento y Psicología
de la Universidad de California del Sur.
El proyecto comprende una parte de selección, en la cual se entrevista por teléfono a todos los gemelos
de Suecia mayores de 65 años. Aquellos que satisfacen ciertos criterios son pasados a la siguiente
etapa. En esta, los gemelos que desean participar son visitados por un equipo de médico y enfermera.
Algunos de los éxamenes practicados son físico, neuropsicológico, laboratorio, diagnóstico neurológico
por imágenes, evaluación de estado psicológico, y recolección de la historia familiar. Adicionalmete, se
recogen datos sobre factores de riesgo médicos y ambientales.
Se puede ver más información sobre estudio de Gemelos en: http://www.mep.ki.se/twinreg/index_en.html
La última parte del proyecto es administrada mediante una interface Web escrita usando Perl y MySQL.
Cada noche, los datos de las entrevistas son volcados en una base de datos MySQL.
3.7.1. Encontrar todos los mellizos no repartidos
La siguiente consulta es empleada para determinar quiénes pasan a la segunda parte del proyecto:
SELECT
CONCAT(p1.id, p1.tvab) + 0 AS tvid,
CONCAT(p1.christian_name, ' ', p1.surname) AS Name,
p1.postal_code AS Code,
p1.city AS City,
pg.abrev AS Area,
IF(td.participation = 'Aborted', 'A', ' ') AS A,
p1.dead AS dead1,
l.event AS event1,
td.suspect AS tsuspect1,
id.suspect AS isuspect1,
td.severe AS tsevere1,
id.severe AS isevere1,
p2.dead AS dead2,
l2.event AS event2,
h2.nurse AS nurse2,
h2.doctor AS doctor2,
td2.suspect AS tsuspect2,
id2.suspect AS isuspect2,
td2.severe AS tsevere2,
id2.severe AS isevere2,
l.finish_date
FROM
twin_project AS tp
/* For Twin 1 */
LEFT JOIN twin_data AS td ON tp.id = td.id
AND tp.tvab = td.tvab
LEFT JOIN informant_data AS id ON tp.id = id.id
AND tp.tvab = id.tvab
LEFT JOIN harmony AS h ON tp.id = h.id
191
Encontrar todos los mellizos no repartidos
AND tp.tvab = h.tvab
LEFT JOIN lentus AS l ON tp.id = l.id
AND tp.tvab = l.tvab
/* For Twin 2 */
LEFT JOIN twin_data AS td2 ON p2.id = td2.id
AND p2.tvab = td2.tvab
LEFT JOIN informant_data AS id2 ON p2.id = id2.id
AND p2.tvab = id2.tvab
LEFT JOIN harmony AS h2 ON p2.id = h2.id
AND p2.tvab = h2.tvab
LEFT JOIN lentus AS l2 ON p2.id = l2.id
AND p2.tvab = l2.tvab,
person_data AS p1,
person_data AS p2,
postal_groups AS pg
WHERE
/* p1 gets main twin and p2 gets his/her twin. */
/* ptvab is a field inverted from tvab */
p1.id = tp.id AND p1.tvab = tp.tvab AND
p2.id = p1.id AND p2.ptvab = p1.tvab AND
/* Just the screening survey */
tp.survey_no = 5 AND
/* Skip if partner died before 65 but allow emigration (dead=9) */
(p2.dead = 0 OR p2.dead = 9 OR
(p2.dead = 1 AND
(p2.death_date = 0 OR
(((TO_DAYS(p2.death_date) - TO_DAYS(p2.birthday)) / 365)
>= 65))))
AND
(
/* Twin is suspect */
(td.future_contact = 'Yes' AND td.suspect = 2) OR
/* Twin is suspect - Informant is Blessed */
(td.future_contact = 'Yes' AND td.suspect = 1
AND id.suspect = 1) OR
/* No twin - Informant is Blessed */
(ISNULL(td.suspect) AND id.suspect = 1
AND id.future_contact = 'Yes') OR
/* Twin broken off - Informant is Blessed */
(td.participation = 'Aborted'
AND id.suspect = 1 AND id.future_contact = 'Yes') OR
/* Twin broken off - No inform - Have partner */
(td.participation = 'Aborted' AND ISNULL(id.suspect)
AND p2.dead = 0))
AND
l.event = 'Finished'
/* Get at area code */
AND SUBSTRING(p1.postal_code, 1, 2) = pg.code
/* Not already distributed */
AND (h.nurse IS NULL OR h.nurse=00 OR h.doctor=00)
/* Has not refused or been aborted */
AND NOT (h.status = 'Refused' OR h.status = 'Aborted'
OR h.status = 'Died' OR h.status = 'Other')
ORDER BY
tvid;
Algunas explicaciones:
• CONCAT(p1.id, p1.tvab) + 0 AS tvid
Se desea ordenar por la concatenación de id y tvab en orden numérico. El agregado de 0 al resultado
provoca que MySQL lo trate como un número.
• columna id
Identifica una pareja de gemelos. Es un campo clave en todas las tablas.
192
Mostrar una tabla de estado de mellizos
• columna tvab
Identifica a un gemelo en una pareja. Toma un valor de 1 o 2.
• columna ptvab
Es lo inverso de tvab. Cuando tvab. vale 1, este vale 2, y viceversa. El motivo de su existencia es
para ahorrar tipeo y facilitarle a MySQL la optimización de la consulta.
Esta consulta muestra, entre otras cosas, cómo realizar búsquedas en una tabla a partir de la misma tabla
con una unión (p1 y p2). En el ejemplo, esto se usa para verificar cuándo una pareja de gemelos murieron
antes de cumplir los 65 años. Si sucede eso, la fila no se devuelve.
Todo lo mencionado anteriormente existe en todas las tablas con información relativa a gemelos. Hay un
índice definido sobre los campos id,tvab (en todas las tablas) y sobre id,ptvab (person_data) para
realizar las consultas más rápidamente.
En nuestra máquina de producción (un UltraSPARC a 200Mhz), esta consulta devuelve cerca de 150-200
filas y toma menos de un segundo.
La cantidad actual de registros en las tablas usadas en la consulta:
Table
Rows
person_data
71074
lentus
5291
twin_project
5286
twin_data
2012
informant_data
663
harmony
381
postal_groups
100
3.7.2. Mostrar una tabla de estado de mellizos
Cada entrevista termina con un código de estado llamado event. La consulta mostrada aquí se emplea
para mostrar una tabla sobre todas las parejas de gemelos combinadas por evento. Esto indica en
cuantas parejas ambos gemelos llegaron al final, en cuantas uno llego y el otro fue rechazado, etc.
SELECT
t1.event,
t2.event,
COUNT(*)
FROM
lentus AS t1,
lentus AS t2,
twin_project AS tp
WHERE
/* We are looking at one pair at a time */
t1.id = tp.id
AND t1.tvab=tp.tvab
AND t1.id = t2.id
/* Just the screening survey */
AND tp.survey_no = 5
/* This makes each pair only appear once */
AND t1.tvab='1' AND t2.tvab='2'
GROUP BY
t1.event, t2.event;
193
Usar MySQL con Apache
3.8. Usar MySQL con Apache
Existen programas que permiten autenticar usuarios a partir de una base de datos MySQL y también
escribir ficheros de log en una tabla MySQL.
Se puede modificar el formato de logging de Apache para que MySQL pueda interpretarlo, colocando lo
siguiente en el fichero de configuración de Apache:
LogFormat \
"\"%h\",%{%Y%m%d%H%M%S}t,%>s,\"%b\",\"%{Content-Type}o\",
\"%U\",\"%{Referer}i\",\"%{User-Agent}i\""
\
Para cargar dentro de MySQL un fichero de log en dicho formato, se puede emplear una sentencia como
esta:
LOAD DATA INFILE '/local/access_log' INTO TABLE tbl_name
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\'
La tabla destino debería ser creada de forma que contenga las columnas tal como las especifica la línea
LogFormat.
194
Download