Professional Documents
Culture Documents
Alejandro Sueldo
En este artículo se explica el uso de la sentencia SELECT para realizar consultas a bases de datos MySQL. Se explican
muchos conceptos relacionados al uso de la sentencia SELECT, pero sobre todo, se incluyen una gran cantidad de
ejemplos y ejercicios.
Supongamos que usted ha instalado MySQL en una empresa. En ese caso los empleados tienen interés en poder
realizar consultas a la base de datos. Pasado un tiempo, a un nivel gerencial medio se desarrolla un considerable
interés en poder realizar consultas directamente. Es muy conveniente poder realizar consultas sin pasar por un
mecanismo burocrático o incurrir en mayores costos.
Este tutorial puede servir de base para un curso. En general, los estudiantes deberían tener alguna experiencia previa
como operadores. O quizás usted desarrolla aplicaciones y se encuentra con MySQL instalado. Quiere aprender
rápidamente (por ejemplo, en un día) a realizar consultas en mysql, con peculiar atención a los problemitas que se
generan con relación a los tildes, los formatos de fecha, etc.
Suponemos que tenemos a disposición un servidor MySQL versión 4.1.3b-beta o posterior. Versiones anteriores pueden
servir para casi todo el curso, pero en algunas pueden no funcionar los subqueries.
- Índice
- Manejo de fechas.
- Agrupando datos.
- Subqueries.
- Salida a Excel.
- El funcionamiento de SELECT.
- Glosario.
- Bibliografía.
El proceso por el que normalmente se extrae información de una base de datos, en SQL, es la instrucción SELECT.
Veremos a continuación varios problemas, con sus soluciones, relativos a SELECT.
En estos problemas utilizaremos una base de datos llamada empresa. Se dispone de una instalación de la base de datos
para Windows. Baje el archivo crear_empresa.sql de aquí.
En lo que sigue suponemos que hay un directorio C:\mysql\bin donde tenemos el cliente mysql que se llama justamente
mysql.exe. Si no es así, tendremos que averiguar en qué directorio se encuentra, y en todo lo que sigue se deberá
sustituir C:\mysql\bin por el directorio donde se encuentra mysql.exe. Cree un directorio dentro del c:\mysql\bin con un
nombre corto. Para lo que sigue supondremos que dicho directorio es c:\mysql\bin\p.
Asegúrese que el servidor MySQL funciona. Si usted está trabajando directamente en el equipo que tiene instalado el
servidor puede iniciarlo con el programa WinMySqlAdmin. Este programa se encuentra normalmente en el directorio
c:\mysql\bin. Por otra parte, si está accediendo a un servidor en red, supondremos que el servidor está funcionando.
De lo contrario deberá contactar al administrador de la red.
Ejecute el cliente mysql, según el siguientes procedimiento. En la mayoría de las instalaciones usted debería tener un
nombre de usuario y un password (clave). Basta que cree una ventana MS-DOS (busque MS-DOS, o Símbolo de
Sistema, en Inicio, Programas) y luego escriba
C:\WINDOWS > cd c:\mysql\bin C:\mysql\bin > mysql -uUsuario –pClave
donde Usuario debe sustituirse por su nombre de usuario y Clave por su clave. Si usted está accediendo desde el
equipo donde está instalado el servidor, probablemente no necesite usuario ni clave. En ese caso, ingrese simplemente
el comando mysql.
C:\MySQL\bin > mysql
En este momento debería crearse la base de datos. Ya está listo para comenzar el curso. Si tiene dificultades, es
posible que el administrador de base de datos no le haya dado suficientes "derechos". Quizás usted no tenga "derecho"
a crear una base de datos, por ejemplo. Contáctelo y solicítele poder crear y tener todos los derechos sobre la base
empresa.
Recibimos un mensaje "Database changed" (base de datos cambiada). Una base de datos está formada por tablas,
muy semejantes a las tablas de cualquier libro.
Para ver qué contiene alguna de esas tablas escribimos nuestra primera instrucción SELECT :
mysql> SELECT * FROM sucursales; +----+-------------+ | id | descripcion | +----+-------------+ | 1 | Centro | | 2 | Unión
| | 3 | Malvín | +----+-------------+
Esta tabla está formada por dos columnas: Id y Descripcion. Los nombres de columnas tampoco pueden llevar tildes.
Debajo de los nombres están los valores. Tenemos una fila, por ejemplo, donde Id vale 2 y Descripcion es "Unión". Para
averiguar más sobre esta tabla escribimos:
mysql> DESCRIBE sucursales; +-------------+------------------+------+-----+---------+----------------+ | Field | Type |
Null | Key | Default | Extra | +-------------+------------------+------+-----+---------+----------------+ | id | int(10) unsigned
| | PRI | NULL | auto_increment | | descripcion | varchar(15) | | | | | +-------------+------------------
+------+-----+---------+----------------+
La instrucción "DESCRIBE sucursales" se podría traducir como "Realice una descripción de la tabla sucursales". Cada fila
es una descripción de la columna cuyo nombre figura a la izquierda. En este caso, la 2º fila describe Id y la 3ª describe
Descripcion. Esta descripción de la tabla sucursales contiene información más bien técnica, pero algunas partes son
importantes:
El varchar(15) que se encuentra en la 3ª fila, 2ºcolumna significa que la columna Descripcion puede tener un número
variable de caracteres, hasta 15. Análogamente el int(10) que se encuentra en la 2ª fila, 2ª columna indica que Id es un
número entero.
La palabra PRI que se encuentra en la 2ªfila, 4ª columna significa que Id caracteriza de manera única una fila. Es decir,
cada fila de sucursales va a tener un número que va a estar en la columna Id. Diferentes filas tendrán diferentes
números. De manera que un valor de Id, si está en la tabla, determina una fila. PRI es una abreviatura de PRIMARY
KEY , clave primaria. Esta es una expresión usada en computación para indicar una columna que se usa para identificar
las filas. Es algo así como el número de documento de identidad para las personas. Si se quiere hacer una referencia a
una sucursal en otra tabla se usa el Id.
Sugerimos que el estudiante explore, usando SELECT * FROM ... y DESCRIBE ..., sobre las diversas tablas de la base
de datos empresa.
Tipos de datos
En una tabla cada columna es de un tipo de datos. Para nuestros fines hay 3 grandes tipos de datos: numéricos,
cadenas de caracteres y fechas.
Los datos numéricos pueden ser enteros (int) o decimales (decimal). Los decimales tienen una parte entera y una
fraccionaria. Por ejemplo, un decimal puede valer 120.40.
Las cadenas de caracteres representan texto, generalmente con un largo variable, hasta un máximo dado. Pueden
contener letras, números y otros caracteres como ‘=’,’+’, etc.
Ya vimos un ejemplo con la columna Descripcion de la tabla sucursales. Las columnas de tipo fecha tienen, en su
descripción, la palabra "date". Cualquier columna puede, en principio, tomar el valor NULL, que representa un valor
desconocido o inexistente. Sin embargo, cuando se crearon las tablas el administrador de la base de datos
normalmente especificó que la mayoría de las columnas no pueden tomar valores NULL. Las que sí pueden aparecen con
la palabra YES en la columna NULL de la tabla que se obtiene haciendo el query "DESCRIBE nombre_de_tabla" .
Vemos que por ejemplo en la tabla Sucursales la base de datos no aceptará un valor NULL ni en Id ni en Descripcion.
Para exhibir los valores de una columna determinada de una tabla, usamos SELECT Nombre_de_columna FROM
Nombre_de_tabla;
Ejemplo :
mysql> SELECT descripcion FROM sucursales; +-------------+ | descripcion | +-------------+ | Centro | | Unión | | Malvín
| +-------------+
Para seleccionar más de una columna, SELECT Nombre_de_columna_1, Nombre_de_columna_2,... FROM
Nombre_de_tabla;
Ejemplo:
mysql> SELECT nombre, direccion FROM clientes; +-------------+---------------------+ | nombre | direccion | +---------
----+---------------------+ | Matt Design | NULL | | Diana Pérez | Brito del Pino 1120 | | John Smith | Zum Felde
2024 | +-------------+---------------------+
Para seleccionar todas las columnas de una tabla, SELECT * FROM Nombre_de_tabla;
Ejemplo:
mysql> SELECT * FROM ventas; +----+---------+----------+---------+----------+----------+----------+------------+ | id | cliente |
vendedor | importe | articulo | cantidad | sucursal | fecha | +----+---------+----------+---------+----------+----------+----------+----
--------+ | 1 | 1| 1 | 178.50 | 1| 1| 1 | 2004-10-01 | | 2 | 2| 1 | 195.00 | 2| 1|
2 | 2004-10-05 | | 3 | 3| 1 | 178.50 | 1| 1 | NULL | 2004-10-07 | | 4 | 1| 1 | 16.00 | 7|
2| 2 | 2004-11-01 | | 5 | 1| 2 | 220.00 | 3| 1| 1 | 2004-12-02 | | 6 | 1| 1 | 5.50 |
5| 1| 1 | 2004-10-02 | | 7 | 1| 2 | 11.00 | 5| 2| 1 | 2004-10-03 | | 8 | 1| 2|
5.50 | 5| 1| 1 | 2005-01-01 | | 9 | 2| 1 | 200.00 | 2| 1| 2 | 2004-10-12 | +----+---------+-
---------+---------+----------+----------+----------+------------+
Obsérvese que los clientes, vendedores, artículos y sucursales son identificados por su Id. El importe representa el total
de la venta, no el precio unitario. También se pueden hacer cálculos con una columna numérica.
Ejemplos:
mysql> SELECT importe, 0.10*importe FROM ventas; +---------+--------------+ | importe | 0.10*importe | +---------+-------------
-+ | 178.50 | 17.85 | | 195.00 | 19.50 | | 178.50 | 17.85 | | 16.00 | 1.60 | | 220.00 | 22.00 | |
5.50 | 0.55 | | 11.00 | 1.10 | | 5.50 | 0.55 | | 200.00 | 20.00 | +---------+--------------+
Se pueden agregar a la salida columnas constantes, que no tienen relación con las tablas
Ejemplo:
mysql> SELECT "Impuesto", 0.10*importe FROM ventas; +----------+--------------+ | Impuesto | 0.10*importe | +----------+-----
---------+ | Impuesto | 17.85 | | Impuesto | 19.50 | | Impuesto | 17.85 | | Impuesto | 1.60 | | Impuesto |
22.00 | | Impuesto | 0.55 | | Impuesto | 1.10 | | Impuesto | 0.55 | | Impuesto | 20.00 | +----------+-----------
---+
En general es deseable no tener títulos de columna complicados como "0.10*Importe". Para esos casos se usa la
instrucción AS ( que significa, entre otras cosas, "como").
Ejemplo:
mysql> SELECT 0.10*importe AS impuesto FROM ventas; +----------+ | impuesto | +----------+ | 17.85 | | 19.50 | |
17.85 | | 1.60 | | 22.00 | | 0.55 | | 1.10 | | 0.55 | | 20.00 | +----------+
Se puede solicitar que no haya repeticiones en las filas seleccionadas. Basta agregar DISTINCT después del SELECT.
Ejemplo:
mysql> SELECT DISTINCT cliente FROM ventas; +---------+ | cliente | +---------+ | 1|| 2|| 3 | +---------+
Los resultados de cálculos, si no se toma alguna medida al respecto, a veces salen con demasiados decimales. En
esos casos, conviene usar la función ROUND. Esta función redondea los números a la cantidad deseada de decimales
después del punto. Por ejemplo, ROUND(2.343,2) produce el resultado 2.34. Análogamente ROUND(2.347,2) produce
2.35, y ROUND(2.245,2) produce 2.34. Para redondear a un entero alcanza con escribir ROUND(número). Por ejemplo,
ROUND(2.345) produce 2.
Ejemplo:
http://alejandrosueldo.com.ar/joomla Potenciado por Joomla! Generado: 3 September, 2010, 02:59
Ing. Alejandro Sueldo
La cláusula WHERE.
Esta cláusula sirve para seleccionar filas, dentro de las columnas seleccionadas. WHERE significa "donde". Se pueden
seleccionar filas donde una columna tiene un valor determinado.
Ejemplo:
mysql> SELECT * FROM clientes WHERE id=1; +----+-------------+-----------+----------+ | id | nombre | direccion |
vendedor | +----+-------------+-----------+----------+ | 1 | Matt Design | NULL | 1 | +----+-------------+-----------+----------+
Se puede seleccionar filas donde una columna tiene un valor mayor (o menor) que uno dado.
Ejemplo:
mysql> SELECT * FROM clientes WHERE id < 3; +----+-------------+---------------------+----------+ | id | nombre | direccion
| vendedor | +----+-------------+---------------------+----------+ | 1 | Matt Design | NULL | 1 | | 2 | Diana
Pérez | Brito del Pino 1120 | NULL | +----+-------------+---------------------+----------+
Las igualdades y desigualdades también se aplican a cadenas de caracteres. Una cadena es menor que otra cuando es
previa en orden alfabético. Por ejemplo "azzl" < "baa" . No se distingue entre mayúsculas y minúsculas (aunque, si se
lo desea, es posible configurar el servidor MySQL para que sí distinga). Es decir, "A" < "b" < "c" < "D" y "a"="A".
Ejemplo:
mysql> SELECT * FROM clientes WHERE nombre < "i"; +----+-------------+---------------------+----------+ | id | nombre |
direccion | vendedor | +----+-------------+---------------------+----------+ | 2 | Diana Pérez | Brito del Pino 1120 | NULL
| +----+-------------+---------------------+----------+
Este SELECT listará los clientes con nombre empezando en una letra anterior a "i" en el alfabeto.
También se aplican a fechas la igualdad y desigualdad. Para referirse a una fecha, se le escribe como "Año con 4
cifras-Mes-Día". Por ejemplo, "2004-12-20" indica el 20 de Diciembre de 2004.
Ejemplo:
mysql> SELECT * FROM ventas WHERE fecha < '2004-12-20'; +----+---------+----------+---------+----------+----------+----------
+------------+ | id | cliente | vendedor | importe | articulo | cantidad | sucursal | fecha | +----+---------+----------+---------+------
----+----------+----------+------------+ | 1 | 1| 1 | 178.50 | 1| 1| 1 | 2004-10-01 | | 2 | 2| 1|
195.00 | 2| 1| 2 | 2004-10-05 | | 3 | 3| 1 | 178.50 | 1| 1 | NULL | 2004-10-07 | | 4 |
1| 1 | 16.00 | 7| 2| 2 | 2004-11-01 | | 5 | 1| 2 | 220.00 | 3| 1| 1 | 2004-12-02 | |
6| 1| 1 | 5.50 | 5| 1| 1 | 2004-10-02 | | 7 | 1| 2 | 11.00 | 5| 2| 1 | 2004-10-
03 | | 9 | 2| 1 | 200.00 | 2| 1| 2 | 2004-10-12 | +----+---------+----------+---------+----------+----------+-----
-----+------------+
Para determinar si un dato es NULL se usa la condición ‘IS NULL’. Para saber si no es NULL, se usa la
condición ‘IS NOT NULL’.
Ejemplo:
mysql> SELECT * FROM ventas WHERE sucursal IS NULL; +----+---------+----------+---------+----------+----------+----------+----
--------+ | id | cliente | vendedor | importe | articulo | cantidad | sucursal | fecha | +----+---------+----------+---------+----------
+----------+----------+------------+ | 3 | 3| 1 | 178.50 | 1| 1 | NULL | 2004-10-07 | +----+---------+----------+--
-------+----------+----------+----------+------------+
No debe usarse <>NULL. Produce resultados equivocados. Usar IS NOT NULL.
Expresión Significado
a=b
a es igual a b
a=b
a es igual a b
a <> b
a es distinto de b
a<b
a es menor que b
a>b
a es mayor que b
a <= b
a es menor o igual a b
a >= b
a es mayor o igual a b
a IS NULL
a es NULL
a IS NOT NULL
a no es NULL
Las cantidades a y b pueden ser números, cadenas de caracteres o fechas, en todos los casos. En una cláusula
WHERE se puede usar cualquier condición simple. La cláusula WHERE selecciona aquellas filas en que la condición es
verdadera.
Las condiciones simples pueden aparecer combinadas por operadores lógicos. Los operadores lógicos son AND, OR y
NOT. Aquí E y F representan condiciones.
E AND F
EyF
E es verdadera y F es verdadera
E OR F
E o F o ambos
E es verdadera o F lo es o ambas
NOT E
No E
E es falsa
NOTA : El operador NOT requiere paréntesis. Es decir se debe escribir WHERE NOT (salario >50) mientras que es
incorrecto WHERE NOT salario > 50. Se entiende que buscamos filas con salarios no mayores que 50.
Ejemplos:
Listar los empleados cuya fecha de ingreso sea anterior al 2004, o cuyo salario sea mayor que 50 ( o ambas cosas).
mysql> SELECT * FROM empleados WHERE fecha_ingreso < '2004-1-' OR salario > 50; +----+-----------------+---------------
+---------+ | id | nombre | fecha_ingreso | salario | +----+-----------------+---------------+---------+ | 1 | Carlos Zaltzman |
1999-12-10 | 10000 | | 2 | Juan Fernández | 2000-01-03 | 12000 | +----+-----------------+---------------+---------+
Listar los clientes cuyos nombres empiecen con una letra entre ‘c’ y ‘l’.
mysql> SELECT * FROM clientes WHERE "C" <= nombre AND nombre < "M"; +----+-------------+---------------------+----------
+ | id | nombre | direccion | vendedor | +----+-------------+---------------------+----------+ | 2 | Diana Pérez | Brito del
Pino 1120 | NULL | | 3 | John Smith | Zum Felde 2024 | 1 | +----+-------------+---------------------+----------+
Obsérvese que la condición apropiada para obtener los nombre que empiezan con ‘l’ es nombre
<’M’. Si escribiésemos nombre < =‘L’ no obtendríamos un nombre como ‘Luis
Zúñiga’ porque ‘L’<’Luis Zúñiga’. Se pueden usar incluso condiciones más
complicadas. Por ejemplo, supongamos que ahora queremos listar los empleados cuya fecha de ingreso es anterior al
2004, o cuyo salario sea mayor que 50, pero no ambas cosas a la vez. Entonces, debemos escribir :
mysql> SELECT * FROM empleados WHERE (fecha_ingreso < '2004-1-1' OR salario > 50) -> AND NOT
(fecha_ingreso < '2004-1-1' AND salario > 50); Empty set (0.00 sec)
El resultado es "Empty set", es decir, no hay filas que cumplan la condición. En el caso de condiciones más complicadas
se recomienda un amplio uso de paréntesis.
La cláusula ORDER BY
La cláusula ORDER BY produce una ordenación de las filas de salida del query. Se puede ordenar por una columna
seleccionada.
mysql> SELECT cliente, articulo FROM ventas ORDER BY cliente; +---------+----------+ | cliente | articulo | +---------+---------
-+ | 1| 1|| 1| 7|| 1| 3|| 1| 5|| 1| 5|| 1| 5|| 2| 2|| 2|
2|| 3| 1 | +---------+----------+
También se puede ordenar por varias columnas.
mysql> SELECT cliente, vendedor, articulo FROM ventas ORDER BY cliente, vendedor; +---------+----------+----------+ |
cliente | vendedor | articulo | +---------+----------+----------+ | 1| 1| 1|| 1| 1| 7|| 1| 1|
5|| 1| 2| 3|| 1| 2| 5|| 1| 2| 5|| 2| 1| 2|| 2| 1| 2||
3| 1| 1 | +---------+----------+----------+
Cuando se ordena por varias columnas, por ejemplo 3, el procedimiento es básicamente el que sigue : Se ordena por la
primera columna. Si hay valores repetidos en la primera columna, para cada grupo de valores repetidos se ordenan las
filas por el valor de la 2ª columna. Si hay valores repetidos de las dos primeras columnas en conjunto, se ordenan las
filas correspondientes por la 3ª columna. Ejemplo: Supongamos una tabla con las siguientes columnas y valores:
+-----+-----------------------+------------+----------+ | a | b |c |d | +-----+-----------------------+------------+--
--------+ | 125 | Diana Pérez | 1/1/2004 | 12313 | | 486 | Alejandro Bentancourt | 30/12/2005 | 45646 | | 222 |
Jorge Rodríguez | 2/5/2004 | 78987 | | 125 | Diana Pérez | 3/8/2004 | 654654 | | 222 | Adriana Salgado
| 1/3/2002 | 12312 | +-----+-----------------------+------------+----------+
Si ordenamos esta tabla por las columnas a, b y c, obtenemos
+-----+-----------------------+------------+----------+ | a | b |c |d | +-----+-----------------------+------------+-----
-----+ | 125 | Diana Pérez | 1/1/2004 | 12313 | | 125 | Diana Pérez | 3/8/2004 | 654654 | | 222 | Adriana
Salgado | 1/3/2002 | 12312 | | 222 | Jorge Rodríguez | 2/5/2004 | 78987 | | 486 | Alejandro Bentancourt |
30/12/2005 | 45646 | +----+-------------+-----------------------+----------+
Por último, se puede ordenar por una cantidad calculada a partir de una o varias columnas.
mysql> SELECT articulo, importe, cantidad FROM ventas -> ORDER BY articulo, importe/cantidad; +----------+---------
+----------+ | articulo | importe | cantidad | +----------+---------+----------+ | 1 | 178.50 | 1|| 1 | 178.50 | 1||
2 | 195.00 | 1|| 2 | 200.00 | 1|| 3 | 220.00 | 1|| 5 | 5.50 | 1|| 5 | 11.00 |
2|| 5 | 5.50 | 1|| 7 | 16.00 | 2 | +----------+---------+----------+
La cláusula LIMIT
La preparación de un query complicado implica normalmente un proceso de prueba y error. Aunque no se cometan
errores, siempre se empieza escribiendo queries que sólo realizan una parte de lo que se desea alcanzar. Luego, se van
mejorando gradualmente hasta llegar al objetivo buscado.
Cuando se trabaja con tablas auténticas con muchos miles de filas, puede ser demasiado engorroso ir obteniendo
repetidas salidas con cientos o miles de filas. Es obvio que no se pueden observar en la pantalla del cliente mysql. Más
adelante, veremos cómo usar Microsoft Excel para observar las salidas de los queries. Por otra parte, en su instalación
puede haber otros clientes que operen con MySQL.
De todas maneras, interesa una cláusula sencilla que limite el número de filas que produce el SELECT. Esa es la
función de LIMIT. Si, por ejemplo, escribimos
mysql> SELECT articulo, cliente FROM ventas LIMIT 3; +----------+---------+ | articulo | cliente | +----------+---------+ | 1|
1|| 2| 2|| 1| 3 | +----------+---------+
entonces sólo vemos 3 filas en la salida, a pesar que hay varias más en Ventas.
Este procedimiento es inconveniente apenas se empiezan a complicar los queries. Un procedimiento sencillo para
Windows, es el siguiente:
- Escriba en él su query.
- Guárdelo en nuestro directorio de trabajo : C:\MySQL\bin\p. con un nombre sencillo que le parezca apropiado como
prueba.txt. Nota : El Bloc de Notas agrega automáticamente .txt al final del nombre de archivo así que sólo escriba
prueba, sin punto al final. ¡Si escribe prueba. se guardará como prueba..txt, con 2 puntos!
- Si el query no dio el resultado esperado, ahora no es preciso escribir todo de nuevo. Simplemente corríjalo en el Bloc
de Notas. y vuelva a guardarlo. Repita los pasos d) y e) hasta obtener el resultado buscado. Si lo desea, ahora puede
archivar el query con un nombre más descriptivo, usando la opción Guardar como del menú Archivo del Bloc de Notas.
Los clientes son programas relativamente sencillos que se pueden programar para que estén adaptados a las
necesidades del usuario. En cambio, los servidores son programas complejos que realmente no se pueden adaptar a las
necesidades de un usuario individual (aunque son configurables, por ejemplo, pueden emitir mensajes en un idioma
seleccionado por el administrador de la base de datos).
Problemas resueltos
Sin embargo, sigue siendo muy poco práctico. Además, si hay dos empleados con el mismo nombre, no hay manera
de distinguirlos, si no se usa otra columna. Por eso todas las empresas tienen números de funcionario.
- Sacar una lista de los nombres de los clientes de los cuales no se tiene dirección.
Solución:
Se trata de obtener la columna Nombre de las filas de la tabla Clientes cuya dirección es NULL. El query es :
- Sacar una lista de los nombres y direcciones de los clientes de los cuales sí se tiene la dirección.
Solución:
Se trata de obtener la columnas Nombre, Direccion de las filas de la tabla Clientes que tienen direcciones que no sean
NULL. El query es:
- Sacar una lista ordenada alfabéticamente de los nombre y direcciones de los clientes, ordenados por nombre.
Solución:
- Sacar una lista de todos los datos de los empleados ordenados por nombre.
Solución:
- Sacar una lista de los datos de los empleados ordenados por salario en forma descedente. Los salarios deben ser
formateados con comas cada 3 dígitos y dos decimales después del punto y alineados a la derecha , por ejemplo,
1,200,340.50.
Solución:
- Igual al anterior pero se quiere que los números salgan formateados con puntos cada 3 dígitos y coma decimal, en
vez de punto. Por ejemplo, 1.200.340,50 .
Solución:
Si bien es un procedimiento complicado, para usarlo en otro caso sólo hay que copiar la parte que comienza con
REPLACE y termina en el paréntesis antes de AS Salario y hacer los siguientes cambios:
- Eventualmente cambiar el número de decimales después de la coma, que figura dentro de la función FORMAT, de 2
al valor que se desee.
- Si es conveniente, variar el ancho de la columna. Este ancho aparece dentro de la función LPAD. En este ejemplo vale
12. El ancho debe ser suficiente para poder escribir todos los valores que aparezcan en la columna, con el número de
decimales que se haya solicitado.
Manejo de fechas
SELECT como calculadora
Se puede usar la cláusula SELECT para hacer cálculos aritméticos.
Ejemplos:
SELECT 1+1; SELECT 4.5*(3.86+2.34)
Se debe usar punto decimal y no coma.
Se puede usar la función POW ( por power, potencia) para hacer cálculos relativos a intereses.
POW(a,b) calcula a elevado a la potencia b. Por ejemplo, POW(10,3) produce el valor 1000.
http://alejandrosueldo.com.ar/joomla Potenciado por Joomla! Generado: 3 September, 2010, 02:59
Ing. Alejandro Sueldo
También se pueden hacer cálculos trigonométricos, etc, pero, en general, estos cálculos no relacionados con bases
de datos se hacen mejor con una calculadora.
- CURDATE(). Esta función da la fecha del día (¡si el sistema tiene la fecha correcta!). Ejemplo:
SELECT CURDATE();
Obtenemos 2005-01-01, en el formato de fecha ‘Año-Mes-Día’ propio de MySQL.
- DAYNAME(). Dada una fecha, esta función da el nombe ( en inglés) del día de la semana correspondiente. Ejemplo:
SELECT DAYNAME(CURDATE());
Obtenemos Saturday, es decir, Sábado.
- DAYOFWEEK(). Es complementaria de la anterior. En vez de darnos el nombre del día de la semana nos da un código
numérico de 1 a 7. El código 1 representa el Domingo, el 2 el Lunes, y así hasta el 7 que representa el Sábado. Ejemplo:
SELECT DAYOFWEEK(CURDATE());
Obtenemos un 7,que indica el Sábado.
- DATE_FORMAT(). Nos permite presentar las fechas en otros formatos. Los formatos que usaremos son '%d/%m/%y'
y '%d/%m/%Y'. Ejemplo:
SELECT DATE_FORMAT(CURDATE(),’%d/%m/%Y');
Produce 01/01/2005.
- DATE_ADD(). Esta función nos permite agregar a una fecha cierto número de días ( o meses y años) Ejemplo: ¿Cuál
es la fecha de dentro de 15 días?
SELECT DATE_ADD(CURDATE(), INTERVAL 15 DAY);
o mejor :
SELECT DATE_FORMAT(DATE_ADD(CURDATE(),INTERVAL 15 DAY) ,’%d/%m/%Y');
Produce 16/01/2005.
- DATE_SUB(). Esta función le quita cierto número de días (o meses y años) a una fecha. Ejemplo: ¿Cuál es la fecha
de hace 15 días?
SELECT DATE_FORMAT(DATE_SUB(CURDATE(),INTERVAL 15 DAY),’%d/%m/%Y');
Produce 17/12/2004.
- DATEDIFF(). Esta función obtiene la diferencia, en días, entre dos fechas. Ejemplo :
SELECT DATEDIFF(‘2005-4-1’,’2004-5-30’);
Este query produce 306, lo que significa que del 30/5/2004 al 1/4/2005 van 306 días.
- YEAR(), MONTH() ,DAY() extraen de una fecha el año, el mes y día correspondientes. Ejemplo:
SELECT MONTH(‘2005-4-1’); produce 4, el número del mes.
Problemas resueltos
En general la función DATE_FORMAT( .........., '%d / %m / %y') nos sirve para presentar cualquier fecha en un formato
legible.
- Obtener una lista de los empleados que ingresaron después del 15/12/1999, con sus nombres y fechas de ingreso en
el formato usual día/mes/año (el año con 4 cifras).
Solución:
SELECT Nombre,DATE_FORMAT(Fecha_ingreso,'%d/%m/%Y') AS Fecha_de_Ingreso
FROM Empleados WHERE Fecha_ingreso > '1999-12-15';
La %Y en el formato de la fecha produce el año con 4 cifras.
Primero se evalúa CURDATE() dando la fecha del día. DAYOFMONTH separa de esa fecha el día del mes.
Supongamos que se trata de un día 3. Entonces DATE_SUB le resta a su primer parámetro CURDATE(), el número de
día del mes. Pero 3 días antes del 3 de mes está el último día del mes anterior. Una fecha mayor que el último día del
mes anterior es lo mismo que una fecha del mes actual.
- Realizar una tabla con los datos de los conformes, pero agregando una columnas donde se indica cuántos días faltan
para el vencimiento de cada uno.
Solución:
SELECT *, DATEDIFF(Vencimiento,CURDATE()) AS Dias_para_Vencimiento FROM Conformes;
http://alejandrosueldo.com.ar/joomla Potenciado por Joomla! Generado: 3 September, 2010, 02:59
Ing. Alejandro Sueldo
- Obtener una lista de los conformes con sus fechas de vencimiento en la forma , por ejemplo, 3 de Febrero de 2004 ,
ordenados por fecha de vencimiento de manera que el conforme que se vence primero aparezca primero en la lista.
Solución:
En inglés las fechas se formatean con facilidad:
SELECT Acreedor, DATE_FORMAT(Vencimiento,'%M %D, %Y') AS Vencimiento, Importe
FROM Conformes ORDER BY Vencimiento;
Para obtener un resultando semejante en español hay que escribir:
SELECT Acreedor, CONCAT( DAYOFMONTH(Vencimiento), ' de ',
CASE MONTH(Vencimiento) WHEN 1 THEN 'Enero' WHEN 2 THEN
'Febero' WHEN 3 THEN 'Marzo' WHEN 4 THEN 'Abril' WHEN 5
THEN 'Mayo' WHEN 6 THEN 'Junio' WHEN 7 THEN 'Julio'
WHEN 8 THEN 'Agosto' WHEN 9 THEN 'Setiembre' WHEN 10 THEN 'Octubre'
WHEN 11 THEN 'Noviembre' WHEN 12 THEN 'Diciembre' END,
' de ', YEAR(Vencimiento)) AS Vencimiento, Importe FROM Conformes;
- Obtener una lista de los empleados con el número de años que llevan en la empresa al día de hoy. Se cuentan
únicamente años enteros. Por ejemplo, si un empleado lleva 5 años y 10 meses en la empresa, contamos
únicamente 5 años.
Solución:
SELECT *, YEAR(CURDATE()) - YEAR(Fecha_ingreso) - (RIGHT(CURDATE(),5) <
RIGHT(Fecha_ingreso,5)) AS Antiguedad FROM Empleados;
Veamos cómo funciona este query, que es bastante complejo. En primer lugar, aparece un valor booleano
RIGHT(CURDATE(),5) < RIGHT(Fecha_ingreso,5). Para entender este valor, en primer lugar debemos darnos cuenta
que RIGHT(CURDATE(),5) representa los 5 caracteres más a la derecha de CURDATE(). Es decir, los dos dígitos del
mes de hoy, un guión, y los dos dígitos del día de hoy.
El signo de < que separa los dos RIGHT representa en realidad una pregunta : ¿ el primero da un resultado
alfabéticamente anterior al segundo ? Esto es equivalente a preguntar si la fecha de hoy es anterior al día en que se
cumplen años de la fecha de ingreso. Ahora bien, el hecho que una condición sea verdadera se representa en el
computador por un valor 1 mientras que si la condición es falsa se guarda un valor 0.
Veamos un ejemplo completo. Si un empleado hubiese ingresado el 20 de diciembre del año y hoy es 10 de octubre,
entonces todavía no cumplió un año. Obtenemos un resultado correcto porque YEAR(CURDATE()) -
YEAR(Fecha_ingreso) vale 1 y (RIGHT(CURDATE(),5) < RIGHT(Fecha_ingreso,5)) también vale 1. La diferencia, cero,
indica que el empleado todavía no tiene un año en la empresa.
Este truco es útil porque muchas reglamentaciones sobre licencias y primas dependen de los años enteros que tenga
el empleado.
- SUM(). Esta función totaliza una columna, dentro de las filas que cumplen una condición, o de todas las filas si no es
especifica ninguna condición. En lo que sigue abreviaremos esta expresión y diremos simplemente ‘de las filas
especificadas’. Ejemplos: Sumar todos los importes de Ventas.
mysql> SELECT SUM(importe) FROM ventas; +--------------+ | SUM(importe) | +--------------+ | 1010.00 | +--------------
+
Sumar todos los importes de Ventas, con fecha del año 2003.
http://alejandrosueldo.com.ar/joomla Potenciado por Joomla! Generado: 3 September, 2010, 02:59
Ing. Alejandro Sueldo
mysql> SELECT SUM(importe) FROM ventas WHERE YEAR(fecha)=2003; +--------------+ | SUM(importe) | +--------------
+| NULL | +--------------+
- COUNT(*). Cuenta todas las filas especificadas. Por ejemplo, el siguiente query produce el número de filas de la tabla
lineas_factura.
mysql> SELECT COUNT(*) FROM lineas_factura; +----------+ | COUNT(*) | +----------+ | 5 | +----------+
- COUNT(Nombre_de_columna). Cuenta cuántos valores no NULL hay de la columna especificada dentro de las filas
especificadas. Por ejemplo, el siguiente query produce el número de direcciones de clientes que tenemos registradas.
mysql> SELECT COUNT(direccion) FROM clientes; +------------------+ | COUNT(direccion) | +------------------+ |
2 | +------------------+
- COUNT ( DISTINCT Nombre_de_columna). Cuenta cuántos valores no NULL diferentes hay de la columna
especificada, en las filas especificadas. El siguiente ejemplo produce el número de clientes distintos a los cuales se les
han registrado ventas.
mysql> SELECT COUNT(DISTINCT(cliente)) FROM ventas; +--------------------------+ | COUNT(DISTINCT(cliente)) | +---
-----------------------+ | 3 | +--------------------------+
- MAX(). Produce el máximo valor de una columna dentro de las filas especificadas.
- AVG(). Produce el promedio de los valores de una columna numérica, contando sólo las filas especificadas.
Un subquery siempre debe estar rodeado de paréntesis. Usaremos subqueries para crear condiciones en cláusulas
WHERE.
Problemas resueltos
- ¿Y el salario mínimo?
Solución:
Agrupando datos
La cláusula GROUP BY.
A menudo interesa agrupar las filas según algún criterio, que suele ser el valor de una columna, o varias. Una
cláusula SELECT con un GROUP BY produce una sola fila por cada grupo. Los valores de las columnas especificadas
en el SELECT deberían ser iguales dentro de cada grupo. De lo contrario los resultados son imprevisibles.
También aparecen usualmente funciones de agregado que ahora se calculan sobre cada grupo. Los resultados, si no
especifica otra cosa con un ORDER BY, salen ordenados por las columnas del GROUP BY.
http://alejandrosueldo.com.ar/joomla Potenciado por Joomla! Generado: 3 September, 2010, 02:59
Ing. Alejandro Sueldo
Ejemplo: ¿Cuántas líneas tiene cada una de las facturas? Veamos la tabla Lineas_factura:
La cláusula HAVING.
Después de un GROUP BY, todavía se pueden volver a seleccionar filas con una cláusula HAVING. Por ejemplo,
podemos estar interesados, hipotéticamente, en las facturas con más de una línea. Entonces deberíamos usar
SELECT Factura, COUNT(*) FROM Lineas_Factura GROUP BY Factura HAVING COUNT(*) > 1;
El resultado es:
+---------+----------+ | factura | cantidad | +---------+----------+ | 1| 3 | +---------+----------+
El orden de las cláusulas vistas hasta ahora es SELECT.....FROM...., WHERE, GROUP BY, HAVING, ORDER BY,
LIMIT.
Hay dos momentos en que se seleccionan filas, una con el WHERE antes de la agrupación y otro con el HAVING,
después de la misma.
Problemas resueltos
En la tabla Ventas tenemos una columna Sucursal. Esa columna contiene un código numérico que por ahora utilizaremos
tal como está. ( Más adelante, le haremos corresponder a cada código numérico su descripción del tipo 1=Centro,
2=Unión, etc. Estos son barrios de la bella ciudad de Montevideo, donde es nacido el autor). Un valor NULL de Sucursal
puede representar una venta no asociada a una región determinada, por ejemplo una exportación inusual o una venta al
Estado. Queremos para cada Sucursal totalizar los Importes correspondientes.
SELECT Sucursal, SUM(Importe) FROM Ventas GROUP BY Sucursal;
Una presentación algo mejor se logra con:
SELECT Sucursal, SUM(Importe) as Ventas_Totales FROM Ventas GROUP BY Sucursal;
- ¿Cuántas ventas se efectuaron en cada región, por cada vendedor? Sólo se van a incluir en este informe las ventas con
datos completos. No admitimos Sucursal o Vendedor NULL.
http://alejandrosueldo.com.ar/joomla Potenciado por Joomla! Generado: 3 September, 2010, 02:59
Ing. Alejandro Sueldo
Solución:
SELECT Sucursal, Vendedor, COUNT(*) AS Numero_Ventas FROM Ventas WHERE Sucursal IS
NOT NULL AND Vendedor IS NOT NULL GROUP BY Sucursal, Vendedor;
- Ahora queremos totalizar los importes de las ventas de cada vendedor en cada región.
Solución:
Le vamos a pedir a MySQL que sume los importes agrupando por vendedor y región.
SELECT Vendedor, Sucursal, SUM(Importe) AS Total FROM Ventas GROUP BY Vendedor,
Sucursal;
- Queremos totalizar los importes de las ventas de cada vendedor y además el total general de las ventas.
Solución:
SELECT Vendedor, SUM(Importe) AS Total FROM Ventas GROUP BY Vendedor WITH ROLLUP;
El total está en la última fila. Aparecen dos filas con Vendedor NULL. La primera corresponde a las ventas para las
que no se tiene un vendedor en la tabla. La última contiene el total general, como es fácil verificar. Este total general
aparece debido a que se agregó WITH ROLLUP al GROUP BY.
- Queremos totalizar los importes de las ventas por vendedor y región pero además obtener subtotales por vendedor y
un total general.
Solución:
Después del subquery es imprescindible agregar "AS Totales" para darle un nombre ("Totales") a la tabla temporaria .
Es decir, si el subquery se usa para generar una tabla temporaria de la cual se realiza un SELECT...FROM, es decir, de
la cual se seleccionan filas, entonces es preciso asignarle un nombre a la tabla temporaria. El nombre se le asigna
usando "AS".
Por ejemplo, supongamos que hacemos esta operación con las tablas T1 y T2
T1 +------+------+ | a | b | +------+------+ | 1 | 4 | | 2 | 9 | | 3 | 7 | +------+------+ T2 +------+------+ | c | d | +---
---+------+ | AB | 4 | | CD | 10 | | EF | 9 | +------+------+
Entonces el JOIN de T1 y T2 es :
+------+------+------+------+ | a | b | c | d | +------+------+------+------+ | 1 | 4 | AB | 4 | | 2 | 9 | AB | 4 | | 3
| 7 | AB | 4 | | 1 | 4 | CD | 10 | | 2 | 9 | CD | 10 | | 3 | 7 | CD | 10 | | 1 | 4 | EF | 9 | | 2 | 9 |
EF | 9 | | 3 | 7 | EF | 9 | +------+------+------+------+
La cláusula ON
Generalmente, no nos interesa obtener todas las combinaciones de filas, sino únicamente aquellas que cumplen cierta
condición. Esa condición se especifica en la cláusula ON. Por ejemplo, si efectuásemos el query
SELECT * FROM T1 JOIN T2 ON T1.b=T2.d;
obtendríamos únicamente las filas del JOIN donde b y d coinciden, es decir:
+------+------+------+------+ | a | b | c | d | +------+------+------+------+ | 1 | 4 | AB | 4 | | 2 | 9 | EF | 9 | +-----
-+------+------+------+
Supongamos ahora, que queremos hacer un listado donde figure cada fila de T1 combinada con cada fila de T2 que
tenga T1.b = T2.d, y además, la fila de T1 seguida de una fila de T2 llena de NULL si no hay ninguna fila de T2 que
verifique la condición del ON con la fila de T1 dada. Esto es lo que se llama un LEFT JOIN. El query
SELECT * FROM T1 LEFT JOIN T2 ON T1.b=T2.d;
produce la tabla
+------+------+------+------+ | a | b | c | d | +------+------+------+------+ | 1 | 4 | AB | 4 | | 2 | 9 | EF | 9 | | 3
| 7 | NULL | NULL | +------+------+------+------+
La última fila aparece debido a la inexistencia de valores de d iguales a b=7 en la tabla T2.
Si, al revés, queremos que toda fila de T2 aparezca precedida de las filas de T1 que le corresponden, si las hay, y si no,
una fila llena de NULL, entonces tenemos que hacer un RIGHT JOIN. El query
SELECT * FROM T1 RIGHT JOIN T2 ON T1.b=T2.d;
produce
+------+------+------+------+ | a | b | c | d | +------+------+------+------+ | 1 | 4 | AB | 4 | | NULL | NULL | CD | 10
| | 2 | 9 | EF | 9 | +------+------+------+------+
Para prepararnos para los problemas resueltos, veamos las siguientes tablas:
Clientes
+----+-------------+---------------------+----------+ | id | nombre | direccion | vendedor | +----+-------------+--------------------
-+----------+ | 1 | Matt Design | NULL | 1 | | 2 | Diana Pérez | Brito del Pino 1120 | NULL | | 3 | John
Smith | Zum Felde 2024 | 1 | +----+-------------+---------------------+----------+
Empleados
+----+-----------------+---------------+---------+ | id | nombre | fecha_ingreso | salario | +----+-----------------+---------------+----
-----+ | 1 | Carlos Zaltzman | 1999-12-10 | 10000 | | 2 | Juan Fernández | 2000-01-03 | 12000 | +----+-----------------
+---------------+---------+
Algunos clientes son atendidos por un vendedor de la empresa. El vendedor que atiende a un clientes es identificado en
la columna Vendedor por su código. El 1 que aparece en la primera fila de Clientes significa que Matt Design es atendido
por el empleado Carlos Zaltzman, que tiene código 1. Sin entrar en detalles, MySQL "sabe" que la columna Vendedor de
Clientes se refiere a la columna Codigo de Empleados.
El NULL de la segunda fila de Clientes significa que no es atendido por ningún vendedor. La columna Vendedor de
Clientes es lo que se llama una clave extranjera ("foreign key"). La columna Id de Empleados es una clave primaria
(identifica completamente a un empleado). La clave extranjera Vendedor de Clientes es una referencia a la clave
primaria Id de Empleado.
Por ejemplo, la primera fila significa que la venta identificada por el número 1 fue realizada al cliente Matt Design por el
vendedor Carlos Zaltzman, por un importe de 178.50.
Problemas resueltos
- Se busca hacer una tabla con los nombres de los clientes que son atendidos por un vendedor y el nombre del
correspondiente vendedor.
Solución:
Formamos una tabla con el Nombre de los Clientes y de los Empleados que tengan el Vendedor del Cliente igual al
Código del Empleado.
SELECT Clientes.Nombre, Empleados.Nombre FROM Clientes JOIN Empleados ON
Clientes.Vendedor = Empleados.Id;
- Ahora queremos que aparezcan en la tabla también los clientes que no son atendidos por ningún vendedor. El
nombre del vendedor aparecerá como NULL.
Solución:
- En este caso queremos hacer una tabla con los nombres de los empleados y al lado de ellos los nombres de los
clientes. Si un empleado atiende varios clientes aparecerá en varias filas. Si no atiende ninguno aparecerá una sola
vez con un NULL en la columna de cliente.
Solución:
- Hacer una tabla en la cual figuren para cada venta el nombre del cliente, el nombre del vendedor si lo hubo y el
importe de la venta.
Solución:
Si no se hubiesen agregado los "AS ..." las dos primeras columnas llevarían el título de "Nombre" lo que es confuso.
Es de hacer notar que hemos realizado un JOIN de 3 tablas, o si se prefiere un JOIN de Cliente con Ventas, al cual se le
ha hecho un LEFT JOIN con Empleados. Este último tenía que ser un LEFT JOIN porque pueden existir ventas que no
tienen un empleado correspondiente (Vendedor es NULL). Si hubiésemos hecho un JOIN esas ventas sin empleado
correspondiente no figurarían en el resultado.
- Igual al anterior salvo que sólo deben aparecer las ventas con importes mayores a $ 50.
Solución:
- Considerando ahora todas las ventas queremos totalizar cuánto le vendió cada vendedor a cada cliente.
Solución:
- Este problema es una combinación de los dos anteriores. Queremos totalizar cuánto le vendió cada vendedor a cada
cliente, salvo que sólo totalizaremos las ventas de importe que superen los.
Solución:
- Ahora queremos totalizar cuánto le vendió cada vendedor a cada cliente, pero queremos listar únicamente los
TOTALES de ventas que superen los 0.
Solución:
- Formar una tabla que represente las ventas con los nombres de clientes, los vendedores, los importes y los artículos
vendidos.
Solución:
- Tenemos un archivo de Facturas. La legislación, con fines impositivos, requiere que estén registrados todos los
números de factura consecutivamente. Queremos comprobar si es así.
Solución:
se refiere a la igualdad de dos columnas. En este caso, hacemos todas las combinaciones de una factura de F1 (una
copia de Facturas) y otra de F2 (otra copia) con el número siguiente. Como se trata de un LEFT JOIN, de no haber una
factura con el número siguiente, en el join va la factura de F1 seguida de columnas NULL. Pero de esas combinaciones
de filas únicamente seleccionamos el número de factura de F1 más 1 cuando el de F2 es NULL.
Es decir, cuando no hay número siguiente seleccionamos el que debería haber. La última parte del WHERE sirve para
que no se agregue a la lista de faltantes el siguiente al último número de factura del archivo.
Esta solución tiene limitaciones. Algunas son inherentes al problema planteado: no tenemos manera de saber si faltan
números de factura antes del primer número registrado o después del último. Pero la solución propuesta únicamente
encuentra el primer número de cada intervalo de números faltantes.
Por ejemplo, si los números registrados son ...,1033, 1034, 1037, 1038, 1039, 1040,.... sólo se listará 1035. No es difícil
completar manualmente el trabajo, pero se puede resolver esta dificultad completamente como se verá en el problema
8-3.
- Clientes a quienes se les ha vendido durante 3 meses consecutivos y en qué mes comienza el trimestre en que se
efectuaron dichas ventas.
Solución:
Nota: La manera de saber si un mes de un determinado año es anterior o posterior a otro y cuántos meses de
diferencia hay entre ellos es usar la expresión YEAR(UnaFecha)*12+MONTH(Una Fecha).
Aquí Una Fecha representa una de las dos fechas que estamos comparando. Por ejemplo, consideremos el mes de
marzo (3) del 2004 y el mes de diciembre(12) de 2003.
Como 24051 - 24048 = 3, concluimos que diciembre de 2003 es 3 meses antes que marzo de 2004. Este es un "theta
join". Luego se agrupan estas combinaciones según el cliente y el mes y año de la primera fecha y por último, se
cuentan cuantos meses distintos hay en cada grupo.
Cuando hay 3 meses distintos esto significa que figuran por lo menos una vez el mes de la primera fecha y los dos
siguientes. O sea que el cliente tiene ventas en 3 meses consecutivos.
Esta solución tiene una peculiaridad : supongamos que un cliente ha efectuado compras en 4 meses consecutivos. Por
ejemplo, de enero a abril de 2004. Entonces, en la salida va a figurar el cliente con una fecha del mes de enero y otra de
febrero. Esto es correcto, en la medida que son ciertas dos afirmaciones
Se realizaron ventas enero, febero y marzo. Se realizaron ventas en febrero, marzo y abril. Hay varios puntos
interesantes más en este query: hemos usado la función CONCAT que concatena, es decir escribe uno después de otro
los resultados de varias expresiones; en este caso el mes en que comienza el trimestre, un guión y el año en que
comienza dicho trimestre de nuevo hemos usado COUNT (DISTINCT ....) para contar cuántos elementos distintos hay
en una expresión calculada en base a una columna.
A menudo tenemos columnas que son cadenas de caracteres, y queremos buscar las cadenas que contienen cierta
palabra. Esto se realiza a través de un nuevo tipo de condición: Nombre_de_columna LIKE cadena_de_caracteres.
Estas condiciones pueden usarse, como todas, en una cláusula WHERE o en una cláusula HAVING. La condición
Nombre_de_columna LIKE cadena_de_caracteres (donde cadena_de_caracteres no contiene ni ‘%’ ni
‘_’ ) es verdadera cuando el valor de Nombre_de_columna coincide con cadena_de_caracteres (salvo que
no se distingue entre mayúsculas y minúsculas).
Valor de la columna A
'Carlos'
Verdadera
'carlos'
Verdadera
'Carlos '
Falsa
'Juan'
Falsa
'Juan Carlos'
Falsa
Un % dentro de cadena_de_caracteres representa cualquier cadena de caracteres, incluso una sin caracteres. Entonces
A LIKE ‘Carlos%’ tiene los siguientes valores:
Valor de la columna A
'Carlos'
Verdadera
'carlos'
Verdadera
'Carlos Zaltzman'
Verdadera
'Carlos '
Verdadera
'Juan'
Falsa
'Juan Carlos'
Falsa
Valor de la columna A
'Carlos'
Verdadera
'carlos'
Verdadera
'Juan carlos'
Verdadera
Valor de la columna A
'Carlos'
Verdadera
'carlos'
Verdadera
'Juan'
Falsa
El carácter '_' representa un carácter cualquiera. A diferencia de ‘%’ representa un carácter y uno sólo.
Luego dos’_’ seguidos representan dos caracteres cualquiera,etc.
Valor de la columna A
'Carlos'
Falsa
'12Carlos'
Verdadera
'xxCarlos'
Verdadera
' Carlos'
Verdadera
'xxcarlos'
Verdadera
'Juan Carlos'
Falsa
NOT LIKE es simplemente la negación de LIKE: es verdadera cuando LIKE es falsa y recíprocamente.
Problemas resueltos
- Hacer una lista de todos los datos de los artículos en cuyo nombre figura la palabra ‘monitor’.
Solución:
SELECT * FROM Articulos WHERE Nombre LIKE ‘%monitor%’;
Obsérvese que aunque la palabra monitor esté en la columna Nombre con mayúscula, igualmente aparece en el
resultado del query.
- Listar todos los datos de los artículos cuyo código comience por ‘mon’.
Solución:
Problemas resueltos
(SELECT * FROM Ventas WHERE Sucursal = 1) UNION ALL (SELECT * FROM Ventas
WHERE Sucursal = 3);
Obsérvese que como no es posible que una venta corresponda a las dos Sucursales, entonces es mejor especificar
UNION ALL, con lo que se evita el trabajo de ordenar las filas, para suprirmir las duplicaciones.
- Listar los conformes que se vencen en los próximos 30 días y los que son de más de $ 1000 y todavía no se han
vencido, sin duplicaciones.
Solución:
- Volver a resolver el problema 6-10, de los números de factura faltantes, de manera que se indique para cada
intervalo faltante de cuál a cuál valor no están registradas las facturas.
Solución:
El UNION ALL junta todas las filas obtenidas. Luego se ordenan, primero por número faltante y luego por Limite. Esto
hace que si falta una factura sola el Desde correspondiente figure antes del Hasta. Por ejemplo, dada la sucesión de
facturas 1020,1022,1025, la salida es :
+---------+-------+ | Limite | Falta | +---------+-------+ | Desde | 1021 | | Hasta | 1021 | | Desde | 1023 | | Hasta |
024 | +---------+-------+
Subqueries
Subqueries escalares
Ya antes, en la sección 4, usamos subqueries escalares. Un subquery escalar produce un sólo valor, que se usa en una
condición WHERE o HAVING.
Ejemplo: Listar los empleados que tienen salarios mayores que la mitad del salario más alto.
SELECT * FROM Empleados WHERE Salario > (SELECT MAX(Salario) FROM Empleados)/2;
IN y NOT IN
Una manera de preguntar si un valor si el valor de una columna está en una lista es usando IN.
Ejemplo: Listar las ventas efectuadas por los empleados con código 1,2.
SELECT * FROM Ventas WHERE Vendedor IN (1,2);
Este query lista los Clientes a los cuáles se les han vendido algo.
NOT IN es la negación de IN. Si queremos la lista de los clientes a los que no se les han vendido nada en los últimos 30
días, escribimos
SELECT * FROM Clientes WHERE Id NOT IN ( SELECT Cliente FROM Ventas
WHERE Fecha>=DATE_SUB(CURDATE(), INTERVAL 30 DAY));
ALL y ANY
Podemos seleccionar filas que cumplen una condición con todas las filas de un subquery.
También podemos seleccionar filas que cumplen una condición con alguna de las filas de un subquery.
SELECT * FROM Conformes WHERE Vencimiento < ANY (SELECT Fecha FROM Facturas);
Nota: Se recomienda tener cuidado con el uso de ALL. Puede producir inestabilidad del sistema si la columna que figura
antes del ALL se escribe incorrectamente y por lo tanto no existe.
Subqueries correlacionados
Un subquery se llama correlacionado cuando hace referencia a una tabla que no figura en su cláusula FROM (aunque
sí debe figurar en un query que lo contiene).
Ejemplo: Hacer una tabla de las ventas cuyo importe es máximo dentro del artículo considerado.
SELECT Articulo, Importe FROM Ventas V1 WHERE Importe = (SELECT MAX(Importe) FROM Ventas V2
WHERE V2.Articulo = V1.Articulo) ORDER BY Articulo;
A menudo lo único que interesa de un subquery correlacionado es saber si tiene alguna fila o no. Para eso tenemos
EXISTS y NOT EXISTS.
Por ejemplo, si queremos seleccionar todas las Sucursales en las que se hizo alguna venta,
SELECT * FROM Sucursales WHERE EXISTS (SELECT 1 FROM Ventas WHERE Sucursal
= Sucursales.Id);
El SELECT 1 es para enfatizar que no nos interesa el contenido de las filas del subquery sino si existen o no. Si
ejecutamos el subquery por sí mismo, con un valor apropiado en vez de Sucursales.Id, obtenemos una columnas de
unos. Esta tabla tiene tantas filas como filas de Ventas hay con la Sucursal indicada.
o también
SELECT DISTINCT Sucursales.* FROM Sucursales LEFT JOIN Ventas ON
Sucursales.Id = Ventas.Sucursal WHERE Ventas.Id IS NULL;
Problemas resueltos
SELECT * FROM Ventas WHERE Fecha > ALL (SELECT Fecha FROM Facturas);
Es equivalente a
SELECT * FROM Ventas WHERE Fecha > (SELECT MAX(Fecha ) FROM Facturas);
De hecho, aunque se solicite el primer query, MySQL, internamente, ejecuta el 2º., que es mucho más eficiente.
El SELECT 1 del subquery no tiene importancia, lo que realmente hace MySQL es averiguar si hay alguna fila de Ventas
que cumpla la cláusula WHERE, para darle un valor al NOT EXISTS. Si hay una fila que cumple el WHERE Sucursal...,
entonces el NOT EXISTS es falso, etc.
El SELECT 1 puede sustituirse por cualquier otro SELECT, que quizás resulte más intuitivo. El funcionamiento será el
mismo.
- Clientes a los que se les han hecho menos de tres ventas en los últimos 365 días.
Solución:
SELECT Nombre FROM Articulos WHERE NOT EXISTS( SELECT 1 FROM Sucursales
WHERE NOT EXISTS (SELECT 1 FROM Ventas WHERE
http://alejandrosueldo.com.ar/joomla Potenciado por Joomla! Generado: 3 September, 2010, 02:59
Ing. Alejandro Sueldo
- Vendedores que hayan vendido todos los artículos a la venta en el último año (los últimos 365 días).
Solución:
- Vendedores que hayan vendido por lo menos un artículo de cada grupo en el último año.
Solución:
- Grupos de los cuales no se vendieron artículos en el último año, para cada vendedor, ordenado alfabéticamente por
vendedor y grupo.
Solución:
Salida a Excel
El programa mysql, en el que ingresamos los queries, no permite ver resultados grandes claramente. Los problemas
vistos tenían soluciones con pocas filas y columnas. ¿ Qué hacemos si tenemos 1000 filas y 30 columnas?
Una solución, no muy buena, es pasar la salida del query a texto. Esto se realiza agregando después de la cláusula
SELECT (exterior, si hay subqueries) una cláusula INTO OUTFILE path.
Por ejemplo, para que el resultado se guarde en un archivo c:\MySQL\bin\p\salida.txt (c:\MySQL\bin\p es el directorio
donde hemos supuesto que guardaron los problemas resueltos) debemos escribir
SELECT ... INTO OUTFILE 'c:/MySQL/bin/p/salida.txt' LINES TERMINATED BY '\r\n' FROM ...
La última línea es característica de Windows, donde el final de cada línea se indica por dos caracteres (invisibles)
mientras que en Unix, el final de cada línea se indica por un solo carácter.
Obsérvese que el camino (path) del archivo va con barras : / . Mientras que la cláusula LINES TERMINATED lleva
contrabarras : \ .
Para que el procedimiento funcione es imprescindible que el directorio donde se va a guardar la salida exista. MySQL
crea el archivo pero no el directorio. También es imprescindible que el archivo no exista. Si existe, aparecerá un
mensaje de error. Si se observa el texto obtenido con cualquier procesador (Bloc de notas, WordPad, Word) se verá
que hay problemas : salvo en el Bloc de notas las columnas no aparecen bien alineadas ( y el bloc de notas tiene
limitaciones en lo que se refiere al tamaño del archivo que puede manejar).
Las vocales con tilde se cambian por otros caracteres.
Para resolver estos problemas se puede usar Microsoft Excel. Usando Excel 97 empezamos abriendo el archivo
(teniendo cuidado de seleccionar ‘Archivos de texto’ en ‘Tipo de Archivo’ ). A continuación
aparecen varios cuadros de diálogo.
- El primero tiene título ‘Asistente para importar texto – paso 1 de 3’. A media altura, a la derecha,
donde dice ‘Origen del archivo:’ se debe seleccionar ‘DOS u OS/2 (PC-8)’. Si no están
seleccionados, seleccionar además ‘Delimitados’ y ‘ Comenzar a importar en la fila : 1’.
Hacer click en el botón ‘Siguiente>’.
- En el tercer cuadro de diálogo asegurarse que esté seleccionado ‘General’ en ‘Formato de los
datos en columnas’ y por último hacer click en el botón ‘Terminar’.
Para disponer de una planilla Excel del tipo usual ir al menú ‘Archivo’ y seleccionar ‘Guardar
como’.
En el cuadro de diálogo que aparece seleccionar en ‘Guardar como tipo: ‘ la opción ‘Libro de
Microsoft Excel (*.xls)’. Luego hacer click en el botón ‘Guardar’.
Se creará una planilla Excel con el mismo nombre del archivo de texto, pero con terminación ‘xls’. En este
caso, sería ‘salida.xls’.
Esta vez tenemos una columna de Excel por cada columna del query y las vocales con tilde se ven correctamente.
Lo que sí hay que agregar manualmente son los títulos de las columnas.
El funcionamiento de SELECT
Ahora que hemos visto unos cuantos queries, podemos preguntarnos cómo funciona SELECT. Es un proceso formado
por varias etapas sucesivas :
- WHERE: De las filas resultantes del FROM se separan las que cumplen las condiciones especificadas en el WHERE.
- GROUP BY: Las filas se ordenan y agrupan según las columnas especificadas.
- SELECT : Ahora a partir de las filas que han resultado de los pasos anteriores, se construyen otras según las
expresiones que figuren en el SELECT. Si hay un GROUP BY sólo se construye una fila por cada grupo de filas del
GROUP BY. Cuidado :en caso que haya valores distintos de una columna seleccionada dentro de un grupo, se
selecciona un valor cualquiera al azar.
- HAVING: Vuelven a descartarse filas que no cumplan con la condición de esta cláusula.
- LIMIT : Si hay más filas de las indicadas por esta cláusula, se descartan.
- UNION : Se unen los resultados de varios queries. Puede haber un ORDER BY y un LIMIT después del UNION.
- Nota final sobre eficiencia: Para bases de datos chicas, con algunos miles de filas, normalmente no hay grandes
problemas de eficiencia. Con todo, si algún query es muy lento, eso no quiere decir que el problema sea
intrínsecamente demasiado complicado para el computador. Los tiempos en que se ejecutan los queries varían
muchísimo según los detalles de la base de datos y los detalles de los queries mismos. O sea que si hay problemas de
velocidad, es recomendable consultar con un programador con experiencia en SQL.
Glosario
Como el SQL es a menudo comprensible aún para personas que no lo han estudiado, pero que hablan inglés, parece
útil tener un pequeño diccionario.
TérminoDescripción
ALL
Todos.
ANY
Cualquier.
AS
Como.
AVG
Cualquier.
ANY
Abreviatura de AVERAGE, promedio.
COUNT
Contar.
CURDATE()
Función SQL. Abreviatura de CURRENT DATE, fecha de hoy.
DATE
Fecha.
DATE_ADD()
Función SQL. Literalmente, fecha sumar.
DATE_SUB()
Función SQL. Literalmente, fecha restar.
DAY
Día.
DAYNAME()
Función SQL, de DAY, día y NAME, nombre.
DAYOFWEEK()
Función SQL, concatenación de DAY OF WEEK, día de la semana.
DESC
Abreviatura de 'descending' , que puede traducirse como 'en sentido descendiente'. Se refiere a ordenar en
sentido descendente.
DISTINCT
Distintos.
EXISTS
Existe.
FROM
De.
IN
En.
IS
Es.
JOIN
Literalmente unión, zona de contacto. En SQL, representa una manera especial de unir dos tablas.
Matemáticamente, es un subconjunto de un producto cartesiano..
LEFT JOIN
Expresión usada en SQL. Literalmente, unión izquierda.
LIKE
Parecido a.
MAX
Abreviatura de MAXIMUM, máximo.
MIN
Abreviatura de MINIMUM, mínimo.
MONTH
Mes.
NAME
Nombre.
NOT
No.
NOT IN
No en, no pertenece a.
NULL
NULO, pero en un sentido especial, no se refiere al número 0, sino a un valor desconocido.
ON
Sobre. En SQL indica una condición en un JOIN.
ORDER BY
Ordenar por.
RIGHT JOIN
Expresión usada en SQL. Literalmente, unión derecha.
RIGHT()
Funcion SQL. Right significa derecha.
SELECT
Seleccionar.
SHOW
Mostrar, usado en SHOW TABLES (Mostrar tablas) y SHOW DATABASES (Mostrar bases de datos).
SUM
Sumar.
TABLE
Tabla.
UNION
Unión.
WHERE
Donde.
YEAR
Año.
Bibliografía
- Reference Manual for version 5.0.1-alfa, MySQL AB, http://dev.mysql.com/doc. En esta página encontrará las
instrucciones para conseguir el manual.
- J. Benavides Abajo, J.M. Olaizola Bartolomé, E. Rivero Cornelio, SQL Para usuarios y programadores, Paraninfo
S.A., Madrid, 1991.
- MySQL Internals Manual for version 4.1.7, MySQL AB. Para obtener este manual deberá obtener una distribución de
MySQL con fuentes (source version) y encontrará el archivo internals.texi en el directorio Docs de la distribución. Para
obtener esa distribución seguir las instrucciones de http://www.mysql.com/downloads. Advertencia: este manual es
altamente técnico y requiere Unix para ser leído con facilidad.