====== Lenguaje SQL en MYSQL ====== ===== Creación de tablas ===== ==== Formato básico ==== La forma más básica de crear una tabla es de la siguiente manera: CREATE TABLE [IF NOT EXISTS] NombreTabla ( NombreColumna TipoDato [, NombreColumna TipoDato] ...); Ésta es una tabla simple sin restricciones.\\ Ejemplo: CREATE TABLE socios ( socio_no INT(4), apellidos VARCHAR(14), telefono CHAR(9), fecha_alta DATE, direccion VARCHAR(20), codigo_postal INT(5)); ==== Restricciones ==== Las restricciones son importantes en cuanto a la implementación del modelo relacional, y su función es especificar limitaciones en los valores que pueden tomar los datos en cada columna de la tabla.\\ Hay varios tipos: * **Clave primaria PRIMARY KEY**: Especifica que __cada fila__ debe ser única a través de un valor identificativo. Puede estar formada por una columna o un grupo de columnas. En una base de datos relacional es obligatoria su existencia en cada una de las tablas. * **Clave ajena FOREIGN KEY**: Será la forma de implementar las relaciones entre las tablas. Una columna o grupo de columnas que sea clave ajena, referenciará a la tabla con la que está relacionada. Podrá tomar los valores que ya existan en la tabla relacionada, o en su defecto, un valor nulo. * Esto nos limita los valores que pueden tomar las claves ajenas, ya que no podrán tomar valores que no existan en las columnas referenciadas * Los valores de las claves primarias no podrán actualizarse si existen filas que los referencian. * **Unicidad UNIQUE**: Obliga a que una columna o conjunto de columnas tenga un valor único o nulo. * **Restricción de valores permitidos CHECK**: Define el conjunto de valores que serán válidos en una columna. Para ello deben cumplir la condición especificada. //Nota: MySQL lo acepta dentro del formato, pero no lo implementa en la versión actual (5.0.2)// * **Obligación de valor NOT NULL**: Esta columna debe siempre tomar un valor, de forma que NUNCA puede ser nulo. ==== Creación de tablas con restricciones (CONSTRAINTS) ==== Hay dos maneras de definir las restricciones en una tabla: a nivel de columna o a nivel de tabla.\\ Es posible dar un nombre a las restricciones o CONSTRAINTS, de forma que podamos referirnos a ellas después, si las queremos borrar o modificar. === Creación de tablas con restricciones a nivel de columna === De esta manera las restricciones afectan sólo a una columna, la que se está definiendo en cada momento. Definimos la restricción cuando definimos cada columna: CREATE TABLE [IF NOT EXISTS] NombreTabla ( NombreColumna TipoDato [Restricción1] [, NombreColumna TipoDato [Restricción2]] ...]); De esta forma se pueden definir las siguientes restricciones: * **Clave primaria**: PRIMARY KEY * **Clave ajena**: REFERENCES NombreTabla [(NombreColumna)] //**Nota:** El nombre de columna de la tabla referenciada, sólo es obligatorio ponerlo cuando ambas columnas no tienen el mismo nombre en ambas tablas.// * **Unicidad**: UNIQUE * **Comprobación de valores**: CHECK(expresión) * **Valor por defecto**: DEFAULT ValorDefecto * **Autoincremento**: AUTO_INCREMENT //**Nota:** Aunque no es exactamente una restricción, forma parte de la definición de columnas. El sistema irá incrementando de uno en uno los valores de esta columna cada vez que se declare una nueva fila, empezando por 1. Las columnas deben ser enteras y claves.//\\ Ejemplos: CREATE TABLE socios ( socio_no INT(4) PRIMARY KEY AUTO_INCREMENT, apellidos VARCHAR(14) UNIQUE, telefono CHAR(9) NOT NULL, fecha_alta DATE DEFAULT CURDATE(), direccion VARCHAR(20), codigo_postal INT(5) CHECK (codigo_postal BETWEEN 28000 AND 28999) ); CREATE TABLE prestamos ( num_prestamo INT(2) PRIMARY KEY AUTO_INCREMENT, socio_no INT(4) REFERENCES socios (socio_no) ); === Creación de tablas con restricciones a nivel de tabla === De esta manera las restricciones pueden afectar a una única columna o a varias y puede darse un nombre a cada restricción.\\ Definimos las restricciones al final de la sentencia, cuando ya hemos definimos todas las columnas: CREATE TABLE [IF NOT EXISTS] NombreTabla ( NombreColumna TipoDato [, NombreColumna TipoDato] ... [, Restricción1, Restricción2, ...]); En este caso las restricciones que pueden definirse son más limitadas: * **Clave primaria**: [CONSTRAINT [NombreConstraint]] PRIMARY KEY (NombreColumna [, NombreColumna ...] ) * **Clave ajena**: [CONSTRAINT [NombreConstraint]] FOREIGN KEY (NombreColumna [, NombreColumna ...] ) REFERENCES NombreTabla [(NombreColumna [, NombreColumna ...] )] //**Nota:** El nombre de columna/s de la tabla referenciada, sólo es obligatorio ponerlo cuando ambas columnas no tienen el mismo nombre en ambas tablas.// * **Unicidad**: [CONSTRAINT [NombreConstraint]] UNIQUE (NombreColumna [, NombreColumna ...] ) * **Comprobación de valores**: [CONSTRAINT [NombreConstraint]] CHECK (expresión) Ejemplos: CREATE TABLE socios ( socio_no INT(4), apellidos VARCHAR(14), telefono CHAR(9), fecha_alta DATE, direccion VARCHAR(20), codigo_postal INT(5), CONSTRAINT pk_socios PRIMARY KEY (socio_no), CONSTRAINT uq_apellidos UNIQUE (apellidos), CONSTRAINT ck_codpostal CHECK (codigo_postal BETWEEN 28000 AND 28999) ); CREATE TABLE prestamos ( num_prestamo INT(2), socio_no INT(4), CONSTRAINT pk_prestamos PRIMARY KEY (num_prestamo), CONSTRAINT fk_socios FOREIGN KEY (socio_no) REFERENCES socios(socio_no) ); ==== Integridad referencial ==== La definición de claves ajenas nos permiten mantener la integridad referencial de una base de datos relacional.\\ Para mantener la integridad de los datos al borrar (DELETE) o modificar (UPDATE) una fila referenciada, __por defecto__ el sistema no nos dejará llevarlo a cabo si existe una fila con el valor referenciado. También se conoce como **RESTRICT**.\\ Al definir la clave ajena existen varias opciones para mantener la integridad referencial: * **CASCADE**: El borrado o modificación de una fila de tabla referenciada lleva consigo el borrado o modificación en cascada de las filas de la tabla que contiene la clave ajena. Es la más utilizada. * **SET NULL**: El borrado o modificación de una fila de tabla referenciada lleva consigo poner a NULL los valores de las claves ajenas de la tabla que referencia. * **SET DEFAULT**: El borrado o modificación de una fila de tabla referenciada lleva consigo poner un valor por defecto en las claves ajenas de la tabla que referencia. * **NO ACTION**: El borrado o modificación de una fila de tabla referenciada sólo se produce si no existe ese valor en la tabla que contiene la clave ajena. Tiene el mismo efecto que RESTRICT. El formato es el siguiente: REFERENCES NombreTabla [ ( NombreColumna [, NombreColumna ] ) ] [ON DELETE {CASCADE | SET NULL | NO ACTION | SET DEFAULT | RESTRICT} ] [ON UPDATE {CASCADE | SET NULL | NO ACTION | SET DEFAULT | RESTRICT} ] Vemos un ejemplo: CREATE TABLE prestamos ( num_prestamo INT(2), socio_no INT(4), CONSTRAINT pk_prestamos PRIMARY KEY (num_prestamo), CONSTRAINT fk_socios FOREIGN KEY (socio_no) REFERENCES socios(socio_no) ON DELETE NO ACTION ON UPDATE CASCADE); ==== Formato completo de la creación de tablas ==== CREATE TABLE [IF NOT EXISTS] NombreTabla ( NombreColumna TipoDato [RestriccionTipoColumna1] [, NombreColumna TipoDato [RestriccionTipoColumna2] ...] [, RestriccionTipoTabla1] [, restriccionTipoTabla2]... ); Pueden utilizarse en la misma sentencia ambos tipos de restricciones (tabla y columna), siempre que afecten a columnas distintas. ===== Edición y borrado de tablas ===== ==== Modificación de tablas ==== Una vez ya existe una tabla, es posible realizar modificaciones en su estructura. Para ello usamos la sentencia ALTER TABLE: ALTER TABLE NombreTabla EspecificacionModificacion [, EspecificacionModificacion...]; A continuación se especifican las posibles modificaciones que pueden realizarse en la estructura de una tabla: * **Añadir nueva columna**: ADD [COLUMN] NombreColumna TipoDato [RestriccionTipoColumna] //**Nota:** Puede añadirse todas las restricciones, salvo NOT NULL, ya que al crearse todos los valores serán nulos.// * **Añadir restricción**: * **Clave primaria**: ADD [CONSTRAINT [NombreConstraint] ] PRIMARY KEY (NombreColumna [, NombreColumna...] ) * **Clave foránea**: ADD [CONSTRAINT [NombreConstraint] ] FOREIGN KEY (NombreColumna [, NombreColumna...] ) REFERENCES NombreTabla [ (NombreColumna [, NombreColumna...] ) ] * **Clave única**: ADD [CONSTRAINT [NombreConstraint] ] UNIQUE (NombreColumna [, NombreColumna...] ) * **Borrar una columna**: DROP [COLUMN] NombreColumna * **Borrar una restricción**: * **Clave primaria**: DROP PRIMARY KEY * **Clave Foránea**: DROP FOREIGN KEY NombreConstraint * **Modificar una columna sin cambiar su nombre**: MODIFY [COLUMN] NombreColumna TipoDato [RestriccionTipoColumna] * **Modificar la definición de una columna y su nombre**: CHANGE [COLUMN] NombreColumnaAntiguo NombreColumnaNuevo TipoDato [RestriccionTipoColumna] * **Renombrar la tabla**: RENAME [TO] NombreTablaNuevo ==== Eliminación de tablas ==== Para eliminar una tabla, se utiliza la siguiente sentencia: DROP TABLE [IF EXISTS] NombreTabla [CASCADE | RESTRICT]; ==== Renombrado de una tabla ==== Para cambiar el nombre de una tabla, usamos el siguiente formato: RENAME TABLE NombreTablaAntiguo TO NombreTablaNuevo [, NombreTablaAntiguo TO NombreTablaNuevo ...]; Como se observa en la caja superior, en una misma sentencia es posible renombrar varias tablas. ===== Actualización de tablas ===== ==== Inserción de nuevas filas en la base de datos ==== El formato para añadir nuevas filas en una tabla es: INSERT INTO NombreTabla [ (NombreColumna [, NombreColumna ...]) ] VALUES (Expresion [,Expresion ...] ); Como se ve en la caja superior, la lista de columnas a introducir es opcional, ya que es posible no indicarla, en cuyo caso se esperarán valores para todas las columnas. Además, la lista de valores a insertar deberá coincidir en número y posición con las columnas de la tabla.\\ ==== Modificación de filas ==== Es posible modificar datos en las columnas de las filas ya insertadas: UPDATE NombreTabla SET NombreColumna = Expresion [, NombreColumna = Expresion ...] [WHERE Condicion]; Como se ve, puede indicarse una condición opcional, de forma que podamos filtrar las filas que serán modificadas. ==== Eliminación de filas ==== Para eliminar filas usamos la sentencia: DELETE FROM NombreTabla [WHERE Condicion]; De nuevo, puede indicarse una condición opcional, de forma que podamos filtrar las filas que serán eliminadas. Si no se especifica ninguna condición __serán borradas TODAS las filas de la tabla__. ===== Consultas sencillas ===== La forma más básica de hacer consultas es a través de la siguiente sentencia: SELECT { *|[ALL/DISTINCT] ExpresionColumna [[AS] AliasColumna] [, ExpresionColumna [[AS] AliasColumna]...] } FROM NombreTabla [AliasTabla] [WHERE CondicionSeleccion] [ORDER BY {ExpresionColumna|Posicion}[ASC|DESC] [,{ExpresionColumna|Posicion}[ASC|DESC]...] ] [LIMIT [m,]n]; Como se observa, muchas sentencias son opcionales, y sirven para filtrar los posibles resultados.\\ A continuación se verá el significado de cada parte de esta sentencia. ==== SELECT ... FROM ==== Es la sentencia obligatoria más básica: * **SELECT**: Indicamos la columna (o alias de la columna) o una expresión de la columna a recuperar. Es posible usar las [[bases_de_datos:mysql:aspectos_basicos#funciones|funciones vistas anteriormente]]. Además, podemos usar las siguientes instrucciones para recuperar columnas: * *****: Con el carácter '*' indicamos que queremos recuperar todas las columnas de la tabla. Si se usa esta instrucción, no podemos usar ALL o DISTINCT. * **ALL**: Indicamos que queremos recuperar la información de todas las filas de los elementos seleccionados, aunque haya valores repetidos. Es la opción por defecto, por lo que no es necesario escribirla. * **DISTINCT**: No se obtienen valores repetidos. * **FROM**: Indicamos la tabla de la que se extraerán los datos. Podrían ponerse varias tablas, para el caso de las [[bases_de_datos:mysql:lenguaje_mysql#consultas_multitabla|consultas multitabla]], pero eso se verá más adelante. === Alias === Se pueden utilizar alias, tanto para tablas como para columnas. Los alias especifican un nombre alternativo para la tabla o columna, a través del cual nos podemos referir a ella.\\ Puede haber dos motivos para asignar alias: * OPCIONAL: Hacer el nombre más "usable" o descriptivo. * OBLIGATORIO: Pueden darse casos ([[subconsultas correlacionadas]]) en los que sea necesario definir un alias para referirnos a esa estructura. Se verán más adelante. Se puede definir un alias con la cláusula AS, o poniendo directamente el nombre entre comillas dobles o simples. ==== WHERE ==== Con la sentencia opcional WHERE podemos filtrar los valores a recuperar, a través de una condición. Para cada fila se evalúa la condición, y retornará las expresiones siempre que el resultado de la expresión sea TRUE. ==== ORDER BY ==== Con esta sentencia ordenamos los resultados (expresiones) devueltas por la consulta. En caso de que haya varias expresiones para ordenar, se comenzará ordenando de izquierda a derecha.\\ Se puede ordenar seleccionando una expresión de columna o una determinada expresión de la sentencia SELECT, indicando la posición de la expresión en la sentencia SELECT por la que se quiere ordenar. ==== LIMIT ==== Con la sentencia LIMIT, se pueden establecer límite al número de resultados devuelto por la sentencia SELECT. Los parámetros a definir son: * **m** (opcional): Número de fila (de los valores devueltos) por el que comienza la visualización de resultados. Las filas comienzan a contarse partiendo de 0. Si se omite comenzará desde 0. * **n**: Indica el número de filas a visualizar. ==== Ejemplo ==== A continuación veremos algunos ejemplos de consulta sencilla.\\ Tenemos la tabla "EMPLEADOS": ^ emp_no ^ apellido ^ oficio ^ director ^ fecha_alta ^ salario ^ Comisión ^ dep_no ^ | 7499 | ALONSO | VENDEDOR | 7698 | 20/02/81 | 1400.0 | 400.00 | 30 | | 7521 | LOPEZ | EMPLEADO | 7782 | 08/05/81 | 1350.0 | NULL | 10 | | 7654 | MARTIN | VENDEDOR | 7698 | 28/09/81 | 1500.0 | 1600.00 | 30 | | 7698 | GARRIDO | DIRECTOR | 7839 | 01/05/81 | 3850.0 | NULL | 30 | | 7782 | MARTINEZ | DIRECTOR | 7839 | 09/06/81 | 2450.0 | NULL | 10 | | 7839 | REY | PRESIDENTE | NULL | 17/11/81 | 6000.0 | NULL | 10 | | 7844 | CALVO | VENDEDOR | 7698 | 08/09/81 | 1800.0 | 0.00 | 30 | | 7876 | GIL | ANALISTA | 7782 | 06/05/82 | 3350.0 | NULL | 20 | | 7900 | JIMENEZ | EMPLEADO | 7782 | 24/03/82 | 1400.0 | NULL | 20 | **Ejemplo 1:** Devolver los datos emp_no, apellido, salario, dep_no, de los 5 empleados que más salario tengan. SELECT emp_no, apellido, salario, dep_no FROM empleados ORDER by salario LIMIT 5; ^emp_no^apellido^salario^dep_no^ |7521|LOPEZ|1350.50|10| |7499|ALONSO|1400.00|30| |7900|JIMENEZ|1400.00|20| |7654|MARTIN|1500.00|30| |7844|CALVO|1800.00|30| **Ejemplo 2:** Devolver los datos emp_no, apellido, salario, dep_no, de los empleados que figura en las posiciones 5ª, 6ª y 7ª, del listado de empleados ordenado por orden alfabético de apellido. SELECT emp_no, apellido, salario, dep_no FROM empleados ORDER by apellido LIMIT 4,3; ^emp_no^apellido^salario^dep_no^ |7900|JIMENEZ|1400.00|20| |7521|LOPEZ|1350.50|10| |7654|MARTIN|1500.00|30| **Ejemplo 3:** Devolver los apellidos de los tres empleados que más ganan, junto con su salario anual (salario + comisión en 14 pagas), ordenados de mayor a menor. SELECT apellido, (salario + IFNULL(comision,0))*14 "Salario anual" FROM empleados ORDER by (salario+IFNULL(comision,0))*14 DESC LIMIT 3; ^apellido^Salario anual^ |REY|84000.00| |GARRIDO|53901.68| |GIL|46900.00| ===== Consultas con agrupamiento y funciones de grupo ===== ==== Consultas de selección con agrupamientos ==== SQL permite agrupar las filas de una tabla, seleccionadas en una consulta formando grupos según el contenido de una o varias expresiones, y obtener salidas calculadas a partir de los grupos formados.\\ Las salidas obtenidas son los resultados de agrupar y aplicar las funciones a cada uno de los grupos de las filas seleccionadas en la tabla. El formato de las consultas con selección de agrupamiento, se consigue al añadir al formato de consultas simples las sentencias: [GROUP BY ExpresionColumnaAgrupacion|Posicion] [,ExpresionColumnaAgrupacion|Posicion...] [HAVING CondicionSeleccionGrupos]] En primer lugar debemos tener claro que en el SELECT, las expresiones deben contener columnas de agrupación y/o funciones de grupo.\\ Si hay más de una expresión de agrupación, éstas se realizan de izquierda a derecha.\\ La claúsula HAVING se emplea para controlar qué grupos se seleccionan una vez realizada la agrupación (la condición debe ser TRUE). Está asociada a GROUP BY y no tiene sentido sin ella.\\ La cláusula ORDER BY no puede contener funciones de grupo. Si se desea ordenar por una de estas funciones, debe hacerse referenciando la posición que ocupa en el SELECT.\\ Ni en la clausula GROUP BY, ni en la condición de HAVING pueden utilizarse los Alias.\\ **Funcionamiento:**: - Primero se realiza una selección de filas según la cláusula WHERE. - Forma grupos según la clausula GROUP BY. - Hace una selección de los grupos a mostrar según la cláusula HAVING. Es importante tener en cuenta que, sólo pueden mostrarse expresiones que contengan columnas de agrupación y/o funciones de grupo. Además, si se utilizan funciones de agrupación sin la cláusula GROUP BY, no pueden mostrarse el resto de las filas de la tabla. ==== Funciones de grupo ==== ^ Función ^ Operación^ | AVG(expr) | Valor medio de "expr" ignorando los valores nulos | | COUNT ({*|expr}) | Número de veces que "expr" tiene un valor no nulo. La opción "*" cuenta el número de filas seleccionadas| | MAX(expr) | Valor máximo de "expr" | | MIN(expr) | Valor mínimo de "expr" | | STDDEV(expr) | Desviación típica de "expr" sin tener en cuenta los valores nulos | | SUM(expr) | Suma de "expr" | | VARIANCE(expr) | Varianza de "expr" sin tener en cuenta los valores nulos | ==== Ejemplo ==== Seleccionar los oficios que tengan dos o más empleados, cuyo salario supere los 1400 euros: SELECT oficio, COUNT(*) FROM empleados WHERE SALARIO > 1400 GROUP BY oficio HAVING COUNT(*) >= 2; ^ oficio ^ COUNT(*)^ | DIRECTOR | 2 | | VENDEDOR | 2 | ==== Formato de consulta con agrupamiento ==== SELECT { *|[ALL/DISTINCT] ExpresionColumna [[AS] AliasColumna] [, ExpresionColumna [[AS] AliasColumna]...] } FROM NombreTabla [AliasTabla] [WHERE CondicionSeleccion] [GROUP BY ExpresionColumnaAgrupacion|Posicion] [,ExpresionColumnaAgrupacion|Posicion...] [HAVING CondicionSeleccionGrupos]] [ORDER BY {ExpresionColumna|Posicion}[ASC|DESC] [,{ExpresionColumna|Posicion}[ASC|DESC]...] ] [LIMIT [m,]n]; ===== Subconsultas ===== Una subconsulta en SQL consiste en utilizar los resultados de una consulta dentro de otra, que se considera principal. Esta posibilidad fue la razón original para la palabra "estructurada" que da el nombre al SQL de Lenguaje de Consultas Estrucutradas (//Structured Query Language//).\\ Su uso se corresponde con la necesidad de ser capaces de tomar el resultado de una consulta, como valores a comparar por una consulta "principal", por no ser éstos constantes, con el fin de filtrar los resultados. Las subconsultas pueden encontrarse tanto en la cláusula WHERE, como en la HAVING, en el caso de la selección por agrupamiento de filas.\\ Es posible anidar subconsultas dentro de otras subconsultas, lo que le da una gran potencia a la cláusula SELECT. **Formato de subconsultas:** ( SELECT [ALL/DISTINCT] ExpresionColumna [, ExpresionColumna ...] FROM NombreTabla [, NombreTabla] [WHERE CondicionSeleccion] [GROUP BY ExpresionColumnaAgrupacion [,ExpresionColumnaAgrupacion...] [HAVING CondicionSeleccionGrupos]] ) El formato de una subconsulta, es el mismo que el de una consulta con las siguientes diferencias: * Toda la cláusula de la subconsulta va entre paréntesis. * No tiene sentido la cláusula ORDER BY, ya que los resultados de la subconsulta se utilizan internamente y no son visibles para el usuario. * Es posible que las expresiones de la subconsulta hagan referencia a las columnas de la tabla de la "consulta principal". Esto se conoce como **Referencias externas**. **Funcionamiento**: - Para cada fila de la consulta, se ejecuta la subconsulta. - Con ése resultado, se evalúa la fila correspondiente a la consulta. - Se muestra si el resultado de la evaluación es verdadero. Dado que los resultados de las subconsultas son usados para realizar una comparación con los valores de la consulta principal, con el fin de seleccionar los valores adecuados, la comparación con dicha consulta principal puede realizarse de diferentes formas, según las expresiones que retorne la subconsulta: * Subconsultas que retornan una sola expresión * Expresión simple (un único valor): operadores aritméticos (=, <>, <, >, <=, >=). * Expresión que devuelve más de un valor: operadores lógicos: * **[NOT] IN**: Comprueba si los valores de la fila actual de la consulta principal coincide con alguno de la lista de valores devueltos por la subconsulta. Si el resultado es afirmativo, la comparación es TRUE. La condición puede ser negada (TRUE si e resultado es negativo) añadiendo NOT. * **ANY**: Se utiliza junto a los comparadores aritméticos(=, <>, <, >, <=, >=). Si alguna de las comparaciones de la consulta principal, con los valores retornados por la subconsulta, es TRUE el operador ANY devuelve TRUE. Puede sustituirse por el operador IN. * **ALL**: También se utiliza junto a los comparadores aritméticos(=, <>, <, >, <=, >=). Para que ALL devuelva TRUE, TODAS las comparaciones entre los valores de la consulta principal y los devueltos por la subconsulta deben de ser TRUE. En el caso de "<> ALL", puede ser sustituido por NOT IN. * **[NOT] EXISTS**: En este caso la condición de selección consiste en comprobar que la subconsulta devuelve alguna fila seleccionada según la condición incluida en la propia subconsulta. Una subconsulta EXISTS puede ser expresada también por el operador IN. Se usa principalmente en [[bases_de_datos:mysql:lenguaje_mysql#subconsultas_correlacionadas|subconsultas correlacionadas]], que se verá más adelante. * Subconsultas que devuelven más de una expresión: simplemente hay que especificar en la consulta el mismo número de expresiones a comparar, que expresiones que retornarán que la subconsulta. Los operadores que se usarán serán '=' ó IN, según la subconsulta devuelva un valor o varios, respectivamente. ==== Subconsultas correlacionadas ==== En una subconsulta podemos hacer referencias a las columnas de la tabla de la consulta principal. Cuando los nombre de las columnas que aparecen en una subconsulta, son nombres de columnas de la consulta principal o de otra subconsulta más externa, se dice que son **referencias externas** y que la **subconsulta es correlacionada**.\\ Cuando en una subconsulta nos queremos referir a los datos de la columna de una tabla que ya han sido referenciados en la consulta principal, debemos especificar un alias para diferenciar ambas tablas (que en realidad son la misma). Según cada caso, se podrá (o no) poner un alias sólo a la tabla de la consulta, o se deberá poner en ambas. **Ejemplo 1**: SELECT e1.dep_no "Nº departamento", e1.oficio, salario FROM empleados e1 WEHERE e1.salario > (SELECT AVG (e2.salario) FROM empleados e2 WHERE e2.dep_no = e1.dep_no); Da el mismo resultado que: SELECT dep_no "Nº departamento", oficio, salario FROM empleados e1 WEHERE salario > (SELECT AVG (salario) FROM empleados WHERE dep_no = e1.dep_no); La 2ª opción es válida porque, si no se indica nada, la subconsulta siempre toma los valores correspondientes a esa subconsulta. Para referenciar nombre externos siempre es necesario anteponer el nombre de la tabla de la consulta. Si además ambas tablas (en consulta y subconsulta) son la misma, es imprescindible usar alias. **Ejemplo 2**: Tabla EMPLEADOS: ^ emp_no ^ apellido ^ oficio ^ director ^ fecha_alta ^ salario ^ Comisión ^ dep_no ^ | 7499 | ALONSO | VENDEDOR | 7698 | 20/02/81 | 1400.0 | 400.00 | 30 | | 7521 | LOPEZ | EMPLEADO | 7782 | 08/05/81 | 1350.0 | NULL | 10 | | 7654 | MARTIN | VENDEDOR | 7698 | 28/09/81 | 1500.0 | 1600.00 | 30 | | 7698 | GARRIDO | DIRECTOR | 7839 | 01/05/81 | 3850.0 | NULL | 30 | | 7782 | MARTINEZ | DIRECTOR | 7839 | 09/06/81 | 2450.0 | NULL | 10 | | 7839 | REY | PRESIDENTE | NULL | 17/11/81 | 6000.0 | NULL | 10 | | 7844 | CALVO | VENDEDOR | 7698 | 08/09/81 | 1800.0 | 0.00 | 30 | | 7876 | GIL | ANALISTA | 7782 | 06/05/82 | 3350.0 | NULL | 20 | | 7900 | JIMENEZ | EMPLEADO | 7782 | 24/03/82 | 1400.0 | NULL | 20 | Tabla DEPARTAMENTOS: ^ DEP_NO ^ DNOMBRE ^ LOCALIDAD ^ | 10 | Contabilidad | Barcelona | | 20 | Investigación | Valencia | | 30 | Ventas | Madrid | | 40 | Producción | Sevilla | Visualizar los departamentos en los que hay más de un trabajador: SELECT dep_no, dnombre FROM departamentos e WHERE EXISTS ( SELECT * FROM empleados d WHERE e.dep_no = d.dep_no GROUP BY dep_no HAVING COUNT(*) > 1); ===== Consultas Multitabla ===== Hasta ahora se han utilizados sentencias SQL en las que interviene una única tabla. Cuando se necesita obtener datos de dos o más tablas al mismo tiempo, se utilizan consultas multitabla.\\ Estas consultas simplemente se realizan indicando en el SELECT las diferentes columnas o expresiones a obtener (como se ha hecho siempre) sin importar la tabla a la que pertenecen. Se especifica en la clausula FROM las tablas a las que pertenecen.\\ Si hay dos columnas que se llaman igual, pero pertenecen a tablas diferentes, hay que especificar el nombre de la tabla en cada caso, de la forma //NombreTabla.NombreColumna//. También pueden utilizarse Alias, de forma similar a lo que se vio en el caso de las subconsultas correlacionadas.\\ Cuando se realiza una consulta multitabla, se realiza una multiplicación o producto cartesiano, de las tablas. Esto quiere decir que internamente se crea una tabla en la cual cada fila de las tablas especificadas se combina con todas las filas del resto de tablas indicadas.\\ Esto no es muy útil, y para quedarnos con la información que nos interesa es necesario filtrar la información a través de lo que se denominan **Composiciones** o **Combinaciones de tablas**, también denominadas **Join**. Este filtro resulta de aplicar una condición en la cláusula WHERE, denominada **Condición o Criterio de composición**.\\ Dependiendo de la condición de composición, tendremos: * **Composición natural**: * La condición de selección se establece con el operador de igualdad, entre las columnas que deban coincidir exactamente en tablas diferentes. * SQL no exige que las columnas de emparejamiento estén relacionadas como clave primaria y clave ajena, aunque suele ser lo habitual. * **Composición basada en desigualdad**: Consiste en que la condición de selección no sea una igualdad. Es posible realizar composiciones o combinaciones de una tabla consigo misma. Basta con especificar un alias diferente para la misma tabla (como si fuesen tablas diferentes) en la clausula FROM.\\ ==== Composiciones externas ==== Puede darse el caso de que al realizar una combinación multitabla, no se emparejen todas las filas que debieran, por falta de correspondencia. Esto ocurre cuando existen filas en una tabla que no tienen correspondencia con las filas de la otra tabla. \\ Si deseamos que aparezcan todos las filas de un determinado campo de una tabla, aunque no tenga correspondencia con las filas de la otra tabla, se realiza lo que se denomina una **Composición o Combinación Externa (Outer Join)**. === Formato=== SELECT [ALL/DISTINCT] ExpresionColumna [, ExpresionColumna ...] FROM NombreTabla [AliasTabla] { LEFT|RIGHT [OUTHER] JOIN NombreTabla [AliasTabla] ...} ON CondicionComposicion * **LEFT JOIN**: Se obtienen todas las filas de la tabla de la izquierda, aunque no tengan correspondencia en la tabla de la derecha (los valores serán NULL). * **RIGHT JOIN**: Se obtienen todas las filas de la tabla de la dereecha, aunque no tengan correspondencia en la tabla de la izquierda (los valores serán NULL). * **ON**: En el caso de las Combinaciones Externas, se utiliza la cláusula ON, en vez de WHERE, aunque el funcionamiento es exactamente el mismo. ==== Ejemplos ==== Tabla EMPLEADOS ^ emp_no ^ apellido ^ oficio ^ director ^ fecha_alta ^ salario ^ Comisión ^ dep_no ^ | 7499 | ALONSO | VENDEDOR | 7698 | 20/02/81 | 1400.0 | 400.00 | 30 | | 7521 | LOPEZ | EMPLEADO | 7782 | 08/05/81 | 1350.0 | NULL | 10 | | 7654 | MARTIN | VENDEDOR | 7698 | 28/09/81 | 1500.0 | 1600.00 | 30 | | 7698 | GARRIDO | DIRECTOR | 7839 | 01/05/81 | 3850.0 | NULL | 30 | | 7782 | MARTINEZ | DIRECTOR | 7839 | 09/06/81 | 2450.0 | NULL | 10 | | 7839 | REY | PRESIDENTE | NULL | 17/11/81 | 6000.0 | NULL | 10 | | 7844 | CALVO | VENDEDOR | 7698 | 08/09/81 | 1800.0 | 0.00 | 30 | | 7876 | GIL | ANALISTA | 7782 | 06/05/82 | 3350.0 | NULL | 20 | | 7900 | JIMENEZ | EMPLEADO | 7782 | 24/03/82 | 1400.0 | NULL | 20 | Tabla DEPARTAMENTOS: ^ DEP_NO ^ DNOMBRE ^ LOCALIDAD ^ | 10 | Contabilidad | Barcelona | | 20 | Investigación | Valencia | | 30 | Ventas | Madrid | | 40 | Producción | Sevilla | **Ejemplo de Composición o Combinación Natural** SELECT emp_no "Nº empleado", apellido "Apellido", dnombre "Departamento", localidad "Localidad" FROM empleados, departamentos WHERE empleados.dep_no = departamentos.dep_no; Resulta: ^Nº empleado^Apellido^Departamento^Localidad^ |7499|ALONSO|VENTAS|MADRID| |7521|LOPEZ|CONTABILIDAD|BARCELONA| |7654|MARTIN|VENTAS|MADRID| |7698|GARRIDO|VENTAS|MADRID| |7782|MARTINEZ|CONTABILIDAD|BARCELONA| |7839|REY|CONTABILIDAD|BARCELONA| |7844|CALVO|VENTAS|MADRID| |7876|GIL|INVESTIGACION|VALENCIA| |7900|JIMENEZ|INVESTIGACION|VALENCIA| **Ejemplo de composición basada en la desigualdad**\\ Listar los empleados de departamentos con códigos menores que el código de departamento de Barcelona: SELECT e.emp_no "Nº Empleado", e.apellido FROM empleados e, departamentos d WHERE d.localidad = 'Barcelona' AND e.dep_no > d.dep_no; Resulta: ^Nº Empleado^apellido^ |7499|ALONSO| |7654|MARTIN| |7698|GARRIDO| |7844|CALVO| |7876|GIL| |7900|JIMENEZ| **Ejemplo de consulta de una tabla consigo misma**\\ Obtener la lista de empleados con los nombres de sus directores. SELECT e1.emp_no "Nº Empleado", e1.apellido "Nombre empleado", e1.director "Nº Director", e2.apellido "Nombre Director" FROM empleados e1, empleados e2 WHERE e1.director = e2.emp_no; Obteniendo como resultado: ^Nº Empleado^Nombre empleado^Nº Director^Nombre Director^ |7499|ALONSO|7698|GARRIDO| |7521|LOPEZ|7782|MARTINEZ| |7654|MARTIN|7698|GARRIDO| |7698|GARRIDO|7839|REY| |7782|MARTINEZ|7839|REY| |7844|CALVO|7698|GARRIDO| |7876|GIL|7782|MARTINEZ| |7900|JIMENEZ|7782|MARTINEZ| **Ejemplo de combinaciones externas**\\ Obtener los departamentos con su nombre, localidad y número de empleados trabajando en ellos, incluyendo los que no tienen empleados. SELECT dnombre "Departamento", localidad "localidad", COUNT(emp_no) "Nº empleados" FROM departamentos d LEFT JOIN empleados e ON d.dep_no = e.dep_no GROUP BY dnombre, localidad; Resulta: ^Departamento^localidad^Nº empleados^ |CONTABILIDAD|BARCELONA|3| |INVESTIGACION|VALENCIA|2| |PRODUCCION|SEVILLA|0| |VENTAS|MADRID|4| ===== Composiciones y subconsultas ===== Hay ocasiones que una consulta puede resolverse con una composición o combinación (Join) de tablas, o una subconsulta.\\ Si puede solucionarse de ambas formas, siempre será preferible hacerlo con una subconsulta, ya que las consultas multitabla siempre requerirán más tiempo y recursos.\\ En general, si no se necesitan visualizar columnas de más de una tabla, de utilizarán subconsultas. En caso contrario, se usará un join. ===== Formato completo de consultas ===== SELECT { *|[ALL/DISTINCT] ExpresionColumna [AliasColumna] [, ExpresionColumna [AliasColumna]...] } FROM NombreTabla [AliasTabla] [, NombreTabla [AliasTabla] ...] [WHERE {CondicionSeleccion|CondicionComposicion}] [GROUP BY ExpresionColumnaAgrupacion|Posicion] [,ExpresionColumnaAgrupacion|Posicion...] [HAVING CondicionSeleccionGrupos]] [ORDER BY {ExpresionColumna|Posicion}[ASC|DESC] [,{ExpresionColumna|Posicion}[ASC|DESC]...] ] [LIMIT [m,]n]; ===== Consultas dentro de otras instrucciones ===== ==== Creación de una tabla a partir de una selección de otra tabla ==== CREATE TABLE [IF NOT EXISTS] NombreTabla [( DefinicionColumna [, DefinicionColumna ...] )] [IGNORE|REPLACE] SentenciaSelect Los nombres de las columnas de la nueva tabla son opcionales y en caso de que no se especifiquen, recibirán los valores de la otra tabla, o sus alias correspondientes. Si hay expresiones o funciones en la lista del SELECT, deben indicarse nombre o alias, ya que en caso contrario estos valores no podrán referenciarse.\\ Para saber qué acción tomar cuando se produce la repetición de un campo UNIQUE o PRIMARY KEY, podemos indicar IGNORE (no se guarda el nuevo dato y es ignorado) o REPLACE (el dato reemplaza al anterior). Si no se indica nada y ocurre la coincidencia, se producirá un error.\\ LA nueva tabla creada no hereda las constraints, por lo que habría que crearlas en la definición de la misma, o añadirlas posteriormente con ALTER TABLE.\\ Al crear la nueva tabla, se insertan las filas correspondientes de la tabla resultado de la sentencia SELECT. ==== Actualización de una tabla a partir de una subconsulta ==== INSERT INTO NombreTabla [( NombreColumna [,NombreColumna ...] )] SELECT FormatoSelect La lista de columnas es opcional, pero deberá especificarse si las columnas que devuelve la consulta no coinciden en número u orden con las columnas de la tabla destino.\\ ==== Modificaciones con subconsultas ==== En este caso, la condición que deben cumplir las filas que deseamos modificar implica la realización de una subconsulta a otras tablas.\\ La forma de hacerlo es incluyendo la subconsulta en la cláusula WHERE.\\ Existen algunas limitaciones: * La tabla destino no puede aparecer en la consulta. * No se puede incluir la cláusula ORDER BY en la consulta. **Ejemplo** Se desea elevar 500 euros el salario de todos los empleados cuyo departamento no esté en Madrid. UPDATE empleados SET salario = salario + 500 WHERE dep_no NOT IN ( SELECT dep_no FROM departamentos WHERE localidad <> 'Madrid' ); ==== Eliminaciones con subconsultas ==== En ocasiones la condición que deben cumplir las filas que queremos eliminar implica realizar una subconsulta a otras tablas. En estos casos se incluirá la subconsulta en la cláusula WHERE con las mismas restricciones que las modificaciones: * La tabla destino no puede aparecer en la consulta. * No se puede incluir la cláusula ORDER BY en la consulta. Se pueden utilizar subconsultas anidadas a varios niveles, pero respetando la siguiente restricción: **La tabla destino no puede aparecer en la cláusula FROM de ninguna de las subconsultas que intervienen en la selección. __Sí se permiten referencias externas__.** **Ejemplo** DELETE FROM departamentos WHERE NOT EXISTS ( SELECT * FROM empleados WHERE empleados.dep_no = departamentos.dep_no ); ===== Vistas ===== Una vista es una "tabla virtual" que se almacena en memoria y que se crea a partir de una consulta. Esta "tabla virtual" o "Vista", está "conectada" directamente a las tablas de origen, de forma que se mantiene constantemente actualizada en tiempo real. Podemos operar sobre la vista como si de una tabla corriente se tratase, sirviendo de interfaz con el usuario y los datos de interés.\\ Ventajas del uso de vistas: * Seguridad y confidencialidad: La vista ocultará los datos a los que el usuario no tenga permiso de acceso. * Comodidad: Sólo muestra los datos relevantes, aunque pertenezcan en realidad a diferentes tablas. Se permite incluso trabajar con agrupaciones de filas como si se tratase de una sola, o composiciones de tablas como si fuera sólo una. * Sigue funcionando aunque se produzcan cambios en las tablas de origen (nombres de columnas, tablas, etc). ==== Creación de vistas ==== CREATE VIEW NombreVista [( DefinicionColumna [,DefinicionColumna ...] )] AS Consulta; Deben tenerse en cuenta algunas consideraciones cuando se crean vistas: * Si no empleamos nombres para las columnas y expresiones, sólo podremos referirnos a ellas con un SELECT * * No se puede usar la cláusula ORDER BY en la creación de una vista. * es obligatorio definir nombres de columnas o alias, cuando la vista devuelve funciones de agrupamiento (SUM, COUNT, etc), y posteriormente quiere hacerse referencia a ellas. * Pueden usarse funciones de agrupación para crear vistas. Después también es posible usar funciones de agrupación en las consultas sobre esas mismas vistas, de forma que podemos recuperar "dobles agrupamientos", que no están permitidos por el estándar. Se pueden realizar consultas a las vistas, de la misma manera que se hacía a las tablas. ==== Ejemplo ==== Creamos una vista para trabajar con los datos de dos tablas agrupados y seleccionando las filas que interesen (todos los departamentos que tengan más de dos empleados): CREATE VIEW resumen_emp_dep (departamento, num_empleados, suma_salario) AS SELECT dnombre, COUNT(emp_no), SUM(salario) FROM empleados, departamentos WHERE empleados.dep_no = departamentos.dep_no GROUP BY empleados.dep_no, dnombre HAVING COUNT(*) > 2; Consultamos los datos del número de empleados por departamento: SELECT departamento, num_empleados FROM resumen_emp_dep; Que resulta: ^departamento^num_empleados^ |CONTABILIDAD|3| |VENTAS|4| ==== Eliminación de vistas ==== DROP VIEW [IF EXISTS] NombreVista [RESTRICT|CASCADE] RESTRICT y CASCADE están permitidas pero no implementadas en la versión 5 de MySQL.