Documentos de Académico
Documentos de Profesional
Documentos de Cultura
¿Qué es el SQL ?
Antes de empezar debes tener unas nociones básicas de bases de datos relacionales, si
quieres repasarlas haz clic aquí
Una tabla tiene cero o más filas, cada fila contiene la información de un determinado
'sujeto' de la tabla, por ejemplo en una tabla de alumnos, en una fila tenemos los datos de
un alumno. Las filas en un principio están desordenadas.
Cada columna representa un 'campo' de la tabla, sirve para almacenar una determinada
información, por ejemplo en una tabla de alumnos tendremos una columna para almacenar
el nombre de los alumnos.
Todos los valores de una columna determinada tienen el mismo tipo de dato, y éstos
están extraídos de un conjunto de valores legales llamado dominio de la columna. A parte
de los valores del dominio, una columna puede contener el valor nulo (NULL) que indica
que no contiene ningún valor.
En una tabla no pueden haber dos columnas con el mismo nombre pero ese nombre sí
se puede utilizar en otra tabla.
Normalmente todas las tablas deben tener una clave principal definida. Una clave
principal es una columna (o combinación de columnas) que permite identificar de forma
inequívoca cada fila de la tabla, por lo que no pueden haber en una tabla dos filas con el
mismo valor en la columna definida como clave principal.
Una clave foránea es una columna (o combinación de columnas) que contiene un valor
que hace referencia a una fila de otra tabla (en algunos casos puede ser la misma tabla).
Una tabla tiene una única clave primaria. Una tabla puede contener cero o más claves
foráneas.
Cuando se define una columna como clave principal, ninguna fila de la tabla puede
contener un valor nulo en esa columna ni tampoco se pueden repetir valores en la
columna.
Cuando se define una columna como clave foránea, las filas de la tabla pueden
contener en esa columna o bien el valor nulo, o bien un valor que existe en la otra tabla.
Eso es lo que se denomina integridad referencial que consiste en que los datos que
referencian otros (clave foránea) deben ser correctos.
Las bases de datos de Access2000 tienen la extensión .MDB para que el ordenador las
reconozca como tal.
Por supuesto, a partir del estándar cada sistema ha desarrollado su propio SQL que puede
variar de un sistema a otro, pero con cambios que no suponen ninguna complicación para
alguien que conozca un SQL concreto, como el que vamos a ver aquí corespondiente al
Access2000.
Como su nombre indica, el SQL nos permite realizar consultas a la base de datos.
Pero el nombre se queda corto ya que SQL además realiza funciones de definición,
control y gestión de la base de datos. Las sentencias SQL se clasifican según su
finalidad dando origen a tres ‘lenguajes’ o mejor dicho sublenguajes:
Todas las sentencias empiezan con un verbo (palabra reservada que indica la acción a
realizar), seguido del resto de cláusulas, algunas obligatorias y otras opcionales que
completan la frase. Todas las sentencias siguen una sintaxis para que se puedan ejecutar
correctamente, para describir esa sintaxis utilizaremos un diagrama sintáctico como el que
se muestra a continuación.
Cómo interpretar un diagrama sintáctico
Las palabras que aparecen
en mayúsculas son palabras
reservadas se tienen que poner
tal cual y no se pueden utilizar
para otro fin, por ejemplo, en el
diagrama de la figura tenemos
las palabras reservadas
SELECT, ALL, DISTINCT,
FROM, WHERE.
Las palabras en minúsculas
son variables que el usuario
deberá sustituir por un dato
concreto. En el diagrama
tenemos nbcolumna, expresion-
tabla y condicion-de-busqueda.
Una sentencia válida se construye siguiendo la línea a través del diagrama hasta el punto
que marca el final. Las líneas se siguen de izquierda a derecha y de arriba abajo. Cuando
se quiere alterar el orden normal se indica con una flecha.
Hay que empezar por la palabra SELECT, después puedes poner ALL o bien DISTINCT o
nada, a continuación un nombre de columna, o varios separados por comas, a
continuación la palabra FROM y una expresión-tabla, y por último de forma opcional puedes
incluir la cláusula WHERE con una condición-de-búsqueda.
Por ejemplo:
Cuando una palabra opcional está subrayada, esto indica que ese es el valor por defecto
( el valor que se asume si no se pone nada). En el ejemplo anterior las dos primeras
sentencias son equivalentes (en el diagrama ALL aparece subrayada).
Cómo se crea una sentencia SQL en
ACCESS
Este manual está basado en el SQL del motor de base de datos que utiliza el
Access2000, el Microsoft Jet 4.x, para que los ejemplos y ejercicios se puedan ejecutar y
probar. Aunque el curso esté realizado para Access2000, sirve también para Access en sus
versiones posteriores Access 2002, Access 2003 y Access 2007.
Para crear y después ejecutar una sentencia SQL en Access, lo fácil es utilizar la
ventana SQL de las consultas.
Si nos hemos equivocado a la hora de escribir la sintaxis, Access nos saca un mensaje
de error y muchas veces el cursor se queda posicionado en la palabra donde ha saltado el
error. Ojo, a veces el error está antes o después de donde se ha quedado el cursor.
Si no saca ningún mensaje de error, esto quiere decir que la sentencia respeta la sintaxis
definida, pero esto no quiere decir que la sentencia esté bien, puede que no obtenga lo que
nosotros queremos, en este caso habrá que rectificar la sentencia.
pedidos:
Objetivo
Empezaremos por estudiar la sentencia SELECT, que permite recuperar datos de una o
varias tablas. La sentencia SELECT es con mucho la más compleja y potente de las
sentencias SQL. Empezaremos por ver las consultas más simples, basadas en una sola
tabla.
Esta sentencia forma parte del DML (lenguaje de manipulación de datos), en este tema
veremos cómo seleccionar columnas de una tabla, cómo seleccionar filas y cómo
obtener las filas ordenadas por el criterio que queramos.
El resultado de la consulta es una tabla lógica, porque no se guarda en el disco sino que
está en memoria y cada vez que ejecutamos la consulta se vuelve a calcular.
Si no conoces todavía las tablas que utilizaremos para los ejemplos y ejercicios clic aquí
Con la cláusula FROM indicamos en qué tabla tiene que buscar la información. En
este capítulo de consultas simples el resultado se obtiene de una única tabla. La sintaxis de
la cláusula es:
Una especificación de tabla puede ser el nombre de una consulta guardada (las que
aparecen en la ventana de base de datos), o el nombre de una tabla que a su vez puede
tener el siguiente formato:
En una SELECT podemos utilizar tablas que no están definidas en la base de datos
(siempre que tengamos los permisos adecuados claro), si la tabla no está en la base de
datos activa, debemos indicar en qué base de datos se encuentra con la cláusula IN.
Supongamos que la tabla empleados estuviese en otra base de datos llamada otra en la
carpeta c:\mis documentos\, habría que indicarlo así:
SELECT *
FROM empleados IN 'c:\mis documentos\otra.mdb'
Generalmente tenemos las tablas en la misma base de datos y no hay que utilizar la
cláusula IN.
Selección de columnas
La lista de columnas que queremos que aparezcan en el resultado es lo que
llamamos lista de selección y se especifica delante de la cláusula FROM.
Utilización del *
Si añadimos una columna nueva en la tabla, esta nueva columna saldrá sin tener que
modificar la consulta.
Se puede combinar el * con el nombre de una tabla (ej. oficinas.*), pero esto se utiliza más
cuando el origen de la consulta son dos tablas.
Ejemplos :
Alias de columna.
Cuando se visualiza el resultado de la consulta, normalmente las columnas toman el
nombre que tiene la columna en la tabla, si queremos cambiar ese nombre lo podemos
hacer definiendo un alias de columna mediante la cláusula AS será el nombre que
aparecerá como título de la columna.
Ejemplo:
Columnas calculadas.
Además de las columnas que provienen directamente de la tabla origen, una consulta SQL
puede incluir columnas calculadas cuyos valores se calculan a partir de los valores de los
datos almacenados.
Para solicitar una columna calculada, se especifica en la lista de selección una expresión
en vez de un nombre de columna. La expresión puede contener sumas, restas,
multiplicaciones y divisiones, concatenación & , paréntesis y también funciones
predefinidas).
Para ver con más detalle cómo formar una expresión pincha aquí
Formar expresiones.
Operadores.
También se puede utilizar el operador de suma + cuando los dos operandos son de tipo
texto, para concatenarlos. Mi consejo es utilizar el operador & para la concatenación y así
evitar errores o confusiones.
Un operando puede ser un nombre de columna, una expresión, un valor concreto o una
función predefinida.
Valores concretos
Los valores numéricos se indican poniendo el número sin más. Siempre se tiene que
utilizar el punto para separar la parte entera de los decimales, aunque nuestra
configuración utilice la coma; además los valores numéricos no se pueden escribir
formateados, no podemos escribirlos con separadores de miles. Por ejemplo en una
expresión correcta no puedo escribir (ventas + 1.000.000) ni tampoco (ventas +
1,000,000), tengo que escribir (ventas +1000000)
Ejemplo: 2
Los valores de tipo texto deben ir siempre entre comillas simples ' o dobles ".
Los literales de fecha se escriben entre # y deben estar en el formato de EE.UU., incluso
si no estamos utilizando la versión norteamericana del motor de base de datos Microsoft
Jet. Por ejemplo, el 10 de mayo de 1996, se escribe 10/5/96 en España y Latinoamérica, y
5/10/96 en Estados Unidos de América. Para indicar la fecha 10 de mayo de 1996 en
cualquier base de datos sea española, latinoamericana o de EE.UU., debemos escribirla
#5/10/96#; con el formato #mes/dia/año#
Funciones predefinidas.
Cuando combinamos varias expresiones podemos utilizar los paréntesis para delimitar
cada expresión. Siempre se tiene que utilizar un paréntesis de apertura ( y uno de cierre ).
El uso del paréntesis sirve para que la expresión quede más clara sobre todo cuando
combinamos muchas expresiones, y para que los operadores actuen en el orden que
nosotros queramos para así olvidarnos de la prioridad de los operadores.
Ejemplos:
Para ordenar las filas del resultado de la consulta, tenemos la cláusula ORDER BY.
Con esta cláusula se altera el orden de visualización de las filas de la tabla pero en
ningún caso se modifica el orden de las filas dentro de la tabla. La tabla no se modifica.
Ejemplo:
Por defecto el orden será ascendente (ASC) (de menor a mayor si el campo es
numérico, por orden alfabético si el campo es de tipo texto, de anterior a posterior si el
campo es de tipo fecha/hora, etc...
Ejemplos:
SELECT nombre,
Obtiene un listado de los empleados ordenados
numemp,ventas
por volúmen de ventas sacándo los de menores
FROM empleados
ventas primero.
ORDER BY ventas
Ejemplos:
SELECT nombre,
Obtiene un listado de los empleados ordenados
numemp,ventas
por volúmen de ventas sacando primero los de
FROM empleados
mayores ventas.
ORDER BY ventas DESC
También podemos ordenar por varias columnas, en este caso se indican las
columnas separadas por comas.
Se ordenan las filas por la primera columna de ordenación, para un mismo valor de la
primera columna, se ordenan por la segunda columna, y así sucesivamente.
La cláusula DESC o ASC se puede indicar para cada columna y así utilizar una
ordenación distinta para cada columna. Por ejemplo ascendente por la primera columna y
dentro de la primera columna, descendente por la segunda columna.
Ejemplos:
Selección de filas
A continuación veremos las cláusulas que nos permiten indicar qué filas queremos
visualizar.
Por ejemplo queremos saber los dos empleados más antiguos de la empresa.
El número de filas que queremos visualizar se puede expresar con un número entero o
como un porcentaje sobre el número total de filas que se recuperarían sin la cláusula
TOP. En este último caso utilizaremos la cláusula TOP n PERCENT (porcentaje en inglés).
En la consulta sólo aparecerán las filas para las cuales la condición es verdadera (TRUE),
los valores nulos (NULL) no se incluyen por lo tanto en las filas del resultado. La condición
de selección puede ser cualquier condición válida o combinación de condiciones
utilizando los operadores NOT (no) AND (y) y OR (ó). En ACCESS2000 una cláusula
WHERE puede contener hasta 40 expresiones vinculadas por operadores lógicos AND y
OR. Si quieres ver cómo funcionan los operadores lógicos
Operadores lógicos.
Para ver cómo funcionan los operadores lógicos utilizaremos las tablas de verdad de
estos operadores.
Operador AND .
Para que el resultado sea verdadero las dos condiciones deben ser verdaderas.
AND TRUE FALSE NULL
TRUE TRUE FALSE NULL
FALSE FALSE FALSE FALSE
NULL NULL FALSE NULL
Operador OR .
Operador NOT .
El resultado es invertido.
NOT TRUE FALSE NULL
FALSE TRUE NULL
SELECT nombre
FROM empleados Lista el nombre de los empleados de la
WHERE oficina = 12 oficina 12.
Las condiciones de selección son las condiciones que pueden aparecer en la cláusula
WHERE.
el test de comparación
el test de rango
el test de pertenencia a un conjunto
el test de valor nulo
el test de correspondencia con patrón .
El test de comparación.
= igual que
<> distinto de
< menor que
<= menor o igual
> mayor que
>= mayor o igual
SELECT numemp, nombre Lista los empleados contratados antes del año 88
FROM empleados (cuya fecha de contrato sea anterior al 1 de enero
WHERE contrato < #01/01/1988# de 1988).
¡¡Ojo!!, las fechas entre almohadillas # # deben
estar con el formato mes,dia,año aunque
tengamos definido otro formato para nuestras
fechas.
SELECT oficina Lista las oficinas cuyas ventas estén por debajo
FROM oficinas del 80% de su objetivo.
WHERE ventas < objetivo * 0.8 Hay que utilizar siempre el punto decimal aunque
tengamos definida la coma como separador de
decimales.
SELECT numemp, nombre, oficina Lista los empleados de las oficinas 12, 14 y 16
FROM empleados
WHERE oficina IN (12,14,16)
Una condición de selección puede dar como resultado el valor verdadero TRUE, falso
FALSE o nulo NULL.
Cuando una columna que interviene en una condición de selección contiene el valor nulo,
el resultado de la condición no es verdadero ni falso, sino nulo, sea cual sea el test que
se haya utilizado. Por eso si queremos listar las filas que tienen valor en una determinada
columna, no podemos utilizar el test de comparación, la condición oficina = null devuelve el
valor nulo sea cual sea el valor contenido en oficina. Si queremos preguntar si una columna
contiene el valor nulo debemos utilizar un test especial, el test de valor nulo.
Tiene la siguiente sintaxis:
Ejemplos:
Se utiliza cuando queremos utilizar caracteres comodines para formar el valor con el
comparar.
Tiene la siguiente sintaxis:
Ejemplos:
SELECT numemp, nombre Lista los empleados cuyo nombre empiece por
FROM empleados Luis (Luis seguido de cero o más caracteres).
WHERE nombre LIKE 'Luis*'
SELECT numemp, nombre Lista los empleados cuyo nombre contiene Luis,
FROM empleados en este caso también saldría los empleados José
WHERE nombre LIKE '*Luis*' Luis (cero o más caracteres seguidos de LUIS y
seguido de cero o más caracteres).
SELECT numemp, nombre Lista los empleados cuyo nombre contenga una a
FROM empleados como tercera letra (dos caracteres, la letra a, y
WHERE nombre LIKE '??a*' cero o más caracteres.
Caracteres comodines.
En la siguiente tabla se indican los caracteres que comodines que se pueden poner en
un patrón y su significado
Los comodines _ y % sólo funcionan con la versión de Microsoft Jet 4.X. Por
ejemplo no funcionan en Access97.
El guión - define un intervalo unicamente cuando aparece dentro de los corchetes entre
dos caracteres, en cualquier otro caso representa el carácter guión.
El significado del intervalo especificado depende de la ordenación de caracteres, esta
ordenación la podemos cambiar en la pestaña General del cuadro de diálogo Opciones,
menú Herramientas:
Nota: Para que el cambio de orden tenga efecto se debe compactar la base de datos.
(Menú Herramientas--> Utilidades de la base de datos--> Compactar y reparar base
de datos).
Caracteres comodines.
En la siguiente tabla se indican los caracteres que comodines que se pueden poner en un
patrón y su significado
Los comodines _ y % sólo funcionan con la versión de Microsoft Jet 4.X. Por ejemplo
no funcionan en Access97.
El guión - define un intervalo unicamente cuando aparece dentro de los corchetes entre
dos caracteres, en cualquier otro caso representa el carácter guión.
El significado del intervalo especificado depende de la ordenación de caracteres, esta
ordenación la podemos cambiar en la pestaña General del cuadro de diálogo Opciones,
menú Herramientas:
Nota: Para que el cambio de orden tenga efecto se debe compactar la base de datos.
(Menú Herramientas--> Utilidades de la base de datos--> Compactar y reparar base de
datos).
Antes de empezar deberías crear la base de datos datos.mdb con las tablas descritas en
el tema 1 clic aquí para verlas.
Nota: Debes crear una consulta por cada ejercicio, no se pueden escribir varias
sentencias SQL en una misma consulta.
Si quieres puedes guardar cada consulta con un nombre que permita identificarla por
ejemplo: consulta_2_1 siendo 2 el número del tema y 1 el número del ejercicio dentro del
tema.
Ahora puedes empezar a redactar las sentencias SQL para obtener lo que se pide en
cada ejercicio.
La lista de selección
1 Obtener una lista de todos los productos indicando para cada uno su idfab, idproducto,
descripción, precio y precio con I.V.A. incluido (es el precio anterior aumentado en un 16%).
2 De cada pedido queremos saber su número de pedido, fab, producto, cantidad, precio
unitario e importe.
Ordenación de filas.
4 Obtener la lista de los clientes agrupados por código de representante asignado,
visualizar todas la columnas de la tabla.
5 Obtener las oficinas ordenadas por orden alfabético de región y dentro de cada región
por ciudad, si hay más de una oficina en la misma ciudad, aparecerá primero la que tenga
el número de oficina mayor.
Selección de filas.
7 Listar las cuatro líneas de pedido más caras (las de mayor importe).
8 Obtener las mismas columnas que en el ejercicio 2 pero sacando unicamente las 5
líneas de pedido de menor precio unitario.
10 Listar los números de los empleados que tienen una oficina asignada.
12 Listar los datos de las oficinas de las regiones del norte y del este (tienen que
aparecer primero las del norte y después las del este).
Introducción
En este tema vamos a estudiar las consultas multitabla llamadas así porque están
basadas en más de una tabla.
- la unión de tablas
- la composición de tablas
La unión de tablas
Esta operación se utiliza cuando tenemos dos tablas con las mismas columnas y
queremos obtener una nueva tabla con las filas de la primera y las filas de la segunda.
En este caso la tabla resultante tiene las mismas columnas que la primera tabla (que son
las mismas que las de la segunda tabla).
Por ejemplo tenemos una tabla de libros nuevos y una tabla de libros antiguos y
queremos una lista con todos los libros que tenemos. En este caso las dos tablas tienen las
mismas columnas, lo único que varía son las filas, además queremos obtener una lista de
libros (las columnas de una de las tablas) con las filas que están tanto en libros nuevos
como las que están en libros antiguos, en este caso utilizaremos este tipo de operación.
Cuando hablamos de tablas pueden ser tablas reales almacenadas en la base de datos
o tablas lógicas (resultados de una consulta), esto nos permite utilizar la operación con
más frecuencia ya que pocas veces tenemos en una base de datos tablas idénticas en
cuanto a columnas. El resultado es siempre una tabla lógica.
Por ejemplo queremos en un sólo listado los productos cuyas existencias sean iguales a
cero y también los productos que aparecen en pedidos del año 90. En este caso tenemos
unos productos en la tabla de productos y los otros en la tabla de pedidos, las tablas no
tienen las mismas columnas no se puede hacer una union de ellas pero lo que interesa
realmente es el identificador del producto (idfab,idproducto), luego por una parte sacamos
los códigos de los productos con existencias cero (con una consulta), por otra parte los
códigos de los productos que aparecen en pedidos del año 90 (con otra consulta), y luego
unimos estas dos tablas lógicas.
La composición de tablas
La composición de tablas consiste en concatenar filas de una tabla con filas de otra. En
este caso obtenemos una tabla con las columnas de la primera tabla unidas a las
columnas de la segunda tabla, y las filas de la tabla resultante son concatenaciones de
filas de la primera tabla con filas de la segunda tabla.
A diferencia de la unión la composición permite obtener una fila con datos de las dos
tablas, esto es muy útil cuando queremos visualizar filas cuyos datos se encuentran en dos
tablas.
Por ejemplo queremos listar los pedidos con el nombre del representante que ha hecho el
pedido, pues los datos del pedido los tenemos en la tabla de pedidos pero el nombre del
representante está en la tabla de empleados y además queremos que aparezcan en la
misma línea; en este caso necesitamos componer las dos tablas (Nota: en el ejemplo
expuesto a continuación, hemos seleccionado las filas que nos interesan).
. El producto cartesiano
. El INNER JOIN
El operador UNION
Como ya hemos visto en la página anterior, el operador UNION sirve para obtener a partir
de dos tablas con las mismas columnas, una nueva tabla con las filas de la primera y las
filas de la segunda.
La sintaxis es la siguiente:
Consulta puede ser un nombre de tabla, un nombre de consulta (en estos dos
casos el nombre debe estar precedido de la palabra TABLE), o una sentencia SELECT
completa (en este caso no se puede poner TABLE). La sentencia SELECT puede ser
cualquier sentencia SELECT con la única restricción de que no puede contener la cláusula
ORDER BY.
Las dos consultas deben tener el mismo número de columnas pero las columnas
pueden llamarse de diferente forma y ser de tipos de datos distintos.
Por defecto la unión no incluye filas repetidas, si alguna fila está en las dos tablas,
sólo aparece una vez en el resultado.
Si queremos que aparezcan todas las filas incluso las repeticiones de filas, incluimos la
palabra ALL (todo en inglés).
Se puede unir más de dos tablas, para ello después de la segunda consulta
repetimos la palabra UNION ... y así sucesivamente.
También podemos indicar que queremos el resultado ordenado por algún criterio, en
este caso se incluye la cláusula ORDER BY que ya vimos en el tema anterior. La cláusula
ORDER BY se escribe después de la última consulta, al final de la sentencia; para indicar
las columnas de ordenación podemos utilizar su número de orden o el nombre de la
columna, en este último caso se deben de utilizar los nombres de columna de la primera
consulta ya que son los que se van a utilizar para nombrar las columnas del resultado.
Para ilustrar la operación vamos a realizar el ejercicio visto en la página anterior, vamos a
obtener los códigos de los productos que tienen existencias iguales a cero o que aparezcan
en pedidos del año 90.
SELECT idfab,idproducto
FROM productos
WHERE existencias = 0
TABLE [existencias cero]
UNION ALL
UNION ALL
SELECT fab,producto o bien
TABLE [pedidos 90]
FROM pedidos
ORDER BY idproducto
WHERE year(fechapedido) = 1990
ORDER BY idproducto
Se ha incluido la cláusula ALL porque no nos importa que salgan filas repetidas.
Se ha incluido ORDER BY para que el resultado salga ordenado por idproducto, observar
que hemos utilizado el nombre de la columna de la primera SELECT, también podíamos
haber puesto ORDER BY 2 pero no ORDER BY producto (es el nombre de la columna de
la segunda tabla).
Para el 2º caso hemos creado una consulta llamada existencias cero con la primera
SELECT, y una consulta llamada pedidos 90 con la segunda SELECT. Observar que los
nombres de las consultas están entre corchetes porque contienen espacios en blanco, y
que en este caso hay que utilizar TABLE.
Principio del formulario
Tema 3. Las consultas
multitabla (III) Búsqueda
El producto cartesiano
nbtabla puede ser un nombre de tabla o un nombre de consulta. Si todas las tablas
están en una base de datos externa, añadiremos la cláusula IN basedatosexterna
después de la última tabla. Pero para mejorar el rendimiento y facilitar el uso, se
recomienda utilizar una tabla vinculada en lugar de la cláusula IN.
Hay que tener en cuenta que el producto cartesiano obtiene todas las posibles
combinaciones de filas por lo tanto si tenemos dos tablas de 100 registros cada una, el
resultado tendrá 100x100 filas, si el producto lo hacemos de estas dos tablas con una
tercera de 20 filas, el resultado tendrá 200.000 filas (100x100x20) y estamos hablando de
tablas pequeñas. Se ve claramente que el producto cartesiano es una operación costosa
sobre todo si operamos con más de dos tablas o con tablas voluminosas.
Se puede componer una tabla consigo misma, en este caso es obligatorio utilizar
un nombre de alias por lo menos para una de las dos.
Por ejemplo: SELECT * FROM empleados, empleados emp
Para ver cómo funciona el producto cartesiano cogemos las consultas [existencias cero] y
[pedidos 90] creadas en la página anterior, y creamos una consulta que halle el producto
cartesiano de las dos.
SELECT *
obtenemos
FROM [existencias cero],
la siguiente
[pedidos 90]
tabla:
Se observa que tenemos las dos filas de la primera consulta combinadas con las dos filas
de la segunda.
SELECT *
FROM pedidos,clientes
WHERE pedidos.clie=clientes.numclie
Combinamos todos los pedidos con todos los clientes pero luego seleccionamos los que
cumplan que el código de cliente de la tabla de pedidos sea igual al código de cliente de la
tabla de clientes, por lo tanto nos quedamos con los pedidos combinados con los datos del
cliente correspondiente.
Normalmente emparejamos tablas que están relacionadas entre sí y una de las columnas
de emparejamiento es clave principal, pues en este caso, cuando una de las columnas de
emparejamiento tienen un índice definido es más eficiente utilizar otro tipo de
composición, el INNER JOIN.
Principio del formulario
Tema 3. Las consultas
multitabla (IV) Búsqueda
El INNER JOIN
La sintaxis es la siguiente:
Ejemplo:
SELECT *
FROM pedidos INNER JOIN clientes ON pedidos.clie = clientes.numclie
tabla1 y tabla2 son especificaciones de tabla (nombre de tabla con alias o no, nombre
de consulta guardada), de las tablas cuyos registros se van a combinar.
Pueden ser las dos la misma tabla, en este caso es obligatorio definir al menos un
alias de tabla.
Observar que dentro de la cláusula ON los nombres de columna deben ser nombres
cualificados (llevan delante el nombre de la tabla y un punto).
Las columnas de emparejamiento deben contener la misma clase de datos, las dos
de tipo texto, de tipo fecha etc... los campos numéricos deben ser de tipos similares. Por
ejemplo, se puede combinar campos AutoNumérico y Long puesto que son tipos similares,
sin embargo, no se puede combinar campos de tipo Simple y Doble. Además las columnas
no pueden ser de tipo Memo ni OLE.
comp representa cualquier operador de comparación ( =, <, >, <=, >=, o <> ) y se utiliza
para establecer la condición de emparejamiento.
SELECT *
FROM pedidos INNER JOIN productos ON (pedidos.fab = productos.idfab) AND
(pedidos.producto = productos.idproducto)
Por ejemplo:
SELECT *
FROM (pedidos INNER JOIN clientes ON pedidos.clie = clientes.numclie) INNER JOIN
empleados ON pedidos.rep = empleados.numemp
En vez de tabla1 hemos escrito un INNER JOIN completo, también podemos escribir:
SELECT *
FROM clientes INNER JOIN (pedidos INNER JOIN empleados ON pedidos.rep =
empleados.numemp) ON pedidos.clie = clientes.numclie
Las composiciones vistas hasta ahora (el producto cartesiano y el INNER JOIN) son
composiciones internas ya que todos los valores de las filas del resultado son valores que
están en las tablas que se combinan.
Con una composición interna sólo se obtienen las filas que tienen al menos una fila de la
otra tabla que cumpla la condición, veamos un ejemplo:
Queremos combinar los empleados con las oficinas para saber la ciudad de la oficina
donde trabaja cada empleado, si utilizamos un producto cartesiano tenemos:
SELECT empleados.*,ciudad
FROM empleados, oficinas
WHERE empleados.oficina = oficinas.oficina
Observar que hemos cualificado el nombre de columna oficina ya que ese nombre aparece
en las dos tablas de la FROM.
Con esta sentencia los empleados que no tienen una oficina asignada (un valor nulo en
el campo oficina de la tabla empleados) no aparecen en el resultado ya que la condición
empleados.oficina = oficinas.oficina será siempre nula para esos empleados.
Nos pasa lo mismo, el empleado 110 tiene un valor nulo en el campo oficina y no
aparecerá en el resultado.
Pues en los casos en que queremos que también aparezcan las filas que no tienen
una fila coincidente en la otra tabla, utilizaremos el LEFT o RIGHT JOIN.
La descripción de la sintaxis es la misma que la del INNER JOIN (ver página anterior), lo
único que cambia es la palabra INNER por LEFT (izquierda en inglés).
Esta operación consiste en añadir al resultado del INNER JOIN las filas de la tabla de
la izquierda que no tienen correspondencia en la otra tabla, y rellenar en esas filas los
campos de la tabla de la derecha con valores nulos.
Ejemplo:
SELECT *
FROM empleados LEFT JOIN oficinas ON empleados.oficina = oficinas.oficina
Con el ejemplo anterior obtenemos una lista de los empleados con los datos de su
oficina, y el empleado 110 que no tiene oficina aparece con sus datos normales y los datos
de su oficina a nulos.
La sintaxis del RIGHT JOIN es la siguiente:
La sintaxis es la misma que la del INNER JOIN (ver página anterior), lo único que cambia
es la palabra INNER por RIGHT (derecha en inglés).
Esta operación consiste en añadir al resultado del INNER JOIN las filas de la tabla de
la derecha que no tienen correspondencia en la otra tabla, y rellenar en esas filas los
campos de la tabla de la izquierda con valores nulos.
Ejemplo:
SELECT *
FROM empleados RIGHT JOIN oficinas ON empleados.oficina = oficinas.oficina
Con el ejemplo anterior obtenemos una lista de los empleados con los datos de su oficina, y
además aparece una fila por cada oficina que no está asignada a ningún empleado con los
datos del empleado a nulos.
Una operación LEFT JOIN o RIGHT JOIN se puede anidar dentro de una operación
INNER JOIN, pero una operación INNER JOIN no se puede anidar dentro de LEFT JOIN o
RIGHT JOIN. Los anidamientos de JOIN de distinta naturaleza no funcionan siempre, a
veces depende del orden en que colocamos las tablas, en estos casos lo mejor es probar y
si no permite el anudamiento, cambiar el orden de las tablas ( y por tanto de los JOINs)
dentro de la cláusula FROM.
SELECT *
FROM clientes INNER JOIN (empleados LEFT JOIN oficinas ON empleados.oficina =
oficinas.oficina) ON clientes.repclie = empleados.numclie
Combinamos empleados con oficinas para obtener los datos de la oficina de cada
empleado, y luego añadimos los clientes de cada representante, así obtenemos los clientes
que tienen un representante asignado y los datos de la oficina del representante asignado.
Si hubiéramos puesto INNER en vez de LEFT no saldrían los clientes que tienen el
empleado 110 (porque no tiene oficina y por tanto no aparece en el resultado del LEFT
JOIN y por tanto no entrará en el cálculo del INNER JOIN con clientes).
Para resumir hemos llamado T1 y T2 las tablas de las que queremos sacar los datos y R
la tabla lógica que representa el resultado de consulta. T1 y T2 podrían ser tablas
guardadas o consultas.
En la última parte cuando se pregunta "En T1 hay filas que no tienen pareja en T2", la
pregunta se debe de interpretar como "en alguna de las tablas hay filas que no tienen
pareja".
EJERCICIOS PROUESTOS
1 Listar las oficinas del este indicando para cada una de ellas su número, ciudad,
números y nombres de sus empleados. Hacer una versión en la que aparecen sólo las que
tienen empleados, y hacer otra en las que aparezcan las oficinas del este que no tienen
empleados.
2 Listar los pedidos mostrando su número, importe, nombre del cliente, y el límite de
crédito del cliente correspondiente (todos los pedidos tienen cliente y representante).
3 Listar los datos de cada uno de los empleados, la ciudad y región en donde trabaja.
4 Listar las oficinas con objetivo superior a 600.000 pts indicando para cada una de ellas
el nombre de su director.
5 Listar los pedidos superiores a 25.000 pts, incluyendo el nombre del empleado que
tomó el pedido y el nombre del cliente que lo solicitó.
6 Hallar los empleados que realizaron su primer pedido el mismo día en que fueron
contratados.
7 Listar los empleados con una cuota superior a la de su jefe; para cada empleado sacar
sus datos y el número, nombre y cuota de su jefe.
8 Listar los códigos de los empleados que tienen una línea de pedido superior a 10.000
ptas o que tengan una cuota inferior a 10.000 pts.
SOLUCION
Ejercicio 1
SELECT oficinas.oficina, ciudad, Como la columna de emparejamiento
numemp, nombre oficinas.oficina es clave principal en la tabla
FROM oficinas INNER JOIN oficinas, es mejor utilizar el JOIN que un
empleados ON oficinas.oficina = producto cartesiano. Emparejamos las dos
empleados.oficina tablas por el campo oficina. Las oficinas que no
WHERE region = 'este' tengan empleados no salen (es un INNER).
Ejercicio 2
SELECT numpedido, importe, En este ejercicio no pueden haber pedidos sin
clientes.nombre AS cliente, cliente, y lo que nos interesa son los pedidos,
limitecredito luego tampoco tienen que aparecer los clientes
FROM pedidos INNER JOIN clientes que no tienen pedidos, por lo tanto utilizamos un
ON pedidos.clie = clientes.numclie INNER JOIN.
Ejercicio 3
SELECT empleados.*, ciudad, Aquí hemos utilizado LEFT JOIN para que
region también salgan los empleados que no tienen
FROM empleados LEFT JOIN oficina asignada.
oficinas ON empleados.oficina = Como queremos todos los datos del empleado
oficinas.oficina utilizamos empleados.* para acortar.
Ejercicio 4
SELECT oficinas.*, nombre AS Nos interesan las oficinas con objetivo superior
director a 600.000pts. luego nos tenemos que asegurar
FROM empleados RIGHT JOIN que salgan todas incluso si no tienen director
oficinas ON empleados.oficina = asignado por eso utilizamos RIGHT JOIN.
oficinas.oficina En los valores numéricos no utilizar el punto
WHERE objetivo > 600000 para separar los miles (lo consideraría coma
decimal y entendería 600 en vez de 600000).
Ejercicio 5
SELECT numpedido, importe, En este ejercicio no pueden haber pedidos sin
empleados.nombre AS representante ni cliente, y lo que nos interesa
representante, clientes.nombre AS son los pedidos, luego tampoco tienen que
cliente aparecer los representantes que no tienen
FROM (pedidos INNER JOIN clientes pedidos ni los clientes que no tienen pedidos,
ON pedidos.clie = clientes.numclie) por lo tanto utilizamos un INNER JOIN.
INNER JOIN empleados ON
pedidos.rep = empleados.numemp Primero añadimos a cada línea de pedido los
WHERE importe > 25000 datos del cliente corespondiente (con el primer
INNER) y a cada fila resultante añadimos los
datos del representante correspondiente.
Ejercicio 7
SELECT empleados.*, jefes.numemp En una misma línea necesito los datos del
AS num_jefe, jefes.nombre AS empleado y los datos de su jefe, luego tengo
nombre_jefe, jefes.cuota AS que combinar empleados con empleados. No
cuota_jefe interesan los empleados que no tienen jefe
FROM empleados INNER JOIN luego utilizo INNER. El alias de tabla es
empleados jefes ON empleados.jefe obligatorio ya que combino empleados con la
= jefes.numemp misma.
WHERE empleados.cuota >
jefes.cuota
Ejercicio 8
SELECT numemp Una posible solución es combinar pedidos con
FROM empleados LEFT JOIN empleados para poder seleccionar las líneas de
pedidos ON pedidos.rep = importe > 10000 o cuota < 10000. Hay que
empleados.numemp utilizar LEFT para que puedan aparecer
WHERE importe > 10000 OR cuota < empleados con cuota < 10000 que no tengan
10000 pedidos.
SELECT rep Esta es otra solución, obtener por una parte los
FROM pedidos códigos de los empleados con una línea de
WHERE importe > 10000 pedido > 10000, por otra parte los códigos de
UNION los empleados con cuota < 10000 y finalmente
SELECT numemp unir las dos listas con una UNION.
FROM empleados
WHERE cuota < 10000
Principio del formulario
Tema 4. Las consultas de resumen
(I) Búsqueda
Introducción
Es importante entender que las filas del resultado de una consulta de resumen tienen una
naturaleza distinta a las filas de las demás tablas resultantes de consultas, ya que
corresponden a varias filas de la tabla orgen. Para simplificar, veamos el caso de una
consulta basada en una sola tabla, una fila de una consulta 'no resumen' corresponde a una
fila de la tabla origen, contiene datos que se encuentran en una sola fila del origen, mientras
que una fila de una consulta de resumen corresponde a un resumen de varias filas de
la tabla origen, esta diferencia es lo que va a originar una serie de restricciones que sufren
las consultas de resumen y que veremos a lo largo del tema.
Funciones de columna
En la lista de selección de una consulta de resumen aparecen funciones de columna
también denominadas funciones de dominio agregadas. Una función de columna se aplica
a una columna y obtiene un valor que resume el contenido de la columna.
El argumento de la función indica con qué valores se tiene que operar, por eso
expresión suele ser un nombre de columna, columna que contiene los valores a resumir,
pero también puede ser cualquier expresión válida que devuelva una lista de valores.
La función SUM() calcula la suma de los valores indicados en el argumento. Los datos
que se suman deben ser de tipo numérico (entero, decimal, coma flotante o monetario...).
El resultado será del mismo tipo aunque puede tener una precisión mayor.
Ejemplo:
SELECT Obtiene una sola fila con el resultado de sumar todos los valores
SUM(ventas) de la columna ventas de la tabla oficinas.
FROM oficinas
La función AVG() calcula el promedio (la media arimética) de los valores indicados en
el argumento, también se aplica a datos numéricos, y en este caso el tipo de dato del
resultado puede cambiar según las necesidades del sistema para representar el valor del
resultado.
Con esta otra SELECT AVG(col1) devuelve: En este caso los ceros
tabla: AS media se han sustituido por
FROM tabla2 valores nulos y no
entran en el cálculo por
lo que la media sale
igual a 6
(10+5+3+6)/4 = 4
Ejemplo:
¿Cuántos empleados tenemos?
SELECT COUNT(numemp)
FROM empleados
o bien
SELECT COUNT(*)
FROM empleados
En este caso las dos sentencias devuelen el mismo resultado ya que la columna numemp
no contiene valores nulos (es la clave principal de la tabla empleados).
SELECT COUNT(oficina)
FROM empleados
Esta sentencia por el contrario, nos devuelve el número de valores no nulos que se
encuentran en la columna oficina de la tabla empleados, por lo tanto nos dice cuántos
empleados tienen una oficina asignada.
SELECT SUM(ventas)
FROM empleados
WHERE oficina = 12
Origen múltiple.
Si los datos que necesitamos utilizar para obtener nuestro resumen se encuentran en
varias tablas, formamos el origen de datos adecuado en la cláusula FROM como si fuera
una consulta multitabla normal.
Ejemplo: Queremos obtener el importe total de ventas de todos los empleados y el mayor
objetivo de las oficinas asignadas a los empleados:
NOTA: combinamos empleados con oficinas por un LEFT JOIN para que aparezcan en el
origen de datos todos los empleados incluso los que no tengan una oficina asignada, así el
origen de datos estará formado por una tabla con tantas filas como empleados hayan en la
tabla empleados, con los datos de cada empleado y de la oficina a la que está asignado. De
esta tabla sacamos la suma del campo ventas (importe total de ventas de todos los
empleados) y el objetivo máximo. Observar que el origen de datos no incluye las oficinas
que no tienen empleados asignados, por lo que esas oficinas no entran a la hora de calcular
el valor máximo del objetivo.
Principio del formulario
Tema 4. Las consultas de
resumen (II) Búsqueda
La cláusula GROUP BY
Hasta ahora las consultas de resumen que hemos visto utilizan todas las filas de la tabla
y producen una única fila resultado.
Se pueden obtener subtotales con la cláusula GROUP BY. Una consulta con una
cláusula GROUP BY se denomina consulta agrupada ya que agrupa los datos de la tabla
origen y produce una única fila resumen por cada grupo formado. Las columnas
indicadas en el GROUP BY se llaman columnas de agrupación.
Ejemplo:
SELECT SUM(ventas) Se forma un grupo para cada oficina, con las filas de la oficina,
FROM repventas y la suma se calcula sobre las filas de cada grupo. El ejemplo
GROUP BY oficina anterior obtiene una lista con la suma de las ventas de los
empleados de cada oficina.
La consulta quedaría mejor incluyendo en la lista de selección la oficina para saber a qué
oficina corresponde la suma de ventas:
SELECT oficina,SUM(ventas)
FROM repventas
GROUP BY oficina
Ejemplo:
Se pueden agrupar las filas por varias columnas, en este caso se indican las
columnas separadas por una coma y en el orden de mayor a menor agrupación. Se
permite incluir en la lista de agrupación hasta 10 columnas.
Ejemplo: Queremos obtener la suma de las ventas de las oficinas agrupadas por region y
ciudad:
SELECT SUM(ventas)
FROM oficinas
GROUP BY region,ciudad
Todas las filas que tienen valor nulo en el campo de agrupación, pasan a formar un
único grupo. Es decir, considera el valor nulo como un valor cualquiera a efectos de
agrupación.
Ejemplo:
En el resultado aparece una fila con el campo oficina sin valor y a continuación una
cantidad en el campo ventas_totales, esta cantidad corresponde a la suma de las ventas de
los empleados que no tienen oficina asignada (campo oficina igual a nulo).
La cláusula HAVING
Ejemplo: Queremos saber las oficinas con un promedio de ventas de sus empleados
mayor que 500.000 ptas.
SELECT oficina
FROM empleados
GROUP BY oficina
HAVING AVG(ventas) > 500000
NOTA: Para obtener lo que se pide hay que calcular el promedio de ventas de los
empleados de cada oficina, por lo que hay que utilizar la tabla empleados.Tenemos que
agrupar los empleados por oficina y calcular el promedio para cada oficina, por último nos
queda seleccionar del resultado las filas que tengan un promedio superior a 500.000 ptas.
Resumen del tema
4 ¿Cuál es el importe total de los pedidos realizados por el empleado Vicente Pantalla?
5 Hallar en qué fecha se realizó el primer pedido (suponiendo que en la tabla de pedidos
tenemos todos los pedidos realizados hasta la fecha).
7 Listar cuántos empleados están asignados a cada oficina, indicar el número de oficina y
cuántos hay asignados.
8 Para cada empleado, obtener su número, nombre, e importe vendido por ese empleado
a cada cliente indicando el número de cliente.
9 Para cada empleado cuyos pedidos suman más de 30.000 ptas, hallar su importe
medio de pedidos. En el resultado indicar el número de empleado y su importe medio de
pedidos.
10 Listar de cada producto, su descripción, precio y cantidad total pedida, incluyendo sólo
los productos cuya cantidad total pedida sea superior al 75% del stock; y ordenado por
cantidad total pedida.
11 Saber cuántas oficinas tienen empleados con ventas superiores a su cuota, no
queremos saber cuales sino cuántas hay.
SOLUCION
Solución ejercicios tema 4. Las consultas de resumen
Ejercicio 1
SELECT AVG(cuota) AS Sale una única fila con el resultado deseado.
cuota_media, AVG(ventas) AS Siempre que se utilicen expresiones o funciones
ventas_media en la lista de selección, queda mejor utilizar un
FROM empleados alias de columna para que ese aparezca en el
encabezado del resultado.
Ejercicio 2
SELECT AVG(importe) AS El precio medio de venta es la media aritmética
importe_medio, SUM(importe) AS de los precios unitarios de cada pedido. El
importe_total, AVG(importe/cant) AS precio unitario se calcula dividiendo el importe
precio_venta_medio del pedido por la cantidad del pedido:
FROM pedidos importe/cant, por lo que ponemos
AVG(importe/cant).
Ejercicio 3
SELECT AVG(precio) AS Ahora no nos interesan todos los productos sino
p_medio_ACI unicamente los del fabricante ACI, por lo que
FROM productos añadimos la cláusula WHERE para que antes
WHERE idfab = 'ACI' de calcular la media, elimine del origen de datos
los registros que no cumplan la condición.
Ejercicio 4
SELECT SUM(importe) AS El importe total lo tenemos que sacar de la tabla
total_pedidos_V_Pantalla de pedidos, y además sólo nos interesan los de
FROM empleados INNER JOIN Vicente Pantalla. Como nos dan el nombre del
pedidos ON empleados.numemp = representante en vez de su número y en el
pedidos.rep pedido sólo tenemos el número de
WHERE nombre = 'Vicente Pantalla' representante tenemos que añadir a las líneas
de cada pedido, los datos del representante
correspondiente, por lo que el origen de datos
debe ser el que aparece en la FROM.
Ejercicio 5
SELECT MIN(fechapedido) AS La fecha del primer pedido es la fecha más
primer_pedido antigua de la tabla de pedidos.
FROM pedidos
Ejercicio 6
SELECT COUNT(*) AS Se podía haber utilizado también
cuantos_pedidos_mayores COUNT(numpedido) o cualquier nombre de
FROM pedidos columna que no pueda contener valores nulos,
WHERE importe > 25000 pero COUNT(*) es mejor por ser más rápido (la
diferencia se nota con tablas muy voluminosas).
Ejercicio 7
SELECT oficina, COUNT(*) AS Con esta solución obtenemos el listado pedido
cuantos_empleados pero no aparecen las oficinas que no tienen
FROM empleados empleados asignados ya que sacamos la
GROUP BY oficina información de la tabla empleados y aparece
una fila con valor nulo en oficina que contiene el
número de empleados que no tienen oficina. Si
quisieramos listar incluso las que no tengan
empleados habría que recurrir a la solución 2
Ejercicio 9
SELECT rep, AVG(importe) AS No queremos todos los empleados, unicamente
importe_medio los que tengan un importe total pedido superior
FROM pedidos a 30.000, luego tenemos que poner la condición
GROUP BY rep SUM(importe) > 30000. Como esta condición
HAVING SUM(importe) > 30000 contiene una función de columna (SUM()) se
tiene que poner en la cláusula HAVING ya que
selecciona filas de la tabla resultante no del
origen de datos.
Ejercicio 10
SELECT descripcion, precio, La agrupación básica es por idfab e idproducto
SUM(importe) AS total_pedido ya que son los dos campos que conjuntamente
FROM productos INNER JOIN identifican un producto.
pedidos ON pedidos.fab = Como descripción y precio aparecen en la lista
productos.idfab AND de selección y no modifican la agrupación
pedidos.producto = básica los incluimos en el GROUP BY.
productos.idproducto
GROUP BY idfab, idproducto, Como existencias aparece en el HAVING y no
descripcion, precio, existencias modifica la agrupación básica lo incluimos
HAVING SUM(importe) > existencias también el el GROUP BY.
* 0.75
ORDER BY 3 Para calcular el 75% de las existencias
multiplicamos existencias por 0,75; observar
que en la sentencia SQL hay que utilizar el
punto para indicar los decimales.
Definiciones
Una subconsulta es una sentencia SELECT que aparece dentro de otra sentencia
SELECT que llamaremos consulta principal.
Una subconsulta tiene la misma sintaxis que una sentencia SELECT normal
exceptuando que aparece encerrada entre paréntesis, no puede contener la cláusula
ORDER BY, ni puede ser la UNION de varias sentencias SELECT, además tiene algunas
restricciones en cuanto a número de columnas según el lugar donde aparece en la
consulta principal. Estas restricciones las iremos describiendo en cada caso.
Las consultas que utilizan subconsultas suelen ser más fáciles de interpretar por el
usuario.
Referencias externas
A menudo, es necesario, dentro del cuerpo de una subconsulta, hacer referencia al valor
de una columna en la fila actual de la consulta principal, ese nombre de columna se
denomina referencia externa.
Una referencia externa es un nombre de columna que estando en la subconsulta, no se
refiere a ninguna columna de las tablas designadas en la FROM de la subconsulta sino a
una columna de las tablas designadas en la FROM de la consulta principal. Como la
subconsulta se ejecuta por cada fila de la consulta principal, el valor de la referencia
externa irá cambiando.
Ejemplo:
Ejemplo:
En este ejemplo, por cada linea de pedido se calcula la subconsulta de clientes, y esto
se repite por cada empleado, en el caso de tener 10 filas de empleados y 200 filas de
pedidos (tablas realmente pequeñas), la subconsulta más interna se ejecutaría 2000 veces
(10 x 200).
Subconsulta en la lista de selección
Cuando la subconsulta aparece en la lista de selección de la consulta principal, en
este caso la subconsulta, no puede devolver varias filas ni varias columnas, de lo
contrario se da un mensaje de error.
Ejemplo:
En este ejemplo listamos el número y nombre de los empleados cuya fecha de contrato
sea igual a la primera fecha de todos los pedidos de la empresa.
Las condiciones de selección son las condiciones que pueden aparecer en la cláusula
WHERE o HAVING. La mayoría se han visto en el tema 2 pero ahora incluiremos las
condiciones que utilizan una subconsulta como operando.
En todos los tests estudiados a continuación expresion puede ser cualquier nombre de
columna de la consulta principal o una expresión válida como ya vimos en el tema 2.
La sintaxis es la siguiente:
SELECT oficina, ciudad Lista las oficinas cuyo objetivo sea superior a la
FROM oficinas suma de las ventas de sus empleados.
WHERE objetivo > (SELECT En este caso la subconsulta devuelve una única
SUM(ventas) FROM empleados columna y una única fila (es un consulta de
WHERE empleados.oficina = resumen sin GROUP BY)
oficinas.oficina)
Este test es una extensión del test de comparación y del test de conjunto. Compara el
valor de la expresión con cada uno de los valores producidos por la subconsulta. La
subconsulta debe devolver una única columna sino se produce un error.
Tenemos el test ANY (algún, alguno en inglés) y el test ALL (todos en inglés).
La sintaxis es la siguiente:
El test ANY.
El test ALL.
SELECT oficina, ciudad En este caso se listan las oficinas cuyo objetivo
FROM oficinas sea superior a todas las sumas.
WHERE objetivo > ALL (SELECT
SUM(cuota) FROM empleados
GROUP BY oficina)
La sintaxis es la siguiente:
NOTA. Cuando se trabaja con tablas muy voluminosas el test EXISTS suele dar mejor
rendimiento que el test IN.
Dentro de una consulta se puede utilizar una columna del origen de la consulta
principal, una referencia externa.
el test ANY
el test ALL
el test IN
el test EXISTS
EJERCICIOS PROPUESTOS
Ejercicios tema 5. Las subconsultas
1 Listar los nombres de los clientes que tienen asignado el representante Alvaro Jaumes
(suponiendo que no pueden haber representantes con el mismo nombre).
3 Listar los vendedores que no trabajan en oficinas dirigidas por el empleado 108.
4 Listar los productos (idfab, idproducto y descripción) para los cuales no se ha recibido
ningún pedido de 25000 o más.
5 Listar los clientes asignados a Ana Bustamante que no han remitido un pedido
superior a 3000 pts.
6 Listar las oficinas en donde haya un vendedor cuyas ventas representen más del 55%
del objetivo de su oficina.
7 Listar las oficinas en donde todos los vendedores tienen ventas que superan al 50%
del objetivo de la oficina.
8 Listar las oficinas que tengan un objetivo mayor que la suma de las cuotas de sus
vendedores.
SELECT numemp, nombre, oficina Con esta solución tenemos el mismo problema
FROM empleados que con NOT IN , cuando la oficina del
WHERE oficina <> ALL ( SELECT empleado es nula todos los resultados de las
oficina FROM oficinas WHERE dir = comparaciones individuales son nulos por los
108); que el test ALL da nulo y no se seleccionan los
empleados con oficina nula.
Ejercicio 4
SELECT idfab, idproducto, En este caso es más cómodo utilizar NOT
descripcion EXISTS ya que hay que preguntar por el idfab e
FROM productos idproducto a la vez.
WHERE NOT EXISTS (SELECT *
FROM pedidos WHERE fab = idfab
AND producto = idproducto AND
importe >= 25000);
Ejercicio 5
SELECT numclie, nombre
FROM clientes
WHERE repclie IN ( SELECT
numemp FROM empleados WHERE
nombre = 'Ana Bustamante' )
AND numclie NOT IN ( SELECT clie
FROM pedidos WHERE importe >
3000);
Ejercicio 6
SELECT * En una subconsulta todos los campos no
FROM oficinas cualificados se presuponen de la tabla origen de
WHERE EXISTS ( SELECT * FROM la subconsulta y sólo si no existe ninguna
empleados WHERE ventas > columna con ese nombre, la considera como
objetivo * 0.55); referencia externa, por eso no es necesario
cualificar ventas porque interpreta que es el
campo ventas de la tabla empleados.
Ejercicio 7
SELECT * Esta solución no vale porque salen las oficinas
FROM oficinas que no tienen empleados.
WHERE (objetivo * 0.5) <= ALL Hay que añadir una condición para que se
( SELECT ventas FROM empleados consideren sólo las oficinas con empleados
WHERE empleados.oficina = como muestra la solución 1.
oficinas.oficina );
Solución 1
SELECT *
FROM oficinas
WHERE ((objetivo * 0.5) <= ALL
( SELECT ventas FROM empleados
WHERE empleados.oficina =
oficinas.oficina ) )
AND ( EXISTS ( SELECT * FROM
empleados WHERE
empleados.oficina = oficinas.oficina
) );
Introducción
Hasta ahora hemos estudiado el cómo recuperar datos almacenados en las tablas de
nuestra base de datos. En este tema vamos a tratar el de la actualización de esos datos,
es decir insertar nuevas filas, borrar filas o cambiar el contenido de las filas de una
tabla. Estas operaciones modifican los datos almacenados en las tablas pero no su
estructura, ni su definición.
Empezaremos por ver cómo insertar nuevas filas (con la sentencia INSERT INTO),
veremos una variante (la sentencia SELECT... INTO), después veremos cómo borrar filas
de una tabla (con la sentencia DELETE) y por último cómo modificar el contenido de las
filas de una tabla (con la sentencia UPDATE). Si trabajamos en un entorno multiusuario,
todas estas operaciones se podrán realizar siempre que tengamos los permisos
correspondientes.
La sintaxis es la siguiente:
Esta sintaxis se utiliza para insertar una sola fila cuyos valores indicamos después de la
palabra reservada VALUES. En castellano la sentencia se leería: INSERTA EN
destino...VALORES ....
Cuando no se indica ninguna lista de columnas después del destino, se asume por
defecto todas las columnas de la tabla, en este caso, los valores se tienen que especificar
en el mismo orden en que aparecen las columnas en la ventana de diseño de dicha
tabla, y se tiene que utilizar el valor NULL para rellenar las columnas de las cuales no
tenemos valores.
Ejemplo:
INSERT INTO empleados VALUES (200, 'Juan López', 30, NULL, 'rep ventas',
#06/23/01#, NULL, 350000, 0)
Observar en el ejemplo que los valores de tipo texto se encierran entre comillas simples '
' (también se pueden emplear las comillas dobles " ") y que la fecha de contrato se encierra
entre almohadillas # # con el formato mes/dia/año. Como no tenemos valor para los campos
oficina y director (a este nuevo empleado todavía no se le ha asignado director ni oficina)
utilizamos la palabra reservada NULL. Los valores numéricos se escriben tal cual, para
separar la parte entera de la parte decimal hay que utilizar siempre el punto
independientemente de la configuración que tengamos.
Observar que ahora hemos variado el orden de los valores y los nombres de columna no
siguen el mismo orden que en la tabla origen, no importa, lo importante es poner los valores
en el mismo orden que las columnas que enunciamos. Como no enunciamos las columnas
oficina y director se rellenarán con el valor nulo (porque es el valor que tienen esas
columnas como valor predeterminado).
El utilizar la opción de poner una lista de columnas podría parecer peor ya que se
tiene que escribir más pero realmente tiene ventajas sobre todo cuando la sentencia la
vamos a almacenar y reutilizar:
la sentencia queda más fácil de interpretar leyéndola vemos qué valor asignamos a qué
columna,
si por lo que sea cambia el orden de las columnas en la tabla en el diseño, no pasaría
nada mientras que de la otra forma intentaría asignar los valores a otra columna, esto
produciría errores de 'tipo no corresponde' y lo que es peor podría asignar valores erróneos
sin que nos demos cuenta,
otra ventaja es que si se añade una nueva columna a la tabla en el diseño, la primera
sentencia INSERT daría error ya que el número de valores no corresponde con el número
de columnas de la tabla, mientras que la segunda INSERT no daría error y en la nueva
columna se insertaría el valor predeterminado.
Si la tabla de destino tiene clave principal y en ese campo intentamos no asignar valor,
asignar el valor nulo o un valor que ya existe en la tabla, el motor de base de datos
Microsoft Jet no añade la fila y da un mensaje de error de ' infracciones de clave'.
Si tenemos definido un índice único (sin duplicados) e intentamos asignar un valor que
ya existe en la tabla también devuelve el mismo error.
Si la tabla está relacionada con otra, se seguirán las reglas de integridad referencial.
Aquí puedes repasar las reglas de integridad referencial.
Tipos de
relaciones.
Entre dos tablas de cualquier base de datos relacional pueden haber dos tipos de
relaciones, relaciones uno a uno y relaciones uno a muchos:
Relación Uno a Uno: Cuando un registro de una tabla sólo puede estar
relacionado con un único registro de la otra tabla y viceversa.
Por ejemplo: tenemos dos tablas una de profesores y otra de departamentos y queremos
saber qué profesor es jefe de qué departamento, tenemos una relación uno a uno entre las
dos tablas ya que un departamento tiene un solo jefe y un profesor puede ser jefe de un
solo departamento.
Relación Uno a Varios: Cuando un registro de una tabla (tabla secundaria) sólo
puede estar relacionado con un único registro de la otra tabla (tabla principal) y un
registro de la tabla principal puede tener más de un registro relacionado en la tabla
secundaria, en este caso se suele hacer referencia a la tabla principal como tabla 'padre' y
a la tabla secundaria como tabla 'hijo', entonces la regla se convierte en 'un padre puede
tener varios hijos pero un hijo solo tiene un padre (regla más fácil de recordar).
Por ejemplo: tenemos dos tablas una con los datos de diferentes poblaciones y otra con
los habitantes, una población puede tener más de un habitante, pero un habitante
pertenecerá (estará empadronado) en una única población. En este caso la tabla principal
será la de poblaciones y la tabla secundaria será la de habitantes. Una población puede
tener varios habitantes pero un habitante pertenece a una sola población. Esta relación se
representa incluyendo en la tabla 'hijo' una columna que se corresponde con la clave
principal de la tabla 'padre', esta columna es lo denominamos clave foránea (o clave ajena o
clave externa).
Una clave foránea es pues un campo de una tabla que contiene una referencia a un
registro de otra tabla. Siguiendo nuestro ejemplo en la tabla habitantes tenemos una
columna población que contiene el código de la población en la que está empadronado el
habitante, esta columna es clave ajena de la tabla habitantes, y en la tabla poblaciones
tenemos una columna codigo de poblacion clave principal de la tabla.
Por ejemplo: tenemos dos tablas una con los datos de clientes y otra con los artículos
que se venden en la empresa, un cliente podrá realizar un pedido con varios artículos, y un
artículo podrá ser vendido a más de un cliente.
No se puede definir entre clientes y artículos, hace falta otra tabla (por ejemplo una tabla
de pedidos) relacionada con clientes y con artículos. La tabla pedidos estará relacionada
con cliente por una relación uno a muchos y también estará relacionada con artículos por
un relación uno a muchos.
Integridad referencial
Cuando se define una columna como clave foránea, las filas de la tabla pueden contener
en esa columna o bien el valor nulo (ningún valor), o bien un valor que existe en la otra
tabla, un error sería asignar a un habitante una población que no está en la tabla de
poblaciones. Eso es lo que se denomina integridad referencial y consiste en que los
datos que referencian otros (claves foráneas) deben ser correctos. La integridad
referencial hace que el sistema gestor de la base de datos se asegure de que no hayan en
las claves foráneas valores que no estén en la tabla principal.
Cuando queremos borrar una fila de la tabla principal y ese registro tiene 'hijos',
por ejemplo queremos borrar la población 1 (Valencia) si existen habitantes asignados a la
población 1, estos no se pueden quedar con el valor 1 en la columna población porque
tendrían asignada una población que no existe. En este caso tenemos dos alternativas, no
dejar borrar la población 1 de la tabla de poblaciones, o bien borrarla y poner a valor nulo el
campo poblacion de todos sus 'hijos'.
Actualización y borrado en
cascada
El actualizar y/o eliminar registros en cascada, son opciones que se definen cuando
definimos la clave foránea y que le indican al sistema gestor qué hacer en los casos
comentados en el punto anterior
Esta opción le indica al sistema gestor de la base de datos que cuando se cambie un
valor del campo clave de la tabla principal, automáticamente cambiará el valor de la
clave foránea de los registros relacionados en la tabla secundaria.
Por ejemplo, si cambiamos en la tabla de poblaciones (la tabla principal) el valor 1 por el
valor 10 en el campo codigo (la clave principal), automáticamente se actualizan todos los
habitantes (en la tabla secundaria) que tienen el valor 1 en el campo poblacion (en la clave
ajena) dejando 10 en vez de 1.
Si no se tiene definida esta opción, no se puede cambiar los valores de la clave principal
de la tabla principal. En este caso, si intentamos cambiar el valor 1 del codigo de la tabla de
poblaciones , no se produce el cambio y el sistema nos devuelve un error o un mensaje que
los registros no se han podido modificar por infracciones de clave.
Esta opción le indica al sistema gestor de la base de datos que cuando se elimina un
registro de la tabla principal automáticamente se borran también los registros
relacionados en la tabla secundaria.
Podemos insertar en una tabla varias filas con una sola sentencia SELECT INTO si los
valores a insertar se pueden obtener como resultado de una consulta, en este caso
sustituimos la cláusula VALUES lista de valores por una sentencia SELECT como las que
hemos visto hasta ahora. Cada fila resultado de la SELECT forma una lista de valores
que son los que se insertan en una nueva fila de la tabla destino. Es como si tuviesemos
una INSERT...VALUES por cada fila resultado de la sentencia SELECT.
La sintaxis es la siguiente:
Ejemplo: Supongamos que tenemos una tabla llamada repres con la misma estructura
que la tabla empleados, y queremos insertar en esa tabla los empleados que tengan como
titulo rep ventas
INSERT INTO repres SELECT * FROM empleados WHERE titulo = 'rep ventas'
Con la SELECT obtenemos las filas correspondientes a los empleados con título rep
ventas,y las insertamos en la tabla repres. Como las tablas tienen la misma estructura no
hace falta poner la lista de columnas y podemos emplear * en la lista de selección de la
SELECT.
Ejemplo: Supongamos ahora que la tabla repres tuviese las siguientes columnas
numemp, oficinarep, nombrerep. En este caso no podríamos utilizar el asterisco,
tendríamos que poner:
INSERT INTO repres SELECT numemp, oficina, nombre FROM empleados WHERE
titulo = 'rep ventas'
O bien:
INSERT INTO repres (numemp, oficinarep, nombrerep) SELECT numemp, oficina,
nombre FROM empleados WHERE titulo = 'rep ventas'
Principio del formulario
Tema 6. Actualización de
datos (III) Búsqueda
Esta sentencia inserta filas creando en ese momento la tabla donde se insertan las
filas. Se suele utilizar para guardar en una tabla el resultado de una SELECT.
La sintaxis es la siguiente:
Las columnas de la nueva tabla tendrán el mismo tipo y tamaño que las columnas
origen, y se llamarán con el nombre de alias de la columna origen o en su defecto con
el nombre de la columna origen, pero no se transfiere ninguna otra propiedad del
campo o de la tabla como por ejemplo las claves e índices.
Ejemplo:
Esta sentencia genera una nueva tabla t2 con todas las filas de la tabla t1. Las columnas
se llamarán igual que en t1 pero t2 no será una copia exacta de t1 ya no tendrá clave
principal ni relaciones con las otras tablas, ni índices si los tuviese t1 etc...
Si en la base de datos hay ya una tabla del mismo nombre, el sistema nos avisa y
nos pregunta si la queremos borrar. Si le contestamos que no, la SELECT no se ejecuta.
Para formar una sentencia SELECT INTO lo mejor es escribir la SELECT que
permite generar los datos que queremos guardar en la nueva tabla, y después añadir
delante de la cláusula FROM la cláusula INTO nuevatabla.
La sentencia SELECT INTO se suele utilizar para crear tablas de trabajo, o tablas
intermedias, las creamos para una determinada tarea y cuando hemos terminado esa tarea
las borramos. También puede ser útil para sacar datos en una tabla para enviarlos a
alguien.
Por ejemplo: Queremos enviarle a un representante una tabla con todos los datos
personales de sus clientes para que les pueda enviar cartas etc...
Vamos a suponer que hemos añadido a nuestra tabla de clientes los campos direccion y
telefono. En el ejemplo anterior la nueva tabla tendrá cuatro columnas llamadas codigo,
nombre, direccion, telefono y contendrá las filas correspondientes a los clientes del
representante 103.
Principio del formulario
Tema 6. Actualización de
datos (IV) Búsqueda
La sentencia UPDATE modifica los valores de una o más columnas en las filas
seleccionadas de una o varias tablas.
La sintaxis es la siguiente:
La cláusula SET especifica qué columnas van a modificarse y qué valores asignar
a esas columnas.
La expresión en cada asignación debe generar un valor del tipo de dato apropiado
para la columna indicada. La expresión debe ser calculable a partir de los valores de la
fila que se está actualizando. Expresión no puede ser una subconsulta.
Ejemplo:
En este ejemplo queremos actualizar las cuotas de nuestros empleados de tal forma que
la cuota de un empleado sea el 1% del objetivo de su oficina. La columna a actualizar es la
cuota del empleado y el valor a asignar es el 1% del objetivo de la oficina del empleado,
luego la cláusula SET será SET cuota = objetivo*0.01 o SET cuota = objetivo/100. El
origen debe contener la cuota del empleado y el objetivo de su oficina, luego el origen será
el INNER JOIN de empleados con oficinas.
La cláusula WHERE indica qué filas van a ser modificadas. Si se omite la cláusula
WHERE se actualizan todas las filas.
En la condición del WHERE se puede incluir una subconsulta. En SQL standard la
tabla que aparece en la FROM de la subconsulta no puede ser la misma que la tabla que
aparece como origen, pero en el SQL de Microsoft Jet sí se puede.
Si para el cálculo de expresion se utiliza una columna que también se modifica, el valor
que se utiliza es el antes de la modificación, lo mismo para la condición de búsqueda.
Ejemplo:
O bien:
Los dos ejemplos anteriores son equivalentes ya que el valor de ventas que se asigna a
objetivo es el valor antes de la actualización, se deja como objetivo las ventas que ha tenido
la oficina hasta el momento y se pone a cero la columna ventas.
Si actualizamos una columna definida como clave foránea, esta columna se podrá
actualizar o no siguiendo las reglas de integridad referencial. El valor que se le asigna
debe existir en la tabla de referencia.
Tipos de
relaciones.
Entre dos tablas de cualquier base de datos relacional pueden haber dos tipos de
relaciones, relaciones uno a uno y relaciones uno a muchos:
Relación Uno a Uno: Cuando un registro de una tabla sólo puede estar
relacionado con un único registro de la otra tabla y viceversa.
Por ejemplo: tenemos dos tablas una de profesores y otra de departamentos y queremos
saber qué profesor es jefe de qué departamento, tenemos una relación uno a uno entre las
dos tablas ya que un departamento tiene un solo jefe y un profesor puede ser jefe de un
solo departamento.
Relación Uno a Varios: Cuando un registro de una tabla (tabla secundaria) sólo
puede estar relacionado con un único registro de la otra tabla (tabla principal) y un
registro de la tabla principal puede tener más de un registro relacionado en la tabla
secundaria, en este caso se suele hacer referencia a la tabla principal como tabla 'padre' y
a la tabla secundaria como tabla 'hijo', entonces la regla se convierte en 'un padre puede
tener varios hijos pero un hijo solo tiene un padre (regla más fácil de recordar).
Por ejemplo: tenemos dos tablas una con los datos de diferentes poblaciones y otra con
los habitantes, una población puede tener más de un habitante, pero un habitante
pertenecerá (estará empadronado) en una única población. En este caso la tabla principal
será la de poblaciones y la tabla secundaria será la de habitantes. Una población puede
tener varios habitantes pero un habitante pertenece a una sola población. Esta relación se
representa incluyendo en la tabla 'hijo' una columna que se corresponde con la clave
principal de la tabla 'padre', esta columna es lo denominamos clave foránea (o clave ajena o
clave externa).
Una clave foránea es pues un campo de una tabla que contiene una referencia a un
registro de otra tabla. Siguiendo nuestro ejemplo en la tabla habitantes tenemos una
columna población que contiene el código de la población en la que está empadronado el
habitante, esta columna es clave ajena de la tabla habitantes, y en la tabla poblaciones
tenemos una columna codigo de poblacion clave principal de la tabla.
Por ejemplo: tenemos dos tablas una con los datos de clientes y otra con los artículos
que se venden en la empresa, un cliente podrá realizar un pedido con varios artículos, y un
artículo podrá ser vendido a más de un cliente.
No se puede definir entre clientes y artículos, hace falta otra tabla (por ejemplo una tabla
de pedidos) relacionada con clientes y con artículos. La tabla pedidos estará relacionada
con cliente por una relación uno a muchos y también estará relacionada con artículos por
un relación uno a muchos.
Integridad referencial
Cuando se define una columna como clave foránea, las filas de la tabla pueden contener
en esa columna o bien el valor nulo (ningún valor), o bien un valor que existe en la otra
tabla, un error sería asignar a un habitante una población que no está en la tabla de
poblaciones. Eso es lo que se denomina integridad referencial y consiste en que los
datos que referencian otros (claves foráneas) deben ser correctos. La integridad
referencial hace que el sistema gestor de la base de datos se asegure de que no hayan en
las claves foráneas valores que no estén en la tabla principal.
Cuando queremos borrar una fila de la tabla principal y ese registro tiene 'hijos',
por ejemplo queremos borrar la población 1 (Valencia) si existen habitantes asignados a la
población 1, estos no se pueden quedar con el valor 1 en la columna población porque
tendrían asignada una población que no existe. En este caso tenemos dos alternativas, no
dejar borrar la población 1 de la tabla de poblaciones, o bien borrarla y poner a valor nulo el
campo poblacion de todos sus 'hijos'.
Actualización y borrado en
cascada
El actualizar y/o eliminar registros en cascada, son opciones que se definen cuando
definimos la clave foránea y que le indican al sistema gestor qué hacer en los casos
comentados en el punto anterior
Esta opción le indica al sistema gestor de la base de datos que cuando se cambie un
valor del campo clave de la tabla principal, automáticamente cambiará el valor de la
clave foránea de los registros relacionados en la tabla secundaria.
Por ejemplo, si cambiamos en la tabla de poblaciones (la tabla principal) el valor 1 por el
valor 10 en el campo codigo (la clave principal), automáticamente se actualizan todos los
habitantes (en la tabla secundaria) que tienen el valor 1 en el campo poblacion (en la clave
ajena) dejando 10 en vez de 1.
Si no se tiene definida esta opción, no se puede cambiar los valores de la clave principal
de la tabla principal. En este caso, si intentamos cambiar el valor 1 del codigo de la tabla de
poblaciones , no se produce el cambio y el sistema nos devuelve un error o un mensaje que
los registros no se han podido modificar por infracciones de clave.
Esta opción le indica al sistema gestor de la base de datos que cuando se elimina un
registro de la tabla principal automáticamente se borran también los registros
relacionados en la tabla secundaria.
La sintaxis es la siguiente:
La opción tabla.* se utiliza cuando el origen está basado en varias tablas, y sirve
para indicar en qué tabla vamos a borrar.
La cláusula WHERE sirve para especificar qué filas queremos borrar. Se eliminaran
de la tabla todas las filas que cumplan la condición. Si no se indica la cláusula WHERE,
se borran TODAS las filas de la tabla.
Si la tabla donde borramos está relacionada con otras tablas se podrán borrar o
no los registros siguiendo las reglas de integridad referencial definidas en las relaciones.
Aquí puedes repasar las reglas de integridad referencial.
Ejemplo:
DELETE * FROM pedidos WHERE clie IN (SELECT numclie FROM clientes WHERE
nombre = 'Julian López');
O bien:
Las dos sentencias borran los pedidos del cliente Julian López. En la segunda estamos
obligados a poner pedidos.* porque el origen está basado en varias tablas.
DELETE * FROM pedidos; o DELETE FROM pedidos; Borra todas las filas de pedidos.
Si queremos añadir en una tabla una fila con valores conocidos utilizamos la
sentencia INSERT INTO tabla VALUES (lista de valores).
Para crear una nueva tabla con el resultado de una consulta con la sentencia
SELECT...INTO tabla FROM...
Para cambiar los datos contenidos en una tabla, tenemos que actualizar las filas de
dicha tabla con la sentencia UPDATE tabla SET asignación de nuevos valores.
Para eliminar filas de una tabla se utiliza la sentencia DELETE FROM tabla.
1 Crear una tabla (llamarla nuevaempleados) que contenga las filas de la tabla
empleados.
2 Crear una tabla (llamarla nuevaoficinas) que contenga las filas de la tabla oficinas.
3 Crear una tabla (llamarla nuevaproductos) que contenga las filas de la tabla productos.
4 Crear una tabla (llamarla nuevapedidos) que contenga las filas de la tabla pedidos.
6 Añadir una nueva oficina para la ciudad de Madrid, con el número de oficina 30, con un
objetivo de 100000 y región Centro.
Ejercicio 4
SELECT * INTO nuevapedidos
FROM pedidos;
Ejercicio 5
UPDATE productos También se puede poner precio = precio +
SET precio = precio * 1.05 WHERE precio*0.05
idfab = 'ACI';
Ejercicio 6
Solución 1
Como no asignamos valor a todos los campos,
INSERT INTO oficinas ( oficina, no hace falta poner todas las columnas en la
region, ciudad, objetivo ) lista de columnas. Los campos dir y ventas se
VALUES ( 30, 'centro','Madrid', rellenarán con el valor predeterminado.
100000 );
¡Ojo! Si la tabla oficinas tiene definido en la
columna dir el valor predeterminado 0, al
intentar ejecutar la INSERT ocurrirá un error
porque asigna 0 al campo dir , como dir es clave
ajena, antes de insertar comprueba que el valor
insertado en la clave ajena existe en la tabla
empleados, y el empleado 0 no existe por lo que
no puede insertar la oficina, el valor
predeterminado de dir debe ser nulo.
Ejercicio 8
DELETE FROM pedidos WHERE rep
= 105;
Ejercicio 9
Solución 1 Si la oficina no tiene empleados asignados, no
DELETE FROM oficinas WHERE existe ningún empleado con el número de esa
NOT EXISTS (SELECT * oficina.
FROM empleados WHERE
empleados.oficina =
oficinas.oficina);
Ejercicio 11
INSERT INTO oficinas En este caso insertamos en oficinas las oficinas
SELECT * FROM nuevaoficinas de nuevaoficinas cuyo número de oficina no
WHERE oficina NOT IN (SELECT está en oficinas (es decir las que se han
oficina FROM oficinas); borrado).
Ejercicio 12
INSERT INTO pedidos Insertamos en pedidos los pedidos del
SELECT * from nuevapedidos empleados 105 que se encuentran en la tabla
WHERE rep = 105; nuevapedidos.
Ejercicio 13
UPDATE empleados
SET oficina = 21 WHERE oficina = 30;
Principio del formulario
Tema 7. Tablas de referencias
cruzadas (I) Búsqueda
Introducción
La consulta sería:
La consulta quedaría mucho más elegante y clara presentando los datos en un formato
más compacto como el siguiente:
Pues este último resultado se obtiene mediante una consulta de referencias cruzadas.
Observar que una de las columnas de agrupación (rep) sigue definiendo las filas que
aparecen (hay una fila por cada empleado), mientras que la otra columna de agrupación
(mes) ahora sirve para definir las otras columnas, cada valor de mes define una columna en
el resultado, y la celda en la intersección de un valor de rep y un valor de mes es la
columna resumen, la que contiene la función de columna (la suma de importe).
La sentencia TRANSFORM
La sentencia TRANSFORM es la que se utiliza para definir una consulta de
referencias cruzadas.
La sintaxis es la siguiente:
La SELECT puede contener una cláusula WHERE para seleccionar la filas que se
utilizan para calcular el resultado, puede contener subconsultas pero no la cláusula
HAVING.
TRANSFORM Sum(importe)
SELECT rep as empleado
FROM pedidos
GROUP BY rep
PIVOT month(fechapedido)
Lo mejor para montar una consulta de referencias cruzadas en SQL es pensar la sumaria
normal y luego distribuir los términos según corresponda.
Principio del formulario
Tema 7. Tablas de
referencias cruzadas (II) Búsqueda
Como hemos dicho las columnas dinámicas son las que se generan según los valores
almacenados en la columna pivote (la que aparece en la cláusula PIVOT), normalmente se
genera una columna dinámica por cada valor que se encuentre en la columna pivote del
origen de datos.
Cuando los posibles valores que puede tomar la columna pivote son conocidos y
queremos definir cuales queremos que aparezcan, sólo unos cuantos porque no nos
interesan algunos o todos incluso si no generan resultado, en este caso usaremos la
cláusula IN, en la cláusula IN se ponen entre paréntesis todos los posibles valores, o por lo
menos los que queremos que aparezcan en el resultado.
Por ejemplo sólo nos interesan los meses de febrero, mayo y diciembre:
TRANSFORM Sum(importe)
SELECT rep as empleado
FROM pedidos
GROUP BY rep
PIVOT month(fechapedido) IN (2,5,12);
TRANSFORM
Sum(importe)
SELECT rep as
empleado
FROM pedidos
GROUP BY rep
PIVOT
month(fechapedid
o) IN
(10,11,12,1,2,3,4,5,
6,7,8,9);
Las columnas fijas
Las columnas fijas son las que aparecen delante de las columnas dinámicas y son fijas
porque se genera una sola columna en el resultado por cada columna hayamos indicado en
la lista de columnas fijas. Las columnas fijas se indican en la lista de selección de la
sentencia SELECT, una columna fija que siempre debemos incluir es la que sirve de
encabezado de fila para que podamos saber cada fila a qué valor de encabezado de fila
corresponde. Pero además podemos incluir otras columnas por ejemplo columnas de
resumen de cada fila, sin que se tenga en cuenta la agrupación por la columna pivote.
Por ejemplo queremos saber para cada empleado cuánto ha vendido en total y cuál ha
sido el importe mayor vendido en un pedido.
TRANSFORM
Sum(importe)
AS Suma
SELECT rep AS
empleado,
SUM(importe)
AS [Total
vendido],MAX(i
mporte) AS
mayor
FROM pedidos
GROUP BY rep
PIVOT
month(fechaped
ido) ;
Resumen del tema
La instrucción TRANSFORM se utiliza para definir una consulta de referencias cruzadas.
Permite presentar los resultados de una sumaria en una tabla de doble entrada como la que se presenta a
continuación:
1 Queremos saber de cada empleado sus ventas mensuales del año 1990.
4 Se necesita una estadística de cuántos empleados fueron contratados por año en cada
oficina.
5 Queremos saber por año las ventas realizadas en las distintas regiones.
GROUP BY oficina
PIVOT year(contrato);
Ejercicio 5
TRANSFORM SUM(importe)
GROUP BY YEAR(fechapedido)
PIVOT region;
Principio del formulario
Tema 8. El DDL, lenguaje de
definición de datos (I) Búsqueda
Introducción
Hasta ahora hemos estudiado las sentencias que forman parte del DML (Data
Management Language) lenguaje de manipulación de datos, todas esas sentencias sirven
para recuperar, insertar, borrar, modificar los datos almacenados en la base de datos; lo que
veremos en este tema son las sentencias que afectan a la estructura de los datos.
El DDL (Data Definition Language) lenguaje de definición de datos es la parte del SQL
que más varía de un sistema a otro ya que esa area tiene que ver con cómo se organizan
internamente los datos y eso, cada sistema lo hace de una manera u otra.
Así como el DML de Microsoft Jet incluye todas las sentencias DML que nos podemos
encontrar en otros SQLs (o casi todas), el DDL de Microsoft Jet en cambio contiene menos
instrucciones que otros sistemas.
CREATE TABLE
La sentencia CREATE TABLE sirve para crear la estructura de una tabla no para
rellenarla con datos, nos permite definir las columnas que tiene y ciertas restricciones
que deben cumplir esas columnas.
La sintaxis es la siguiente:
tipo: tipo de dato de la columna, todos los datos almacenados en la columna deberán
ser de ese tipo. Para ver qué tipos de datos se pueden emplear haz clic aquí
Tipos de datos.
Estos son los tipos de datos que soporta el SQL de Microsoft® Jet versión 4.0
Notas:
Si se utiliza el nombre del tipo de datos TEXT sin especificar la longitud opcional
(TEXT(25), por ejemplo), se crea un campo LONGTEXT. Esto permite escribir
instrucciones CREATE TABLE que producirán tipos de datos coherentes con Microsoft
SQL Server.
Los caracteres de los campos definidos como TEXT (también conocidos como MEMO) o
CHAR (también conocidos como TEXT(n) con una longitud específica) se almacenan en el
formato de representación Unicode. Los caracteres Unicode requieren siempre dos bytes
para el almacenamiento de cada carácter. Para las bases de datos de Microsoft Jet ya
existentes que contengan principalmente datos de tipo carácter, esto puede significar que
el tamaño del archivo de base de datos sea casi el doble cuando se convierta al formato
Microsoft Jet 4.0. Sin embargo, la representación Unicode de muchos juegos de
caracteres, antes denominados juegos de caracteres de un solo byte (SBCS), puede
comprimirse fácilmente a caracteres de un solo byte. Si define una columna CHAR con el
atributo COMPRESSION, los datos se comprimirán automáticamente a medida que se
almacenen y se descomprimirán cuando se recuperen de la columna.
Los caracteres Unicode y su compresión.
En ACCESS 2000 se utiliza el formato de representación de caracteres Unicode, los
caracteres Unicode requieren siempre dos bytes para cada carácter lo que permite una
gama más amplia de caracteres.
Para las bases de datos de Microsoft® Jet ya existentes que contengan principalmente
datos de tipo carácter, esto puede significar que el tamaño del archivo de base de datos
sea casi el doble cuando se convierta al formato Microsoft Jet versión 4.0. Sin embargo, la
representación Unicode de muchos juegos de caracteres, antes denominados juegos de
caracteres de un solo byte (SBCS), puede comprimirse fácilmente a caracteres de un solo
byte. Si se define una columna CHARACTER con el atributo WITH COMPRESSION
(propiedad Compresión Unicode), los datos se comprimirán automáticamente cuando se
almacenen y se descomprimirán cuando se recuperen de la columna.
Las columnas MEMO también pueden ser definidas de modo que almacenen datos en
formato comprimido. No obstante, existe una restricción. Sólo se comprimirán las
instancias de columnas MEMO que, tras la compresión, ocupen 4.096 bytes o menos. El
resto de instancias de columnas MEMO quedarán sin comprimir. Esto significa que, dentro
de una tabla determinada, para una columna MEMO dada, algunos datos pueden estar
comprimidos y otros no.
Fuente: Datos extraidos de la ayuda de Microsoft Access2000.
Una restricción consiste en la definición de una característica adicional que tiene una
columna o una combinación de columnas, suelen ser características como valores no nulos
(campo requerido), definición de índice sin duplicados, definición de clave principal y
definición de clave foránea (clave ajena o externa, campo que sirve para relacionar dos
tablas entre sí).
Para escribir una sentencia CREATE TABLE se empieza por indicar el nombre de la
tabla que queremos crear y a continuación entre paréntesis indicamos separadas por
comas las definiciones de cada columna de la tabla, la definición de una columna
consta de su nombre, el tipo de dato que tiene y podemos añadir si queremos una serie
de especificaciones que deberán cumplir los datos almacenados en la columna, después
de definir cada una de las columnas que compone la tabla se pueden añadir una serie de
restricciones, esas restricciones son las mismas que se pueden indicar para cada columna
pero ahora pueden afectar a más de una columna por eso tienen una sintaxis ligeramente
diferente.
Una restricción de tipo 1 se utiliza para indicar una característica de la columna que
estamos definiendo, tiene la siguiente sintaxis:
La cláusula NOT NULL indica que la columna no podrá contener un valor nulo, es
decir que se deberá rellenar obligatoriamente y con un valor válido (equivale a la propiedad
requerido Sí de las propiedades del campo).
La cláusula CONSTRAINT sirve para definir una restricción que se podrá eliminar
cuando queramos sin tener que borrar la columna. A cada restricción se le asigna un
nombre que se utiliza para identificarla y para poder eliminarla cuando se quiera.
Como restricciones tenemos la de clave primaria (clave principal), la de índice único (sin
duplicados), la de valor no nulo, y la de clave foránea.
La cláusula PRIMARY KEY se utiliza para definir la columna como clave principal de la
tabla. Esto supone que la columna no puede contener valores nulos ni pueden haber
valores duplicados en esa columna, es decir que dos filas no pueden tener el mismo valor
en esa columna.
En una tabla no pueden haber varias claves principales, por lo que no podemos incluir
la cláusula PRIMARY KEY más de una vez, en caso contrario la sentencia da un error. No
hay que confundir la definición de varias claves principales con la definición de una clave
principal compuesta por varias columnas, esto último sí está permitido y se define con una
restricción de tipo 2.
La cláusula UNIQUE sirve para definir un índice único sobre la columna. Un índice único
es un índice que no permite valores duplicados, es decir que si una columna tiene
definida un restricción de UNIQUE no podrán haber dos filas con el mismo valor en esa
columna. Se suele emplear para que el sistema compruebe el mismo que no se añaden
valores que ya existen, por ejemplo si en una tabla de clientes queremos asegurarnos que
dos clientes no puedan tener el mismo D.N.I. y la tabla tiene como clave principal un código
de cliente, definiremos la columna dni con la restricción de UNIQUE.
La cláusula NOT NULL indica que la columna no puede contener valores nulos, cuando
queremos indicar que una columna no puede contener el valor nulo lo podemos hacer sin
poner la cláusula CONSTRAINT, o utilizando una cláusula CONSTRAINT.
La última restricción que podemos definir sobre una columna es la de clave foránea, una
clave foránea es una columna o conjunto de columnas que contiene un valor que hace
referencia a una fila de otra tabla, en una restricción de tipo 1 se puede definir con la
cláusula REFERENCES, después de la palabra reservada indicamos a qué tabla hace
referencia, opcionalmente podemos indicar entre paréntesis el nombre de la columna donde
tiene que buscar el valor de referencia, por defecto coge la clave principal de la tabla2, si el
valor que tiene que buscar se encuentra en otra columna de tabla2, entonces debemos
inidicar el nombre de esta columna entre paréntesis, además sólo podemos utilizar una
columna que esté definida con una restricción de UNIQUE, si la columna2 que indicamos
no está definida sin duplicados, la sentencia CREATE nos dará un error. Si quieres repasar
conceptos de clave foránea e integridad referencial haz clic aquí
Ejemplo:
Con este ejemplo estamos creando la tabla tab1 compuesta por: una columna llamada
col1 de tipo entero definida como clave principal, una columna col2 que puede almacenar
hasta 25 caracteres alfanuméricos y no puede contener valores nulos, una columna col3 de
hasta 10 caracteres que no podrá contener valores repetidos, una columna col4 de tipo
entero sin ninguna restricción, y una columna col5 de tipo entero clave foránea que hace
referencia a valores de la clave principal de la tabla tab2.
Principio del formulario
Tema 8. El DDL, lenguaje de
definición de datos (II) Búsqueda
CREATE TABLE...Continuación
Una restricción de tipo 2 se utiliza para definir una característica que afecta a una
columna o a una combinación de columnas de la tabla que estamos definiendo, se
escribe después de haber definido todas las columnas de la tabla.
En una tabla no pueden haber varias claves principales, por lo que no podemos
indicar la cláusula PRIMARY KEY más de una vez, en caso contrario la sentencia da un
error.
La cláusula UNIQUE sirve para definir un índice único sobre una columna o sobre una
combinación de columnas. Un índice único es un índice que no permite valores
duplicados. Si el índice es sobre varias columnas no se puede repetir la misma
combinación de valores en dos o más filas. Se suele emplear para que el sistema
compruebe el mismo que no se añaden valores que ya existen.
La cláusula FOREIGN KEY sirve para definir una clave foránea sobre una columna o
una combinación de columnas. Una clave foránea es una columna o conjunto de columnas
que contiene un valor que hace referencia a una fila de otra tabla, en una restricción 1
se puede definir con la cláusula REFERENCES. Para definir una clave foránea en una
restricción de tipo 2 debemos empezar por las palabras FOREIGN KEY después indicamos
entre paréntesis la/s columna/s que es clave foránea, a continuación la palabra reservada
REFERENCES seguida del nombre de la tabla a la que hace referencia, opcionalmente
podemos indicar entre paréntesis el nombre de la/s columna/s donde tiene que buscar el
valor de referencia, por defecto coge la clave principal de la tabla2, si el valor que tiene que
buscar se encuentra en otra/s columna/s de tabla2, entonces debemos escribir el nombre
de esta/s columna/s entre paréntesis, además sólo podemos utilizar una columna (o
combinación de columnas) que esté definida con una restricción de UNIQUE, de lo contrario
la sentencia CREATE TABLE nos dará un error.
Ejemplo:
Con este ejemplo estamos creando la misma tabla tab1 del ejemplo de la página anterior
pero ahora hemos definido las restricciones utilizando restricciones de tipo 2.
Principio del formulario
Tema 8. El DDL, lenguaje de
definición de datos (III) Búsqueda
ALTER TABLE
La sentencia ALTER TABLE sirve para modificar la estructura de una tabla que ya
existe. Mediante esta instrucción podemos añadir columnas nuevas, eliminar columnas. Ten
cuenta que cuando eliminamos una columna se pierden todos los datos almacenados en
ella.
También nos permite crear nuevas restricciones o borrar algunas existentes. La sintaxis
puede parecer algo complicada pero sabiendo el significado de las palabras reservadas la
sentencia se aclara bastante; ADD (añade), ALTER (modifica), DROP (elimina), COLUMN
(columna), CONSTRAINT (restricción).
La sintaxis es la siguiente:
Ejemplo:
ALTER TABLE tab1 ADD COLUMN col3 integer NOT NULL CONSTRAINT c1 UNIQUE
Con este ejemplo estamos añadiendo a la tabla tab1 una columna llamada col3 de tipo
entero, requerida (no admite nulos) y con un índice sin duplicados llamado c1.
Para añadir una nueva restricción en la tabla podemos utilizar la cláusula ADD
restriccion2 (ADD CONSTRAINT...).
Ejemplo:
Con este ejemplo estamos añadiendo a la tabla tab1 un índice único (sin duplicados)
llamado c1 sobre la columna col3.
Para borrar una columna basta con utilizar la cláusula DROP COLUMN (COLUMN es
opcional) y el nombre de la columna que queremos borrar, se perderán todos los datos
almacenados en la columna.
Ejemplo:
Para borrar una restricción basta con utilizar la cláusula DROP CONSTRAINT y el
nombre de la restricción que queremos borrar, en este caso sólo se elimina la definición de
la restricción pero los datos almacenados no se modifican ni se pierden.
Ejemplo:
Con esta sentencia borramos el índice c1 creado anteriormente pero los datos de la
columna col3 no se ven afectados por el cambio.
DROP TABLE
La sentencia DROP TABLE sirve para eliminar una tabla. No se puede eliminar una
tabla si está abierta, tampoco la podemos eliminar si el borrado infringe las reglas de
integridad referencial (si interviene como tabla padre en una relación y tiene registros
relacionados).
La sintaxis es la siguiente:
Ejemplo:
CREATE INDEX
La sentencia CREATE INDEX sirve para crear un índice sobre una o varias columnas de
una tabla. Si quieres repasar conceptos básicos sobre índices haz clic aquí
Un índice en informática es como el índice de un libro donde tenemos los capítulos del
libro y la página donde empieza cada capítulo. No vamos a entrar ahora en cómo se
implementan los índices internamente ya que no entra en los objetivos del curso pero sí
daremos unas breves nociones de cómo se definen, para qué sirven y cuándo hay que
utilizarlos y cuando no.
Un índice es una estructura de datos que permite recuperar las filas de una tabla de
forma más rápida además de proporcionar una ordenación distinta a la natural de la
tabla. Un índice se define sobre una columna o sobre un grupo de columnas, y las
filas se ordenarán según los valores contenidos en esas columnas. Por ejemplo, si
definimos un índice sobre la columna poblacion de la tabla de clientes, el índice permitirá
recuperar los clientes ordenados por orden alfabético de población.
Ventajas:
Si una tabla tiene definido un índice sobre una columna se puede localizar mucho más
rápidamente una fila que tenga un determinado valor en esa columna.
Recuperar las filas de una tabla de forma ordenada por la columna en cuestión
también será mucho más rápido.
Inconvenientes:
Al ser el índice una estructura de datos adicional a la tabla, ocupa un poco más de
espacio en disco.
Cuando se añaden, modifican o se borran filas de la tabla, el sistema debe actualizar los
índices afectados por esos cambios lo que supone un tiempo de proceso mayor.
Los inconvenientes comentados en este punto no son nada comparados con las
ventajas si la columna sobre la cual se define el índice es una columna que se va a utilizar
a menudo para buscar u ordenar las filas de la tabla. Por eso una regla bastante acertada
es definir índices sobre columnas que se vayan a utilizar a menudo para recuperar u
ordenar las filas de una tabla.
La sintaxis es la siguiente:
nbindi: nombre del índice que estamos definiendo. En una tabla no pueden haber
dos índices con el mismo nombre de lo contrario da error.
ASC: la cláusula ASC es la que se asume por defecto e indica que el orden elegido
para el índice es ascendente (en orden alfabético si la columna es de tipo texto, de menor
a mayor si es de tipo numérico, en orden cronológico si es de tipo fecha).
WITH PRIMARY indica que el índice define la clave principal de la tabla, si la tabla ya
tiene una clave principal, la sentencia CREATE INDEX dará error.
WITH DISALLOW NULL indica que no permite valores nulos en las columnas que
forman el índice.
WITH IGNORE NULL indica que las filas que tengan valores nulos en las columnas
que forman el índice se ignoran, no aparecen cuando recuperamos las filas de la tabla
utilizando ese índice.
Ejemplo:
Crea un índice llamado ind1 sobre la tabla clientes formado por las columnas provincia,
población y fecha_nacimiento. Este índice permite tener ordenadas las filas de la tabla
clientes de forma que aparezcan los clientes ordenados por provincia, dentro de la misma
provincia por población y dentro de la misma población por edad y del más joven al más
mayor.
Al añadir la cláusula UNIQUE el índice no permitirá duplicados por lo que no podría tener
dos clientes con la misma fecha de nacimiento en la misma población y misma provincia,
para evitar el poblema sería mejor utilizar:
DROP INDEX
La sentencia DROP INDEX sirve para eliminar un índice de una tabla. Se elimina el
índice pero no las columnas que lo forman.
La sintaxis es la siguiente:
Ejemplo:
Si tienes ya creadas las tablas de los ejercicios del curso y no quieres perder los datos
introducidos cámbiales el nombre antes de empezar los ejercicios de esta unidad.
2 Crear la tabla oficinas con su clave principal y su clave foránea ( la columna dir
contiene el código de empleado del director de la oficina luego es un campo que hace
referencia a un empleado luego es clave foránea y hace referencia a la tabla empleados).
4 Crear la tabla clientes también con todas sus claves y sin la columna limitecredito.
5 Crear la tabla pedidos sin clave principal, con la clave foránea que hace referencia a los
productos, la que hace referencia a clientes y la que indica el representante (empleado) que
ha realizado el pedido.
7 Añadir a la tabla empleados las claves foráneas que le faltan. (Si no tienes claro cuales
son te lo decimos ahora: la columna oficina indica la oficina donde trabaja el empleado y la
columna director indica quién dirige al empleado, su jefe inmediato).
Ejercicio 2
CREATE TABLE oficinas ( Para definir la columna dir como clave foránea
oficina INT PRIMARY KEY, hemos elegido una restricción1 (poner la
ciudad TEXT(30), definición dentro de la definición de la columna).
region TEXT(20),
dir INT CONSTRAINT cf_dir
REFERENCES empleados,
objetivo CURRENCY,
ventas CURRENCY );
Ejercicio 3
CREATE TABLE productos ( En este caso la clave principal está formada por
idfab TEXT(10), dos columnas idfab e idproducto luego para
idproducto TEXT(20), definirla tenemos que utilizar necesariamente
descripcion TEXT(30) NOT NULL, una restricción2.
precio CURRENCY NOT NULL,
existencias INT ,
CONSTRAINT cp PRIMARY KEY
(idfab,idproducto) );
Ejercicio 4
CREATE TABLE clientes ( La clave principal se puede definir en una
numclie INT , restricción2 aunque esté compuesta por una
nombre TEXT(30) NOT NULL, sola columna.
repclie INT CONSTRAINT cf_repclie
REFERENCES empleados,
CONSTRAINT cp PRIMARY KEY
(numclie) ) ;
Ejercicio 5
CREATE TABLE pedidos ( Para exponer más formas de definir una tabla
codigo COUNTER, aquí te hemos definido todas las claves como
numpedido INT PRIMARY KEY, restricción2 la única que es obligatoria en una
fechapedido DATETIME NOT NULL, restricción2 es la cf_prod ya que está
clie INT NOT NULL, compuesta por varias columnas.
rep INT NOT NULL,
fab TEXT(10) NOT NULL,
producto TEXT(20) NOT NULL,
cant INT NOT NULL,
importe CURRENCY NOT NULL,
CONSTRAINT cf_clie FOREIGN KEY
(clie) REFERENCES clientes,
CONSTRAINT cf_rep FOREIGN KEY
(rep) REFERENCES empleados,
CONSTRAINT cf_prod FOREIGN
KEY (fab,producto) REFERENCES
productos );
Ejercicio 6
ALTER TABLE clientes Para añadir una nueva columna a una tabla que
ADD COLUMN limitecredito MONEY; ya existe debemos emplear la sentencia ALTER
TABLE, y en nuestro caso la cláusula ADD
COLUMN (COLUMN es opcional).
Ejercicio 7
ALTER TABLE empleados Para añadir una definición de clave foránea hay
ADD CONSTRAINT cf_oficina que añadir una restricción2, se pueden añadir
FOREIGN KEY (oficina) varias restricciones en la misma sentencia
REFERENCES oficinas, ALTER TABLE.
CONSTRAINT cf_director FOREIGN
KEY (director) REFERENCES
empleados;
Ejercicio 8
Solución 1 Para que no se puedan repetir los valores en la
ALTER TABLE empleados columna nombre hay que definir un índice único,
ADD CONSTRAINT u_nombre o bien definiendo una restricción sobre la
UNIQUE (nombre); columna como te indicamos en la solución 1 o
bien creando el índice único como te indicamos
Solución 2 en la solución 2.
CREATE UNIQUE INDEX u_nombre
ON empleados (nombre);
Ejercicio 9
Solución 1 Para añadir una definición de clave primaria hay
ALTER TABLE pedidos que añadir una restricción2.
ADD CONSTRAINT cp PRIMARY
KEY (numpedido);
Ejercicios
2. Consultas simples
3. Consultas multitabla
4. Consultas de resumen
5. Subconsultas
6. Actualización de datos
7. Tablas de referencias
cruzadas.
8. Lenguaje de Definición de
Datos.
Antes de empezar deberías crear la base de datos datos.mdb con las tablas descritas en
el tema 1 clic aquí para verlas.
Nota: Debes crear una consulta por cada ejercicio, no se pueden escribir varias
sentencias SQL en una misma consulta.
Si quieres puedes guardar cada consulta con un nombre que permita identificarla por
ejemplo: consulta_2_1 siendo 2 el número del tema y 1 el número del ejercicio dentro del
tema.
Ahora puedes empezar a redactar las sentencias SQL para obtener lo que se pide en
cada ejercicio.
La lista de selección
1 Obtener una lista de todos los productos indicando para cada uno su idfab, idproducto,
descripción, precio y precio con I.V.A. incluido (es el precio anterior aumentado en un 16%).
2 De cada pedido queremos saber su número de pedido, fab, producto, cantidad, precio
unitario e importe.
Ordenación de filas.
4 Obtener la lista de los clientes agrupados por código de representante asignado,
visualizar todas la columnas de la tabla.
5 Obtener las oficinas ordenadas por orden alfabético de región y dentro de cada región
por ciudad, si hay más de una oficina en la misma ciudad, aparecerá primero la que tenga
el número de oficina mayor.
Selección de filas.
7 Listar las cuatro líneas de pedido más caras (las de mayor importe).
8 Obtener las mismas columnas que en el ejercicio 2 pero sacando unicamente las 5
líneas de pedido de menor precio unitario.
10 Listar los números de los empleados que tienen una oficina asignada.
12 Listar los datos de las oficinas de las regiones del norte y del este (tienen que
aparecer primero las del norte y después las del este).
1 Listar las oficinas del este indicando para cada una de ellas su número, ciudad,
números y nombres de sus empleados. Hacer una versión en la que aparecen sólo las que
tienen empleados, y hacer otra en las que aparezcan las oficinas del este que no tienen
empleados.
2 Listar los pedidos mostrando su número, importe, nombre del cliente, y el límite de
crédito del cliente correspondiente (todos los pedidos tienen cliente y representante).
3 Listar los datos de cada uno de los empleados, la ciudad y región en donde trabaja.
4 Listar las oficinas con objetivo superior a 600.000 pts indicando para cada una de ellas
el nombre de su director.
5 Listar los pedidos superiores a 25.000 pts, incluyendo el nombre del empleado que
tomó el pedido y el nombre del cliente que lo solicitó.
6 Hallar los empleados que realizaron su primer pedido el mismo día en que fueron
contratados.
7 Listar los empleados con una cuota superior a la de su jefe; para cada empleado sacar
sus datos y el número, nombre y cuota de su jefe.
8 Listar los códigos de los empleados que tienen una línea de pedido superior a 10.000
ptas o que tengan una cuota inferior a 10.000 pts.
Ejercicio 2
SELECT numpedido, importe, En este ejercicio no pueden haber pedidos sin
clientes.nombre AS cliente, cliente, y lo que nos interesa son los pedidos,
limitecredito luego tampoco tienen que aparecer los clientes
FROM pedidos INNER JOIN clientes que no tienen pedidos, por lo tanto utilizamos un
ON pedidos.clie = clientes.numclie INNER JOIN.
Ejercicio 3
SELECT empleados.*, ciudad, Aquí hemos utilizado LEFT JOIN para que
region también salgan los empleados que no tienen
FROM empleados LEFT JOIN oficina asignada.
oficinas ON empleados.oficina = Como queremos todos los datos del empleado
oficinas.oficina utilizamos empleados.* para acortar.
Ejercicio 4
SELECT oficinas.*, nombre AS Nos interesan las oficinas con objetivo superior
director a 600.000pts. luego nos tenemos que asegurar
FROM empleados RIGHT JOIN que salgan todas incluso si no tienen director
oficinas ON empleados.oficina = asignado por eso utilizamos RIGHT JOIN.
oficinas.oficina En los valores numéricos no utilizar el punto
WHERE objetivo > 600000 para separar los miles (lo consideraría coma
decimal y entendería 600 en vez de 600000).
Ejercicio 5
SELECT numpedido, importe, En este ejercicio no pueden haber pedidos sin
empleados.nombre AS representante ni cliente, y lo que nos interesa
representante, clientes.nombre AS son los pedidos, luego tampoco tienen que
cliente aparecer los representantes que no tienen
FROM (pedidos INNER JOIN clientes pedidos ni los clientes que no tienen pedidos,
ON pedidos.clie = clientes.numclie) por lo tanto utilizamos un INNER JOIN.
INNER JOIN empleados ON
pedidos.rep = empleados.numemp Primero añadimos a cada línea de pedido los
WHERE importe > 25000 datos del cliente corespondiente (con el primer
INNER) y a cada fila resultante añadimos los
datos del representante correspondiente.
Ejercicio 7
SELECT empleados.*, jefes.numemp En una misma línea necesito los datos del
AS num_jefe, jefes.nombre AS empleado y los datos de su jefe, luego tengo
nombre_jefe, jefes.cuota AS que combinar empleados con empleados. No
cuota_jefe interesan los empleados que no tienen jefe
FROM empleados INNER JOIN luego utilizo INNER. El alias de tabla es
empleados jefes ON empleados.jefe obligatorio ya que combino empleados con la
= jefes.numemp misma.
WHERE empleados.cuota >
jefes.cuota
Ejercicio 8
SELECT numemp Una posible solución es combinar pedidos con
FROM empleados LEFT JOIN empleados para poder seleccionar las líneas de
pedidos ON pedidos.rep = importe > 10000 o cuota < 10000. Hay que
empleados.numemp utilizar LEFT para que puedan aparecer
WHERE importe > 10000 OR cuota < empleados con cuota < 10000 que no tengan
10000 pedidos.
SELECT rep Esta es otra solución, obtener por una parte los
FROM pedidos códigos de los empleados con una línea de
WHERE importe > 10000 pedido > 10000, por otra parte los códigos de
UNION los empleados con cuota < 10000 y finalmente
SELECT numemp unir las dos listas con una UNION.
FROM empleados
WHERE cuota < 10000
4 ¿Cuál es el importe total de los pedidos realizados por el empleado Vicente Pantalla?
5 Hallar en qué fecha se realizó el primer pedido (suponiendo que en la tabla de pedidos
tenemos todos los pedidos realizados hasta la fecha).
6 Hallar cuántos pedidos hay de más de 25000 ptas.
7 Listar cuántos empleados están asignados a cada oficina, indicar el número de oficina y
cuántos hay asignados.
8 Para cada empleado, obtener su número, nombre, e importe vendido por ese empleado
a cada cliente indicando el número de cliente.
9 Para cada empleado cuyos pedidos suman más de 30.000 ptas, hallar su importe
medio de pedidos. En el resultado indicar el número de empleado y su importe medio de
pedidos.
10 Listar de cada producto, su descripción, precio y cantidad total pedida, incluyendo sólo
los productos cuya cantidad total pedida sea superior al 75% del stock; y ordenado por
cantidad total pedida.
Ejercicio 2
SELECT AVG(importe) AS El precio medio de venta es la media aritmética
importe_medio, SUM(importe) AS de los precios unitarios de cada pedido. El
importe_total, AVG(importe/cant) AS precio unitario se calcula dividiendo el importe
precio_venta_medio del pedido por la cantidad del pedido:
FROM pedidos importe/cant, por lo que ponemos
AVG(importe/cant).
Ejercicio 3
SELECT AVG(precio) AS Ahora no nos interesan todos los productos sino
p_medio_ACI unicamente los del fabricante ACI, por lo que
FROM productos añadimos la cláusula WHERE para que antes
WHERE idfab = 'ACI' de calcular la media, elimine del origen de datos
los registros que no cumplan la condición.
Ejercicio 4
SELECT SUM(importe) AS El importe total lo tenemos que sacar de la tabla
total_pedidos_V_Pantalla de pedidos, y además sólo nos interesan los de
FROM empleados INNER JOIN Vicente Pantalla. Como nos dan el nombre del
pedidos ON empleados.numemp = representante en vez de su número y en el
pedidos.rep pedido sólo tenemos el número de
WHERE nombre = 'Vicente Pantalla' representante tenemos que añadir a las líneas
de cada pedido, los datos del representante
correspondiente, por lo que el origen de datos
debe ser el que aparece en la FROM.
Ejercicio 5
SELECT MIN(fechapedido) AS La fecha del primer pedido es la fecha más
primer_pedido antigua de la tabla de pedidos.
FROM pedidos
Ejercicio 6
SELECT COUNT(*) AS Se podía haber utilizado también
cuantos_pedidos_mayores COUNT(numpedido) o cualquier nombre de
FROM pedidos columna que no pueda contener valores nulos,
WHERE importe > 25000 pero COUNT(*) es mejor por ser más rápido (la
diferencia se nota con tablas muy voluminosas).
Ejercicio 7
SELECT oficina, COUNT(*) AS Con esta solución obtenemos el listado pedido
cuantos_empleados pero no aparecen las oficinas que no tienen
FROM empleados empleados asignados ya que sacamos la
GROUP BY oficina información de la tabla empleados y aparece
una fila con valor nulo en oficina que contiene el
número de empleados que no tienen oficina. Si
quisieramos listar incluso las que no tengan
empleados habría que recurrir a la solución 2
Ejercicio 9
SELECT rep, AVG(importe) AS No queremos todos los empleados, unicamente
importe_medio los que tengan un importe total pedido superior
FROM pedidos a 30.000, luego tenemos que poner la condición
GROUP BY rep SUM(importe) > 30000. Como esta condición
HAVING SUM(importe) > 30000 contiene una función de columna (SUM()) se
tiene que poner en la cláusula HAVING ya que
selecciona filas de la tabla resultante no del
origen de datos.
Ejercicio 10
SELECT descripcion, precio, La agrupación básica es por idfab e idproducto
SUM(importe) AS total_pedido ya que son los dos campos que conjuntamente
FROM productos INNER JOIN identifican un producto.
pedidos ON pedidos.fab = Como descripción y precio aparecen en la lista
productos.idfab AND de selección y no modifican la agrupación
pedidos.producto = básica los incluimos en el GROUP BY.
productos.idproducto
GROUP BY idfab, idproducto, Como existencias aparece en el HAVING y no
descripcion, precio, existencias modifica la agrupación básica lo incluimos
HAVING SUM(importe) > existencias también el el GROUP BY.
* 0.75
ORDER BY 3 Para calcular el 75% de las existencias
multiplicamos existencias por 0,75; observar que
en la sentencia SQL hay que utilizar el punto
para indicar los decimales.
1 Listar los nombres de los clientes que tienen asignado el representante Alvaro Jaumes
(suponiendo que no pueden haber representantes con el mismo nombre).
3 Listar los vendedores que no trabajan en oficinas dirigidas por el empleado 108.
4 Listar los productos (idfab, idproducto y descripción) para los cuales no se ha recibido
ningún pedido de 25000 o más.
5 Listar los clientes asignados a Ana Bustamante que no han remitido un pedido superior
a 3000 pts.
6 Listar las oficinas en donde haya un vendedor cuyas ventas representen más del 55%
del objetivo de su oficina.
7 Listar las oficinas en donde todos los vendedores tienen ventas que superan al 50% del
objetivo de la oficina.
8 Listar las oficinas que tengan un objetivo mayor que la suma de las cuotas de sus
vendedores.
SELECT numemp, nombre, oficina Con esta solución tenemos el mismo problema
FROM empleados que con NOT IN , cuando la oficina del
WHERE oficina <> ALL ( SELECT empleado es nula todos los resultados de las
oficina FROM oficinas WHERE dir = comparaciones individuales son nulos por los
108); que el test ALL da nulo y no se seleccionan los
empleados con oficina nula.
Ejercicio 4
SELECT idfab, idproducto, En este caso es más cómodo utilizar NOT
descripcion EXISTS ya que hay que preguntar por el idfab e
FROM productos idproducto a la vez.
WHERE NOT EXISTS (SELECT *
FROM pedidos WHERE fab = idfab
AND producto = idproducto AND
importe >= 25000);
Ejercicio 5
SELECT numclie, nombre
FROM clientes
WHERE repclie IN ( SELECT
numemp FROM empleados WHERE
nombre = 'Ana Bustamante' )
AND numclie NOT IN ( SELECT clie
FROM pedidos WHERE importe >
3000);
Ejercicio 6
SELECT * En una subconsulta todos los campos no
FROM oficinas cualificados se presuponen de la tabla origen de
WHERE EXISTS ( SELECT * FROM la subconsulta y sólo si no existe ninguna
empleados WHERE ventas > columna con ese nombre, la considera como
objetivo * 0.55); referencia externa, por eso no es necesario
cualificar ventas porque interpreta que es el
campo ventas de la tabla empleados.
Ejercicio 7
SELECT * Esta solución no vale porque salen las oficinas
FROM oficinas que no tienen empleados.
WHERE (objetivo * 0.5) <= ALL Hay que añadir una condición para que se
( SELECT ventas FROM empleados consideren sólo las oficinas con empleados
WHERE empleados.oficina = como muestra la solución 1.
oficinas.oficina );
Solución 1
SELECT *
FROM oficinas
WHERE ((objetivo * 0.5) <= ALL
( SELECT ventas FROM empleados
WHERE empleados.oficina =
oficinas.oficina ) )
AND ( EXISTS ( SELECT * FROM
empleados WHERE
empleados.oficina =
oficinas.oficina ) );
1 Crear una tabla (llamarla nuevaempleados) que contenga las filas de la tabla
empleados.
2 Crear una tabla (llamarla nuevaoficinas) que contenga las filas de la tabla oficinas.
3 Crear una tabla (llamarla nuevaproductos) que contenga las filas de la tabla productos.
4 Crear una tabla (llamarla nuevapedidos) que contenga las filas de la tabla pedidos.
6 Añadir una nueva oficina para la ciudad de Madrid, con el número de oficina 30, con un
objetivo de 100000 y región Centro.
Ejercicio 4
SELECT * INTO nuevapedidos
FROM pedidos;
Ejercicio 5
UPDATE productos También se puede poner precio = precio +
SET precio = precio * 1.05 WHERE precio*0.05
idfab = 'ACI';
Ejercicio 6
Solución 1
Como no asignamos valor a todos los campos,
INSERT INTO oficinas ( oficina, no hace falta poner todas las columnas en la
region, ciudad, objetivo ) lista de columnas. Los campos dir y ventas se
VALUES ( 30, 'centro','Madrid', rellenarán con el valor predeterminado.
100000 );
¡Ojo! Si la tabla oficinas tiene definido en la
columna dir el valor predeterminado 0, al
intentar ejecutar la INSERT ocurrirá un error
porque asigna 0 al campo dir , como dir es clave
ajena, antes de insertar comprueba que el valor
insertado en la clave ajena existe en la tabla
empleados, y el empleado 0 no existe por lo que
no puede insertar la oficina, el valor
predeterminado de dir debe ser nulo.
Ejercicio 8
DELETE FROM pedidos WHERE rep
= 105;
Ejercicio 9
Solución 1 Si la oficina no tiene empleados asignados, no
DELETE FROM oficinas WHERE existe ningún empleado con el número de esa
NOT EXISTS (SELECT * oficina.
FROM empleados WHERE
empleados.oficina =
oficinas.oficina);
Ejercicio 12
INSERT INTO pedidos Insertamos en pedidos los pedidos del
SELECT * from nuevapedidos empleados 105 que se encuentran en la tabla
WHERE rep = 105; nuevapedidos.
Ejercicio 13
UPDATE empleados Si no hemos recuperado las oficinas borradas,
SET oficina = 21 WHERE oficina = no permitirá cambiar el campo oficina a 21 ya
30; que la oficina 21 es de las que se han borrado
en el ejercicio 9.
1 Queremos saber de cada empleado sus ventas mensuales del año 1990.
4 Se necesita una estadística de cuántos empleados fueron contratados por año en cada
oficina.
5 Queremos saber por año las ventas realizadas en las distintas regiones.
Solución ejercicios tema 7. Referencias cruzadas
Ejercicio 1
TRANSFORM SUM(importe) Queremos calcular la suma de importes de los
pedidos realizados durante el año 1990
SELECT rep AS empleado agrupando por empleado y mes, queremos una
FROM pedidos fila por empleado luego GROUP BY rep,
WHERE year(fechapedido)=1990 queremos que los meses aparezcan como
columnas dinámicas, luego PIVOT
GROUP BY rep MONTH(fechapedido), el calculo se hace en
base a los pedidos de 1990 luego el origen de la
PIVOT MONTH(fechapedido); FROM es pedidos con el WHERE para
seleccionar los pedidos de 1990, como columna
fija queremos el número de empleado luego la
lista de selección será rep con un alias para que
el resultado salga más aseado.
Ejercicio 2
TRANSFORM SUM(importe) Ahora queremos que además aparezca el
nombre del empleado, como no está en la tabla
SELECT numemp AS empleado, pedidos sino en empleados, hay que añadir a
nombre los pedidos los datos del empleado con el
FROM pedidos INNER JOIN INNER JOIN, ahora queremos dos columnas
empleados ON fijas, la del número de empleado y su nombre
pedidos.rep=empleados.numemp luego en la lista de selección añadimos nombre,
WHERE year(fechapedido)=1990 y como estamos en una sumaria nombre no
puede estar en la lista de selección si no está en
GROUP BY numemp, nombre el GROUP BY luego lo añadimos a la cláusula
GROUP BY.
PIVOT MONTH(fechapedido);
Ejercicio 3
TRANSFORM SUM(importe) Ahora queremos agrupar por oficina,
año y mes, el pivote sería año y mes
SELECT oficina pero no se pueden poner dos campos
FROM pedidos RIGHT JOIN empleados ON en la cláusula PIVOT, lo que hacemos
pedidos.rep=empleados.numemp es unir los dos campos en uno
mediantela concatenación & además
GROUP BY oficina para que queden los valores más
claros los separamos por una barra.
PIVOT
year(fechapedido)&"/"&MONTH(fechapedido);
Ejercicio 4
TRANSFORM COUNT(numemp) En este caso elegimos como pivote el año y
como encabezado de fila la oficina ya que
SELECT oficina normalmente abrán más oficinas que años.
FROM empleados
GROUP BY oficina
PIVOT year(contrato);
Ejercicio 5
TRANSFORM SUM(importe) En este ejercicios necesitamos los pedidos para
el importe vendido y la tabla oficinas para la
SELECT YEAR(fechapedido) AS región y para unirlas debemos utilizar la tabla
anyo empleados para relacionar los pedidos con las
FROM (pedidos INNER JOIN oficinas de los empleados que han realizado el
empleados ON pedido.
pedidos.rep=empleados.numemp)
INNER JOIN oficinas ON
empleados.oficina=oficinas.oficina
GROUP BY YEAR(fechapedido)
PIVOT region;
Si tienes ya creadas las tablas de los ejercicios del curso y no quieres perder los datos
introducidos cámbiales el nombre antes de empezar los ejercicios de esta unidad.
2 Crear la tabla oficinas con su clave principal y su clave foránea ( la columna dir
contiene el código de empleado del director de la oficina luego es un campo que hace
referencia a un empleado luego es clave foránea y hace referencia a la tabla empleados).
4 Crear la tabla clientes también con todas sus claves y sin la columna limitecredito.
5 Crear la tabla pedidos sin clave principal, con la clave foránea que hace referencia a los
productos, la que hace referencia a clientes y la que indica el representante (empleado) que
ha realizado el pedido.
7 Añadir a la tabla empleados las claves foráneas que le faltan. (Si no tienes claro cuales
son te lo decimos ahora: la columna oficina indica la oficina donde trabaja el empleado y la
columna director indica quién dirige al empleado, su jefe inmediato).
Ejercicio 2
CREATE TABLE oficinas ( Para definir la columna dir como clave foránea
oficina INT PRIMARY KEY, hemos elegido una restricción1 (poner la
ciudad TEXT(30), definición dentro de la definición de la columna).
region TEXT(20),
dir INT CONSTRAINT cf_dir
REFERENCES empleados,
objetivo CURRENCY,
ventas CURRENCY );
Ejercicio 3
CREATE TABLE productos ( En este caso la clave principal está formada por
idfab TEXT(10), dos columnas idfab e idproducto luego para
idproducto TEXT(20), definirla tenemos que utilizar necesariamente
descripcion TEXT(30) NOT NULL, una restricción2.
precio CURRENCY NOT NULL,
existencias INT ,
CONSTRAINT cp PRIMARY KEY
(idfab,idproducto) );
Ejercicio 4
CREATE TABLE clientes ( La clave principal se puede definir en una
numclie INT , restricción2 aunque esté compuesta por una
nombre TEXT(30) NOT NULL, sola columna.
repclie INT CONSTRAINT cf_repclie
REFERENCES empleados,
CONSTRAINT cp PRIMARY KEY
(numclie) ) ;
Ejercicio 5
CREATE TABLE pedidos ( Para exponer más formas de definir una tabla
codigo COUNTER, aquí te hemos definido todas las claves como
numpedido INT PRIMARY KEY, restricción2 la única que es obligatoria en una
fechapedido DATETIME NOT NULL, restricción2 es la cf_prod ya que está
clie INT NOT NULL, compuesta por varias columnas.
rep INT NOT NULL,
fab TEXT(10) NOT NULL,
producto TEXT(20) NOT NULL,
cant INT NOT NULL,
importe CURRENCY NOT NULL,
CONSTRAINT cf_clie FOREIGN KEY
(clie) REFERENCES clientes,
CONSTRAINT cf_rep FOREIGN KEY
(rep) REFERENCES empleados,
CONSTRAINT cf_prod FOREIGN
KEY (fab,producto) REFERENCES
productos );
Ejercicio 6
ALTER TABLE clientes Para añadir una nueva columna a una tabla que
ADD COLUMN limitecredito MONEY; ya existe debemos emplear la sentencia ALTER
TABLE, y en nuestro caso la cláusula ADD
COLUMN (COLUMN es opcional).
Ejercicio 7
ALTER TABLE empleados Para añadir una definición de clave foránea hay
ADD CONSTRAINT cf_oficina que añadir una restricción2, se pueden añadir
FOREIGN KEY (oficina) varias restricciones en la misma sentencia
REFERENCES oficinas, ALTER TABLE.
CONSTRAINT cf_director FOREIGN
KEY (director) REFERENCES
empleados;
Ejercicio 8
Solución 1 Para que no se puedan repetir los valores en la
ALTER TABLE empleados columna nombre hay que definir un índice único,
ADD CONSTRAINT u_nombre o bien definiendo una restricción sobre la
UNIQUE (nombre); columna como te indicamos en la solución 1 o
bien creando el índice único como te indicamos
Solución 2 en la solución 2.
CREATE UNIQUE INDEX u_nombre
ON empleados (nombre);
Ejercicio 9
Solución 1 Para añadir una definición de clave primaria hay
ALTER TABLE pedidos que añadir una restricción2.
ADD CONSTRAINT cp PRIMARY
KEY (numpedido);