Manipulación de datos

Anuncio
Manipulación de datos
6.1 Introducción
Ahora abordaremos los aspectos de manipulación de datos de SQL. Este lenguaje ofrece
cuatro proposiciones en DML – SELECT (seleccionar), UPDATE (actualizar),
DELETE ( borrar) e INSERT (insertar)- el presente capitulo describe las caracteristicas
principales de los cuatro. Como se explico en la sección 4.3 las tablas manipuladas con
esas proposiciones de DML pueden ser, en términos generales, tanto tablas base como
vistas.
Pero este capitulo nos ocuparemos de manera exclusiva de las tablas base. Las vistas se
analizan en el capítulo 8.
Este capitulo esta organizado como sigue: las secciones 6.2 a 6.5 se ocupan de
las operaciones de recuperación de datos y la sección 6.6 estudia las operaciones de
actualización ( término en el cual incluimos, como ya es costumbre, todas las
operaciones con UPDATE, DELETE e INSERT) en términos más específicos:






La sección 6.2 presenta las características principales de la proposición select básica
La sección 6.3 explica como puede utilizarse select para expresar diversos tipos de
reunión ( en particular, la llamada reunión natural).
La sección 6.4 analiza las funciones de agregados COUNT (cuenta), SUM (suma)
AVG (promedio), etcétera; en particular describe el empleo de las cláusulas GROUP
BY (agrupar por) y HAVING (con) junto con esas funciones.
La sección 6.5 describe varias características adicionales: LIKE (como), la
condición IS NULL (es nulo), subconsultas, EXISTS (existe) y UNION (unión).
Estas construcciones, aunque bastante importante en algunos casos, suelen utilizarse
con menor frecuencia en la práctica que las que se describen en las secciones 6.2 a
6.4 razón por la cual se revisa en una sección aparte.
La sección 6.6 esta dedicada a las proposiciones UPDATE (actualizar), DELETE
(eleiminar) e INSERT (insertar).
Por ultimo trataremos de vincular varias de las ideas presentadas en el cuerpo del
capitulo. Para ello la sección 6.7 presentará como ejemplo una consulta muy
compleja y mostrará en principio cómo podría ejecutarse.
No es nuestra intención ofrecer un tratamiento complejo del lenguaje de
manipulación de datos (DML) de SQL; sólo queremos ilustrar sus características
principales. Con todo, el capitulo es bastante largo, y el lector quizá prefiera abordarlo
sección por sección. La sección 6.5 puede omitirse en una primera lectura, si se desea.
Nota: muchos de los ejemplos siguientes sobre todo los de la sección 6.5 son bastante
complejos. El lector deberá sacar la conclusión de que lo complejo radica en el lenguaje
SQL mismo, con ello queremos subrayar más bien el hecho de que las operaciones
comunes son tan sencillas en SQL (y, de hecho, en casi todos los lenguajes relacionales)
que los ejemplos de tales operaciones resultan poco interesantes, y no iluistran toda la
potencia del lenguaje. Por supuesto, también mostraremos algunos ejemplos sencillos.
Como siempre, los ejemplos utilizan la base de datos de proveedores y partes.
6.2 CONSULTAS SIMPLES
Comenzaremos con un ejemplo sencillo: la consulta debe “obtener el número y la
situación de todos los proveedores de París “
la cual puede expresarse en SQL así:
SELECT S#, SITUACION
FROM S
WHERE CIUDAD = “ París”;
-----------------Resultado: S#
Situación
---------------S2
10
S3
30
Este ejemplo ilustra la forma más común de la proposición SELECT en SQL:
“SELECT (seleccionar) los campos especificados FROM (de) la tabla especificada
WHERE (donde) se cumpla la condición especificada”. El primer punto por destacar es
que el resultado de la consulta es otra tabla, derivada en alguna forma de las tablas
existentes en la base de datos. Dicho de otro modo, el usuario de un sistema relacional
trabaja siempre dentro del marco de referencia tabular sencillo, lo cual es una
característica muy atractiva de esos sistemas. (por esta razón decidimos que las tablas
relacionales constituyen un sistema cerrado bajo los operadores de recuperación de
datos de un lenguaje como SQL.
Hablaremos muchos más de cerca de la cerradura en la parte III del presente libro.)
Por cierto podríamos haber formulado la consulta empleando nombres de campo
calificados en todos los casos:
SELECT S.S# , S.SITUACIÓN
FROM S
WHERE S.CIUDAD = “París“
Un nombre de campo calificado se compone de un nombre de tabla ( o nombre
de variable de recorrido) y un nombre de campo, en ese orden, separados mediante un
punto. Nunca es indebido utilizar nombres calificados, y en algunos casos es
indispensable, como se verá en la sección 6.3.
Como referencia, mostramos enseguida la forma general de la proposición SELECT
( pasando por alto la posibilidad de UNION, la cual se explicara más delante de este
capitulo):
SELECT [DISTINCT] elemento (s)
FROM tabla (s)
[WHERE condición]
[GROUP BY campo(s)]
[HAVING condición]
[ ORDER BY campo (s)];
Enseguida mostraremos las características principales de esta proposición
mediante una seria bastante larga de ejemplos.
6.2.1 RECUPERACIÓN SIMPLE
Obtener los números de parte de todas las partes suministradas .
SELECT P#
FROM tabla (s)
RESULTADO:
P#
P1
P2
P3
P4
P5
P6
P1
P2
P2
P2
P4
P5
Obsérvese la repetición de números de parte en este resultado. SQL no elimina
filas repetidas del resultado de una proposición SELECT si el usuario no se lo pide de
manera explícita mediante la palabra DISTINT (distinto), como en:
SELECT DISTINT P#
FROM SP;
RESULTADO:
P#
P1
P2
P3
P4
P5
P6
Nota: en este ejemplo especifico sucede que cada fila contiene un nuevo valor escalar;
por tanto, el efecto de DISTINT en este caso es eliminar valores escalares repetidos.
Pero nótese, que en general el significado de DISTINT es “eliminar filas repetidas”.
Véase el ejemplo 6.3.5 en la siguiente sección como ilustración.
6.2.2 Recuperación de valores calculados.
Obtener, para todas las partes, el número de parte y su peso en gramos ( los pesos de
partes se dan en libras en la tabla P).
SELECT P.P#, ‘peso en gramos =’, P. PESO * 454
FROM P
----- -----------------------------Resultado
P#
---- -----------------------------P1 peso en gramos = 5448
P2 peso en gramos = 7718
P3 peso en gramos = 7718
P4 peso en gramos = 6356
P5 peso en gramos = 5448
P6 peso en gramos = 8626
La cláusula SELECT ( y también las cláusulas WHERE y HAVING, véanse los
ejemplos correspondientes) puede incluir expresiones escalares generales, empleando
por ejemplo, operadores escalares con más y menos y funciones escalares como
SUBSTR (subcadena), en vez de nombres simples de campo, o además de ellos.
6.2.3 Recuperación simple (“ SELECT*”).
Obtener datos completos de todos los proveedores.
SELECT *
FROM S
Resultado una copia de toda la tabla S. El asterisco representa una lista de todos los
nombres de campo de la tabla o tablas nombradas en la cláusula FROM (de), en el
orden de definición de esos campos en las proposiciones CREATE ( y quizá ALTER)
TABLE pertinentes. Así la proposición SELECT mostrada equivale a:
SELECT S.S#
FROM
S;
La notación del asterisco es cómoda para consultas interactivas, ya sea que
ahorra tecleo. No obstante, puede ser peligrosa en SQL embebido ( o sea, SQL dentro
de un programa de aplicación) porque el significado de “*” puede cambiar si se religa el
programa y entre tanto se ha modificado de alguna forma la definición de la tabla (sobre
todo si se ha añadido otra columna). Este libro utilizara “SELECT *” solo en contextos
donde no pueda provocar problemas ( casi en todos los contextos interactivos), y
recomendamos a los usuarios hacer lo mismo en la práctica.
6.2.4. recuperación calificada.
Obtener los números de los proveedores radicados en París cuya situación sea mayor de
que 20.
SELECT S#
FROM S
WHERE CIUDAD = París
AND
SITUACIÓN > 20:
------Resultado
S#
-----S3
La condición que sigue a WHERE ( donde) puede incluir los operadores de
comparación = ,<> (diferente de), >, >=, <, <=; los operadores booleanos AND, OR y
NOT; y paréntesis para indicar un orden de evaluación deseado.
6.2.5 recuperación por ordenamiento
Obtener números de proveedor y situación de los proveedores en París, en orden
descendente por situación.
SELECT S#, SITUACION
FROM S
WHERE CIUDAD= ‘París’
ORDER BY SITUACION DESC;
Resultado:
S# SITUACIÓN
------------------S3
30
S2
10
En general no se garantiza un orden particular en la tabla de resultado, pero aquí
el usuario especificó la organización del resultado en un cierto orden antes de su
presentación. El ordenamiento puede especificarse igual que en CREATE INDEX
(crear índice) como se observa en la sección 5.3, es decir,
Columna
[orden ]
[,
columna [orden] ]
Donde, como el caso de CREATE INDEX, “orden” puede ser asc o desc, y asc es el
orden por omisión
También es posible identificar columnas en la cláusula ORDER BY (ordenar
por) empleando números de columna en vez de nombres; es decir, según la posición
ordinal (izquierda a derecha) de la columna en cuestión dentro de la tabla de resultado.
Esta característica hace posible utilizar como criterio de ordenamiento del resultado una
columna sin nombre. Por ejemplo, si queremos organizar el resultado del ejemplo 6.2.2
en orden ascendente por número de parte dentro de un orden ascendente por peso en
gramos:
SELECT P.P#, ‘
peso en gramos =’, P:PESO * 454
FROM
P
ORDER BY 3, P# ;
/* o bien “ ORDER BY 3, 1;”*/
El 3 se refiere a la tercera columna de la tabla de resultado, Resultado:
P
-------P1
P5
P4
P2
P3
P6
6.3
-----------------------------------------peso en gramos = 5448
peso en gramos = 5448
peso en gramos = 6356
peso en gramos = 7718
peso en gramos = 7718
peso en gramos = 8626
CONSULTAS DE REUNIÓN
La posibilidad de “reunir” dos o más tablas en una sola es una de las
características más poderosas de los sistemas relacionales. De hecho, la
disponibilidad de la operación de reunión es, casi más importante que cualquier
otra cosa, lo que distingue a los sistemas relacionales de los no relacionales. Así
pues, ¿ qué es una reunión? en términos informales, es una consulta en la cual se
obtiene información de más de una tabla de una tabla. He aquí un ejemplo
sencillo.
6.3.1 Equirreunión simple.
Obtener todas las combinaciones de información de proveedores y partes tales que el
proveedor y la parte en cuestión estén situados en la misma ciudad ( es decir, estén
“consituados”; valga intentar un término antiestético pero cómodo).
SELECT S. *, P.*
FROM S, P
WHERE S.CIUDAD = P. CIUDAD;
Adviértase que aquí las referencias a campos en la cláusula WHERE deben calificarse
con los nombres de las tablas correspondientes (pues de lo contrario serían ambiguas)
Resultado.
S# SNOMBRE SITUACIÓN S.CIUDAD P.NOMBRE COLOR PESO P.CIUDAD
S1
S1
S1
S2
S2
S2
S2
S4
S4
S4
Salazar
Salazar
Salazar
Jaimes
Jaimes
Bernal
Bernal
Corona
Corona
Corona
20
20
20
10
10
30
30
20
20
20
Londres
Londres
Londres
París
París
París
París
Londres
Londres
Londres
P1 Tuerca
P4 Birlo
P6 Tuerca
P2 Perno
P5 Leva
P2 Perno
P5 Leva
P1 Tuerca
P1 Birlo
P6 Engrane
Rojo
Rojo
Rojo
Verde
Azul
Verde
Azul
Rojo
Rojo
Rojo
12 Londres
14 Londres
19 Londres
17
París
12
París
17
París
12
París
12 Londres
14 Londres
19 Londres
En este resultado hemos mostrado de manera explícita las dos columnas
CIUDAD como P.CIUDAD y S.CIUDAD, por claridad.
Explicación: por el enunciado del problema en español es evidente que los datos
requeridos provienen de dos tablas, a saber, S y P. Por tanto, en la formulación en SQL
de la consulta, nombramos primero esas dos tablas en la cláusula FROM (de) y en
seguida expresamos la conexión entre ellas ( o sea, el hecho de que los valores
CIUDAD deben ser iguales) en la cláusula WHERE (donde). Para entender el
funcionamiento de esa proposición, considérense cualesquiera dos filas, una de cada
tabla; por ejemplo estas dos:
S# SNOMBRE SITUACIÓN S.CIUDAD P.NOMBRE COLOR PESO P.CIUDAD
S1 Salazar
20
Londres P4 Birlo
Rojo
14
Londres
idénticas
Estas dos filas demuestran que el proveedor S1 y la parte de P1 si están
“cosituadas” (pues el valor de ciudad es el mismo en los dos casos). Por lo tanto,
generan la fila de resultado
--- ------------ ------------ ---------- ----- ----------- ------- ----- -------------S# S. nombre situación S. ciudad P# P nombre color peso P. ciudad
S1 Salazar
20
Londres P1 Tuerca
Rojo 12
Lóndres
-------------------------------------------------------------------------------------------------(ya que la satisfacen la condición de la cláusula WHERE; a saber, S.CIUDAD =
P.CIUDAD).
Lo mismo sucede con las demás parejas de filas en las cuales los valores CIUDAD
concuerdan. Nótese que el proveedor S5 (situado en Atenas) no aparece en el resultado,
por que no hay partes almacenadas en Atenas; de manera similar, la parte P3
(almacenada en Roma) tampoco aparece en el resultado, por que no hay proveedores
situados en Roma.
Se dice que el resultado de esta reunión de las tablas S y P con base en valores de
CIUDAD iguales. También se usa el termino de “reunión” para designar la operación de
construir el resultado de este tipo. Se dice que la condición S.CIUDAD = P.CIUDAD es
una condición de reunión.
Dicho sea de paso, no es obligatorio emplear la igualdad como operador de la
comparación en una condición de reunión, aunque es lo mas frecuente. El ejemplo 6.3.2
ilustra una reunión donde se emplea el operador mayor que. Pero si el operador es la
igualdad, la reunión recibe a veces la designación explícita de “equirreunión”. Por
definición la equirreunión debe producir un resultado de dos columnas idénticas (véase
el ejemplo anterior). Si se elimina una de esas dos columnas, quedará lo que se conoce
como reunión natural. He aquí un ejemplo de reunión natural( la de S y P con base en
las ciudades):
SELECT S#, SNOMBRE, SITUACIÓN, S.CIUDAD
P#, PNOMBRE, COLOR, PESO
FROM
S, P
WHERE S.CIUDAD = P.CIUDAD;
La reunión natural es definitivamente el tipo de reunión más útil; tanto así que el
termino reunión sin calificativo casi siempre se emplea para referirse de manera
especifica a la reunión natural.
Enseguida se presenta una forma distinta ( y útil) de enfocar la construcción
conceptual de las reuniones. Primero, se forma el producto se forma el producto
cartesiano de las tablas incluidas en la cláusula FROM (de). El producto cartesiano de
un conjunto de n tablas es la tabla formada por las filas f posibles, donde f es la
concatenación de una fila de la primera tabla, una fila de la segunda tabla,…, y una fila
de la enésima tabla, por ejemplo, el producto cartesiano de la tabla s y la tabla p (en ese
orden) es la siguiente tabla:
S#
S1
S1
S1
S1
S1
S1
S2
.
.
.
S5
S nombre
Salazar
Salazar
Salazar
Salazar
Salazar
Salazar
Jaimes
Situación
20
20
20
20
20
20
10
Ciudad
Londres
Londres
Londres
Londres
Londres
Londres
París
P#
P1
P2
P3
P4
P5
P6
P1
P nombre
Tuerca
Perno
Birlo
Birlo
Leva
Engrane
Tuerca
Color
rojo
verde
Azul
rojo
Azul
rojo
rojo
Aldana
30
Atenas
P6
Engrane
rojo
Peso
12
17
17
14
12
19
12
Ciudad
Londres
París
Roma
Londres
París
Londres
Londres
19
Londres
La tabla contiene 5*6 =30 filas.
Elimínense ahora de este producto cartesiano todas las filas que no satisfagan la
condición de reunión. Lo restante es la reunión requerida. En el presente caso,
eliminamos todas las filas en las cuales S. CIUDAD no es igual a P. CIUDAD y lo que
queda exactamente es la equirreunión antes mostrada.
6.3.2 Reunión mayor que
Obtener todas las combinaciones de información de proveedor y parte donde la ciudad
del proveedor siga a la ciudad de la parte en el orden alfabetico.
SELECT S.*, P.*
FROM S, P
WHERE S.CIUDAD > P.CIUDAD;
Resultado
S#
S2
S2
S2
S3
S3
S3
S nombre
Jaimes
Jaimes
Jaimes
Bernal
Bernal
Bernal
Situación
10
10
10
30
30
30
Ciudad
París
París
París
París
París
París
P#
P1
P4
P6
P1
P4
P6
P nombre
Tuerca
Birlo
Engrane
Tuerca
Birlo
Engrane
Color
rojo
rojo
rojo
rojo
rojo
rojo
Peso
12
14
19
12
14
19
Ciudad
Londres
Londres
Londres
Londres
Londres
Londres
6.3.3 Consulta de reunión con una condición adicional.
Obtener todas las combinaciones de información del proveedor y parte donde el
proveedor y la parte en cuestión estén cosituados, pero omitiendo a los proveedores
cuya situación sea 20
SELECT S.*, P.P#
FROM S, P
WHERE S.CIUDAD = P.CIUDAD
AND S.SITUACIÓN <> 20;
Resultado:
S#
S2
S2
S3
S3
S nombre
Jaimes
Jaimes
Bernal
Bernal
Situación
10
10
30
30
Ciudad
París
París
París
París
P#
P2
P5
P2
P5
P nombre
Perno
Leva
Perno
Leva
Color
Verde
Azul
Verde
azul
Peso
17
12
17
12
Ciudad
París
París
París
París
La cláusula WHERE en un SELECT de una reunión puede incluir otras condiciones
además de la condición de la reunión.
6.3.4 Recuperación de campos específicos de una reunión.
Obtener todas las combinaciones de un número proveedor/número de parte tales que el
proveedor y la parte en cuestión estén cosituados
SELECT S.S# , P.P#
FROM S, P
WHERE S.CIUDAD = P.CIUDAD;
Resultado:
S#
S1
S1
S1
S2
S2
S3
S3
S4
S4
S4
P
P1
P4
P6
P2
P5
P2
P5
P1
P4
P6
Desde luego también es posible seleccionar sólo los campos especificados de
una reunión, en vez de seleccionarlos todos por fuerza.
6.3.5 Reunión de tres tablas.
Obtener todas las parejas de nombres de ciudad tales que un proveedor situado en la
primera ciudad suministre una parte almacenada en la segunda ciudad. Por ejemplo, el
proveedor S1 suministra la parte P1; el proveedor S1 está situado en Londres, y la parte
P1 se almacena en Londres; por lo tanto, (Londres, Londres) es una pareja de ciudades
en el resultado.
SELECT DISTINCT S.CIUDAD, P.CIUDAD
FROM S, SP, P
WHERE S.S# = SP.S#
AND SP.P# = P.P#;
Resultado S. CIUDAD
P.CIUDAD
Londres
Londres
Londres
París
Londres
Roma
París
Londres
París
París
No hay un limite intrínseco para el número de tablas que se pueden juntar.
Adviértase que se uso DISTINCT (distinto) en el ejemplo con el objeto de eliminar las
parejas repetidas.
6.3.6 Reunión de una tabla consigo misma
Obtener todas las parejas de números de proveedor tales que dos proveedores en
cuestión estén cosituados.
SELECT PRIMERA.S#, SEGUNDA.S#
FROM S.PRIMERA, S.SEGUNDA
WHERE PRIMERA.CIUDAD = SEGUNDA.CIUDAD
AND PRIMERA.S# < SEGUNDA.S#
Resultado:
S#
S1
S2
S
S4
S3
Esta consulta implica una reunión de la tabla S consigo misma ( con base en
igualdad de ciudades) según se explica enseguida. Supongamos por un momento que
tenemos dos copias separadas de la tabla S, la “primera” y la “segunda”. Entonces, la
lógica de la consulta será la siguiente: necesitamos poder examinar todas las parejas
posibles de filas de proveedores, una de la primera copia de S y la otra de la segunda, y
extraer los dos números de proveedor de una de esas parejas de filas y sólo si los valores
de ciudad son iguales. Por tanto, necesitamos poder hacer referencia a dos filas de
proveedor al mismo tiempo. Para distinguir entre las dos referencias, introducimos las
variables de recorrido arbitrarias primera y segunda, cada una de las cuales recorre la
tabla S. En todo momento PRIMERA representa alguna fila de la primera copia de, y
SEGUNDA representa alguna fila de la segunda copia. El resultado de la consulta se
obtiene examinando todas la posibles parejas de valores PRIMERA/SEGUNDA y
probando la condición WHERE en cada caso.
Nota: el propósito de la condición PIMERA.S# < SEGUNDA.S# es doble:
a) Elimina las parejas de los números de proveedor de la forma (x,x)
b) Garantiza la aparición de sólo una de las parejas (x,y) y (y,x).
Éste primer ejemplo que hemos visto en el cual ha sido necesario el empleo de variables
de recorrido. Sin embargo, nunca es erróneo introducir tales variables, aun cuando no
sea indispensable su empleo, y en ocasiones puede hacer más clara la proposición.
6.4
FUNCIONES AGREGADAS
Aunque es bastante poderosa en muchos aspectos la proposición SELECT tal como se
ha descrito hasta ahora resulta inadecuada para muchos problemas prácticos. Por
ejemplo, aun una consulta tan sencilla como
“ ¿ Cuantos proveedores hay? “ No puede expresarse empleando las construcciones
utilizadas hasta ahora. Por tanto, SQL ofrece una serie de funciones agregadas
especiales para ampliar su capacidad básica de recuperación de información. Estas
funciones son COUNT(cuenta), SUM (suma), AVG (promedio), MAX (máximo), MIN
(mínimo). Sin tomar en cuenta el caso especial de “COUNT (*)” (véase lo siguiente),
cada una de las funciones trabaja sobre el total de valores en una columna de alguna
tabla, quizá una tabla derivada, es decir, una tabla construida como resultado de alguna
consulta y produce un solo valor como resultado según estas definiciones:
COUNT - número de valores en la columna
SUM
- suma de los valores de la columna
AVG
- promedio de valores de la columna
MAX - valor más grande de la columna
MIN
- valor más pequeño de la columna
En el caso de SUM y AVG la columna debe contener valores numéricos. En general, el
argumento de la función puede ir precedido de manera opcional por la palabra clave
DISTINC para indicar que los valores repetidos deben eliminarse antes de que se
aplique la función. En el caso de MAX y MIN, empero, DISTINCT sale sobrando y no
tiene efecto alguno. En el caso de COUNT, es necesario especificar DISTINCT; se
incluye la función especial COUNT (*), - no se permite DISTINCT – para contar todas
las filas de una tabla sin eliminación de duplicados.
Si hay nulos en la columna del argumento, se eliminarán antes de aplicarse la
función, se especifique o no la palabra clave DISTINCT (excepto en el caso de COUNT
(*), donde los valores nulos se manejan igual que los no nulos). Si el argumento es un
conjunto vacío, COUNT devuelve el valor de cero; las demás funciones devuelven el
valor nulo.
6.4.1 Función de agregados en la Cláusula SELECT
Obtener el número total de proveedores.
SELECT COUNT (*)
FROM S
Resultado
5
Obsérvese que el resultado en una tabla, con una fila y una columna (sin nombre) y
contiene un solo valor escalar 5.
6.4.2
Función de agregados en la Cláusula SELECT, con DISTINCT
Obtener el número total de proveedores que suministran partes en la actualidad.
SELECT COUNT (DISTINCT S#)
FROM SP;
Resultado: 4
6.4.3 función de agregados en la cláusula SELECT, con una condición
obtener el número de envíos de la parte P2
SELECT COUNT (*)
FROM
SP
WHERE P# = ‘P2’ ;
Resultado
4
6.4.4 función de agregados en la cláusula SELECT, con una condición
obtener la cantidad suministrada de la parte P2
SELECT SUM (CANT)
FROM SP
WHERE P# = ‘P2’;
Resultado
------1000
6.4.5 Empleo de GROUP BY (agrupar por)
El ejemplo 6.4.4 mostró cómo puede calcularse la cantidad total suministrada de una
parte especifica. Pero vamos a suponer que deseamos calcular la cantidad total
suministrada de cada parte: es decir, para cada parte suministrada, obtener el número de
parte y la cantidad total enviada de esa parte.
SELECT P# , SUM (CANT)
FROM SP
GROUP BY P#;
Resultado:
P#
P1
P2
P3
P4
P5
P6
-----600
1000
400
500
500
100
Explicación: el operador GROUP BY reorganiza en el sentido lógico la tabla
representada por la cláusula FROM formando particiones o grupos, de manera que
dentro de un grupo dado todas las filas tengan el mismo valor en el campo de
GROUP BY. (Desde luego, tal agrupamiento es meramente conceptual; la tabla no se
reorganiza en la base de datos) En el ejemplo, la tabla SP se agrupa de manera tal que
un grupo contiene todas las filas de la parte P1, otro contiene todas las filas de la parte
P2, etcétera. En seguida se aplica la cláusula SELECT a cada grupo de la tabla dividida
( y no a cada fila de la tabla original) cada expresión en la cláusula SELECT debe
producir un solo valor por grupo; es decir, puede ser el campo de GROUP BY mismo (
o quizá alguna expresión aritmética que implique a ese campo), o un literal, o una
función como SUM, la cual opera sobre todos los valores de un campo dado entero de
un grupo y los reduce a un solo valor.
Adviértase que GROUP BY no implica ORDER BY (ordenar por); si queremos
presentar el resultado del ejemplo anterior ordenado por P# , deberemos especificar
también la cláusula ORDER BY P# ( después de la cláusula GROUP BY).
Una tabla se puede agrupar según cualquier combinación de sus campos. En la
sección 6.7 se presenta un ejemplo de la agrupación según más de un campo.
6.4.6 Empleo de HAVING (con)
Obtener los números de todas las partes suministradas por más de un proveedor.
SELECT P#
FROM SP
GROUP BY P#
HAVING COUNT(*) > 1;
Resultado
P#
P1
P2
P4
P5
HAVING es a los grupos lo que WHERE es a las filas ( si se especifica HAVING,
deberá haberse especificado también GROUP BY). En otras palabras HAVING (con)
sirve para eliminar grupos de la misma manera como WHERE (donde) sirve para
eliminar filas. Las expresiones en una cláusula HAVING deben producir un solo valor
por grupo.
6.5
CARACTERISTICAS AVANZADAS
En esta sección ilustraremos diversas características de la proposición SELECT. A falta
de un término mejor, llamaremos avanzadas a esas características, aunque en realidad
no son más complejas que algunos de los conceptos ya analizados en las ultimas tres
secciones: de hecho algunas de ellas, - sobre todo EXISTS (véanse los ejemplos 6.5.7 a
6.5.10) – son fundamentales; con todo, quizá se les encuentre con menor frecuencia en
la práctica que las características analizadas en las secciones 6.2 a 6.4. por tal motivo, el
lector puede optar por dejar a un lado esta sección en una primera lectura.
6.5.1 recuperación de datos con LIKE (como)
Obtener todas las partes cuyos nombres comiencen con la letra B.
SELECT P.*
FROM P
WHERE P.NOMBRE LIKE ‘B%’;
Resultado:
P#
P3
P4
PNOMBRE
Birlo
Birlo
COLOR
azul
rojo
PESO CIUDAD
17
Roma
14
Londres
En general, una condición LIKE (como) adopta la forma
Columna LIKE literal-de-cadena
Donde “columna” debe designar una columna de tipo de cadena ( CHAR o VARCHAR
o GRAPHIC o VARGRAPHIC). Para un registro dado, la condición se cumple si el
valor dentro de la columna designada sigue el patrón especificado con “literal”. Los
caracteres dentro de “literal” se interpretan de esta manera:



El carácter “_” (subrayado) representa cualquier carácter individual.
El carácter “%” ( por ciento) representa cualquier secuencia de n caracteres (donde
n puede ser cero)
Todos los demás caracteres se representan por si mismos.
En el ejemplo, entonces, la proposición SELECT extraerá registros de la tabla P en los
cuales el valor de PNOMBRE comience con la letra B seguida de cualquier secuencia
de cero o más caracteres.
He aquí algunos ejemplos más de LIKE ( y su opuesto, NOT LIKE (diferente de));
DOMICILIO LIKE ‘%LIMA%’- Se cumplirá si domicilio contiene la cadena “LIMA”
En cualquier posición.
S# LIKE ‘S_’
- Se cumplirá si S# tiene una longitud de tres caracteres
Y el primero es una S
PNOMBRE LIKE ‘%c___
- Se cumplirá si PNOMBRE tiene una longitud de
cuatro o más caracteres y el tercero antes del ultimo es
una c.
CIUDAD NOT LIKE ‘%E%’ - Se cumplirá si CIUDAD no tiene una E
6.5.2 Recuperación de datos que incluyen NULL (nulo)
Vamos a suponer para este ejemplo que la situación del proveedor S5 tiene un valor
nulo, en vez de 30. Obtener los números de los proveedores cuya situación es mayor
que 25.
SELECT S#
FROM S
WHERE SITUACIÓN >25
Resultado:
S#
S3
El proveedor S5 no cumple la condición. Como se menciono en la sección 5.2,
cuando al evaluar una condición se compara un nulo con cualquier otro valor, sea cual
sea el operador de comparación empleado, el resultado de la comparación nunca se
considera verdadero, aún cuando el otro valor también sea nulo.
En otras palabras si SITUACIÓN tiene un valor nulo, ninguna de las siguientes
comparaciones resulta verdadera:
SITUACIÓN >25
SITUACIÓN <= 25
SITUACIÓN = 25
SITUACIÓN <> 25
SITUACIÓN = NULL /* Esta sintaxis no es legal. Ver lo que sigue */
SITUACIÓN <> NULL /* Ésta tampoco
*/
Se incluye una condición especial con la forma
Nombre – columna IS [ NOT] NULL
Para detectar la presencia o ausencia de nulos. Por ejemplo:
SELECT S#
FROM S
WHERE SITUACIÓN IS NULL
Resultado:
S#
S5
La sintaxis “SITUACION = NULL” no esta permitida, por que nada, ni siquiera un nulo
se considera igual a otro nulo.
6.5.3 Recuperación de datos con subconsulta.
Obtener los nombres de los proveedores que suministran la parte P2
SELECT SNOMBRE
FROM
S
WHERE S in
( SELECT S#
FROM SP
WHERE P# = ‘P2’ );
Resultado :
SNOMBRE
Salazar
Jaimes
Bernal
Corona
Explicación: una subconsulta es (en términos informales) una expresión
SELECT … FROM… GROUP BY …HAVING anidada dentro de otra expresión del
mismo tipo. Las subconsultas se utilizan por lo regular para representar el conjunto de
valores en el cual se realizará una búsqueda mediante una “condición IN (en)“, como
puede verse en el ejemplo. Para evaluar la consulta completa, el sistema evalúa primero
la subconsulta anidada (por lo menos desde el punto de vista conceptual). Esa
subconsulta produce como resultado el conjunto de números de proveedor de los
proveedores que suministran la parte P2, o sea el conjunto (S1,S2,S3,S4). Así, la
consulta original equivale a esta otra consulta mas sencilla:
SELECT NOMBRE
FROM
S
WHERE S# IN (‘S1’,’ S2’,’S3’, ‘S4’);
La cláusula WHERE esta en forma más sencilla si cumple si y sólo si S# tiene
uno de los valores S1,S2,S3,S4; por lo tanto, el resultado final es el que se mostró antes.
Adviértase, por cierto, que el problema original -“ obtener los nombres de los
proveedores que suministran la parte P2“ – se puede expresar también como una
consulta de reunión así:
SELECT
FROM
WHERE
AND
S,S.NOMBRE
S,SP
S.S# = SP.S#
SP.P# = ‘P2’;
Explicación: la reunion y de S y SP con base en números de proveedor se compone de
una tabla de doce filas (una por cada fila de SP), en la cual cada fila se compone de la
fila correspondiente de SP ampliada con los valores SNOMBRE, SITUACIÓN Y
CIUDAD del proveedor identificado por el valor S# de esa fila. de estas doce filas,
cuatro corresponden a la parte P2; de modo que el resultado final se obtiene extrayendo
los valores SNOMBRE de esas cuatro filas.
Las dos formulaciones de la consulta original – una mediante subconsulta y la
otra mediante reunión – son igualmente correctas. La elección de una u otra será
cuestión sólo del gusto del usuario (excepto que –según lo avanzado del optimizador del
sistema – una de las dos podría representar mejor desempeño; en un sistema ideal, desde
luego, el usuario no tendría que preocuparse por ese tipo de consideraciones).
6.5.4 subconsulta con varios niveles de anidamiento
Obtener los nombres de los proveedores que suministren por lo menos una parte roja.
SELECT SNOMBRE
FROM
S
(WHERE S# IN
SELECT S#
FROM SP
(WHERE P#
FROM P
WHERE COLOR =’ROJO’));
Resultado: SNOMBRE
Salazar
Jaimes
Corona
Las subconsultas pueden estar anidadas a cualquier profundidad. Ejercicio: presentar
una formulación de reunión equivalente para esta consulta.
6.5.5 Subconsulta con operador de comparación distinto de IN
Obtener los números de los proveedores situados en la misma ciudad que el proveedor
S1.
SELECT S#
FROM S
WHERE CIUDAD =
(SELECT CIUDAD
FROM S
WHERE S# = ‘S1’);
Resultado:
S#
S1
S4
Si el usuario sabe que el resultado de una subconsulta determinada será
exactamente un valor, puede utilizar un operador de comparación escalar sencillo (como
0,>,etcétera) en vez del IN acostumbrado.
6.5.6 función de agregados en una subconsulta
obtener los números de los proveedores cuya situación sea menor que el valor máximo
actual de situación en la tabla 5.
SELECT SNOMBRE
FROM
S
WHERE SITUACION <
(SELECT MAX (SITUACION)
FROM S);
Resultado:
S#
S1
S2
S4
6.5.7 consulta con EXISTS (existe).
Obtener los nombres de los proveedores que suministran la parte P2 ( igual que en el
ejemplo 6.5.3)
SELECT SNOMBRE
FROM
S
WHERE EXISTS
(SELECT
FROM SP
WHERE S# = S.S#
AND
P# = ´P2´);
Explicación: EXISTS (existe) representa aquí el cuantificador existencial, la expresión
“EXISTS ( SELECT … FROM…)” da como resultado un valor verdadero si y sólo si el
resultado de evaluar la subconsulta “SELECT …FROM …” no es el conjunto vacío; en
otras palabras, si y sólo si existe un registro en la tabla FROM de ese “ SELECT
…FROM …”, adviértase cómo la condición WHERE dentro de la expresión EXISTS
hace referencia a la tabla FROM del nivel externo de la consulta; lo hace a través de un
nombre de columna calificado de esa manera explícita (S.S#, en el ejemplo).
Para entender como funciona el ejemplo, considérese en orden cada valor
SNOMBRE, y véase si hace que se cumpla la prueba de existencia. Vamos a suponer
que el primer valor de SNOMBRE es “Salazar” ( de modo que el valor correspondiente
de S# es S1). ¿ Esta vacío el conjunto de los registros SP en los cuales S# es igual a S1
y P# es igual a P2, de manera que “Salazar” deberá ser uno de los valores extraídos. Lo
mismo hace con los valores de SNOMBRE. Así pues, otra forma de enunciar la
consulta podría ser: “seleccionar nombres de proveedores tales que exista un envío que
relacione esos proveedores con la parte P2”.
Aunque este ejemplo en particular solo ilustra otra manera de formular una
subconsulta para un problema que ya sabemos como manejar (mediante una reunión o
bien una subconsulta), la construcción EXISTS es en realidad una de las más básicas y
generales de todo el lenguaje de SQL. (Adviértase en particular que cualquier consulta
en la cual se utilice IN siempre podrá utilizar a modo EXIST, lo opuesto, en cambio, no
se cumple.) la forma negada, NOT EXISTS (no existe) es importante sobre todo en
cierto tipo de consultas.
6.5.8 Consulta con NOT EXISTS
Obtener los nombres de los proveedores que suministren la parte P2 ( lo inverso al
ejemplo anterior).
SELECT SNOMBRE
FROM S
WHERE NOT EXISTS
( SELECT *
FROM SP
WHERE S# = S.S#
AND
P# = ‘P2’);
Resultado
SNOMBRE
Aldana
Otra forma de enunciar la consulta es: ” Seleccionar nombres de los proveedores
tales que no exista un envío que relacione a esos proveedores con la parte P2”. Cabe
señalar que esta consulta sería equivalente a otra expresada en términos de la forma
negada de IN, a saber:
SELECT SNOMBRE
FROM S
WHERE S# NOT IN
(SELECT S
FROM SP
WHERE P# = P2);
6.5.9 Consulta con NOT EXISTS
Obtener los nombres de los proveedores que suministren todas las partes
SELECT SNOMBRE
FROM S
WHERE NOT EXISTS
(SELECT *
FROM P
WHERE NOT EXIST
(SELECT *
FROM SP
WHERE S# = S.S#
AND P# = P.P#));
Resultado
SNOMBRE
Salazar
La consulta podría enunciarse también así: “obtener los nombres de los
proveedores tales que no exista una parte que no suministren”. Adviértase que esta
consulta no podría expresarse usando la forma negada de IN.
6.5.10 Consulta con NOT EXISTS.
Obtener los números de los proveedores que suministran por lo menos todas las partes
suministradas por el proveedor S2.
Una forma de encarar este problema más bien complejo es descomponerlo en
una serie de consultas más simples y manejarlas una por una. Así, podemos encontrar
primero el conjunto de números de parte de las partes suministradas por el proveedor
S2;
SELECT
P#
FROM SP
WHERE S# = ‘S2’;
Resultado:
P#
P1
P2
Si utilizamos CREATE TABLE e INSERT ( lo cual analiza en forma detallada
la siguiente sección), es posible guardar este resultado en una tabla de la base de datos
digamos la tabla TEMP, ahora podemos encontrar el conjunto de números de
proveedores que suministran todas las partes incluidas en TEMP.
SELECT DISTINCT S#
FROM SP SPX
WHERE NOT EXISTS
(SELECT
*
FROM TEMP
WHERE NOT EXISTS
(SELECTS *
FROM SP SPY
WHERE SPY.S# = SPX.S#
AND SPY.P# = TEMP.P#));
Resultado:
S#
S1
S2
Puede notarse que esta consulta difiere de la del ejemplo 6.5.9 en la necesidad de
utilizar por lo menos una variable de recorrido explícita, pues estamos extrayendo
valores de S# de la tabla SP y no valores de SNOMBRE de la tabla S y por esta razón
es preciso poder hacer dos referencias simultáneas pero distintas a la tabla SP.
Ahora ya podemos desechar la tabla TEMP.
Muchas veces es conveniente manejar consultas complejas con éste método de
paso por paso, pues se facilita la comprensión. Pero desde luego es posible también
expresar toda la consulta como una sola proposición SELECT, con lo cual resulta del
todo innecesaria la tabla TEMP.
SELECT DISTINCT S#
FROM SP SPX
WHERE NOT EXISTS
( SELECT *
WHERE S# = ‘P2’
AND NOT EXISTS
( SELECT *
FROM SP SPZ
WHERE SPZ.S# = SPX.S#
AND SPZ.P# = SPY.P#));
6.5.11 Consulta con unión
Obtener todos los números de las partes que pesen más de 16 libras, o sean
suministradas por el proveedor P2 ( o las dos cosas)
SELECT P#
FROM
P
WHERE PESO>16
UNION
SELECT P#
FROM SP
WHERE S# = ‘P2’;
Resultado
-----P1
P2
P3
P6
UNION es el operador de unión de la teoría de conjuntos tradicional. En otras palabras,
A UNION B ( donde A y B son conjuntos) es el conjunto de todos los objetos de x tales
que x es miembro de A o x es miembro e B ( o las dos cosas). Las filas repetidas
siempre se eliminan del resultado de una UNION.*
6.6
OPERACIONES DE ACTUALIZACIÓN
El lenguaje de manipulación de SQL, incluye tres operaciones de actualización:
UPDATE(actualizar en el sentido de alterar o modificar), DELETE (eliminar) e
INSERT (insertar).
UPDATE (actualizar)
Formato general:
UPDATE
Tabla
SET
campo = expresión-escalar
[campo = expresión-escalar] …
WHERE
[condición];
Todos los registros de tabla que satisfagan condición serán modificados de
acuerdo con las asignaciones (“ campo = expresión-escalar) de la cláusula SET
(establecer).
6.6.1 Modificación de un solo registro.
Cambiar a amarillo el color de la parte P2, aumentar su peso en cinco e indicar que su
ciudad es “desconocida” (NULL)
UPDATE P
SET COLOR=”.amar”
PESO=PESO+5,
CIUDAD= NULL
WHERE P# = ‘ P2’;
Para cada uno de los registros que se van a modificar ( es decir, cada registro que
satisface la condición WHERE, o todos los registros si se omiten la cláusula WHERE),
Las referencias en la cláusula SET a campos dentro de ese registro representan los
valores que tiene esos campos antes de ejecutarse cualquiera de las asignaciones de esa
cláusula SET.
6.6.2 Modificación de varios registros.
Duplicar la situación de todos los proveedores situados en Londres
UPDATE S
SET
SITUACION = 2*SITUACIÓN
WHERE
CIUDAD = “LONDRES”;
6.6.3 Modificación con subconsulta.
Poner en ceros la cantidad enviada por todos los proveedores de Londres.
UPDATE SP
SET
CANT = 0
WHERE “Londres” =
(SELECT CIUDAD
FROM S
WHERE S.S# = SP.S#);
6.6.4 Modificación de varias tablas.
Cambiar el número de proveedor con S2 a S9
UPDATE
SET
WHERE
UPDATE
SET
WHERE
S
S# = “S9”
S# = “S2”;
SP
S# = “S9”
S# = “S2”;
Como por definición las operaciones UPDATE (y DELETE e INSERT) modifican la
base de datos, existe siempre la posibilidad de alterar en alguna forma incorrecta i violar
con ello la integridad de los datos. El ejemplo ilustra este punto:
La primera posición UPDATE (si fuera aceptada) haría inconsistente a la base de datos.
Incluiría algunos envíos para los cuales no existiría el proveedor correspondiente.
Y permanecería en ese estado en tanto no se ejecutará la segunda proposición UPDATE
(en este ejemplo pasamos por alto el hecho de que, en la practica, DB2 rechazaría de
todos modos la primera modificación, precisamente por este problema de integridad.)
De hecho, el ejemplo ilustra un tipo muy especifico de violación de la integridad, a
saber, la violación de la integridad referencial. La integridad referencial se analiza en
forma detallada en el capitulo 12.
DELETE (ELIMINAR)
Formato general:
DELETE
FROM TABLA
{ WHERE CONDICIÓN};
Se eliminaran todos los registros de “TABLA” que satisfagan “CONDICION”.
6.6.5 Eliminación de un solo registro
Eliminar el proveedor S5.
DELETE
FROM S
WHERE S# = ‘S5’;
En general, la eliminación de un proveedor puede llegar a provocara una violación de la
integridad referencial (si la base de datos incluye envíos de ese proveedor; comparesé
con el ejemplo 6.6.4). una vez más, la integridad referencial se analiza en el capitulo 12.
6.6.6 Eliminación de varios registros.
Eliminar todos los envíos cuya cantidad sea mayor de 300.
DELETE
FROM SP
WHERE CANT > 300;
6.6.7 Eliminación de varios registros.
Eliminar todos los embarques.
DELETE
FROM SP;
SP es todavía una tabla conocida (“ eliminar todos los registros” no equivale a desechar
(DROP) la tabla), pero ahora esta vacía.
6.6.8 Eliminación con subconsulta.
Eliminar todos los envíos de proveedores situados en Londres.
DELETE
FROM SP
WHERE “Londres” =
(SELECT CIUDAD
FROM S
WHERE S.S# = SP.S# );
INSERT (INSERTAR)
Formato general:
INSERT
INTO TABLA [(CAMPO[CAMPO]…)]
VALUES (Literal[, literal]…);
O bien
INSERT
INTO TABLA [(campo[, campo]…)]
Subconsulta;
En el primer formato se inserta en “TABLA” una fila con los valores especificados en
los campos especificados ( el iésimo literal en la lista de literales corresponde al iésimo
campo en la lista de campos). En el segundo formato, se valúa la subconsulta y se
inserta una copia del resultado ( casi siempre varias filas) en “TABLA”; la iésima
columna de ese resultado corresponde a iésimo campo en la lista de campos. En ambos
casos, omitir la lista de campos equivale a especificar una lista con todos los campos de
la tabla en orden de izquierda a derecha ( como en caso de “SELECT *”).
6.6.9 Inserción de un solo registro
Añadir la parte P7 (ciudad, Atenas, Peso, 24; nombre y color desconocidos por ahora)
A la tabla P.
INSERT
INTO P (P#,CIUDAD,PESO)
VALUES (“P7”,”Atenas”,24);
Se crea un nuevo registro de parte con el número de parte, la ciudad y el peso
especificados y con nulos en las posiciones del nombre y color.
(suponemos, en este ejemplo, que estos campos no se definieron NOT NULL en la
proposición CREATE TABLE con la cual se creó la tabla P.)
el orden de izquierda a derecha con el cual se nombrar los campos en la proposición
INSERT no es por fuerza el mismo con el que se especificaron el la proposición
CREATE TABLE (o ALTER TABLE).
6.6.10 Inserción de un solo registro, omitiendo nombres de campos.
Añadir la parte P8 ( nombre, cadena, color, rosa, peso, 14, ciudad, Niza)
A la tabla P
INSERT
INTO P
VALUES ( ‘P8’ ,’cadena’, ‘rosa’, 14, ‘Niza’);
Omitir la lista de campos equivale a especificar una lista con todos los campos de la
tabla, en el orden de izquierda a derecha con el cual se definieron en la proposición
CREATE TABLE. Como en el caso de “SELECT *”, esta forma corta quizá sea
conveniente en SQL interactivo, pero puede ser peligrosa en SQL embebido ( o sea,
SQL dentro de un programa de aplicación) por que la lista de campos supuesta puede
cambiar si el programa se religa y a cambiado entre tanto la definición de la tabla.
6.6.11 Inserción de un solo registro.
Insertar un nuevo envío con número de proveedor S20, número de parte P20 y cantidad
1000.
INSERT
INTO SP (S#, P#, CANT)
VALUES ( ‘S20’,’ P20’, 1000);
Al igual que UPDATE y DELETE, INSERT puede provocar problemas de integridad
referencial ( si no existen controles adecuados; Véase el capitulo 12).
En el presente caso, DB2 rechazara el intento de inserción, por que no existe el
proveedor S20 en la tabla S ni la parte P20 en la tabla.
6.6.12 Inserción de varios registros.
Para cada parte suministrada, obtener el número de parte y la cantidad total
suministrada, y guardar el resultado en la base de datos.
CREATE TABLE TPMP
( P# CHAR (6) NOT NULL,
CANTTOTAL
INTEGER NOT NULL,
PRIMARY KEY ( P#);
CREATE UNIQUE INDEX XT ON TEMP ( P#);
INSERT
INTO TEMP ( P#, CANTTOTAL)
SELECT P#, SUM (CANT)
FROM SP
GROUP PY P#
Se ejecuta la proposición SELECT, igual que una selección ordinaria, pero el resultado ,
en vez de presentarse al usuario, se copia a la tabla TEMP. Ahora el usuario puede
hacer lo que desee con esa copia: consultarla, imprimirla y hasta modificarla; ninguna
de esas operaciones afectara en absoluto los datos originales. Cuando ya no se necesite,
la tabla TEMP podrá desecharse.
DROP TABLE TEMP;
El ejemplo anterior es una ilustración perfecta de la importancia de la propiedad de
cerradura en los sistemas relacionales. El ejemplo funciona precisamente porque el
resultado de una proposición SELECT es otra tabla. No resultaría si el resultado fuera
algo distinto.
Por cierto, no es indispensable que la tabla objetivo este vacía antes de efectuar una
inserción de varios registros, aunque sí lo esta en el ejemplo anterior, si no esta vacía los
nuevos registros simplemente se agregarán a los ya presentes.
6.7
COMENTARIOS FINALES.
Ya hemos presentado todas las características de la proposiciones de manipulación de
datos de SQL que pensamos ilustrar en este libro. En términos específicos hemos
descrito:










La cláusula SELECT ( seleccionar) básica, incluyendo el empleo de DISTINC
(distinto), literales, y expresiones escalares, y “SELECT *”
La cláusula FROM (de), incluyendo el empleo de variables de recorrido
El empleo de ORDER BY (ordenar por) para ordenar la tabla de resultado
La cláusula WHERE (donde), incluyendo:
- operaciones escalares de comparacion =,<>, >, <, <=, >=
- condiciones de reunión
- operadores booleanos AND,OR,NOT
Las funciones de agregados COUNT(cuenta), SUM (suma), AVG (promedio),
MAX(máximo), MIN (mínimo), y el empleo de la cláusulas GROUP BY (agrupar
por) y HAVING (con)
Las condiciones especiales [NOT] LIKE…([no] como e IS [NOT] NULL ([no] es
nulo)
El empleo de subconsultas y el operador de comparación [NOT] IN ([no]) en)
Empleo del cuantificador existencial EXISTS (existe) (sobre todo la forma negada
NOT EXISTS (no existe))
El operador UNION (unión)
Las proposiciones de actualización UPDATE (modificar), DELETE ( eliminar),
e
INSERT (insertar)
Cabe señalar que la existencia de sólo cuatro proposiciones de DML en SQL es una de
las razones de la relativa facilidad del empleo de ese lenguaje. Y el hecho de que sólo
haya cuatro operaciones de este tipo es una consecuencia de la sencillez de la estructura
de datos relacional. Como se explico en el capitulo 4, toda la información de una base
de datos relacionada se representa de la misma manera, a saber, como valores
dispuestos de columnas dentro de filas pertenecientes a tablas. Como sólo hay una
forma de representar cualquier cosa, sólo se requiere un operador para cada una de las
cuatro funciones básicas de manipulación (recuperar, modificar, insertar, eliminar). En
cambio en los sistemas basados en estructuras de datos más complejas requieren en
principio 4n operaciones de este tipo, donde n es el número de formas de representar
datos en ese sistema. Por ejemplo en los sistema derivados de CODASYL, donde los
datos se pueden representar ya sea como registros o como ligas entre registros, lo más
común es encontrar una operación STORE (almacenar) para crear un registro y una
operación CONNECT (conectar) para crear una liga; una operación ERASE para
eliminar un registro y una operación DISCONNECT (desconectar) para eliminar una
liga,; una operación MODIFY (modificar) para alterar un registro y una operación
RECONNECT (reconectar) para modificar una liga, Etc.
Para concluir, presentamos un ejemplo muy rebuscado para ilustrar como pueden
utilizarse muchas de las características de SQL analizadas en este capitulo. Tambien
presentamos un algoritmo conceptual para evaluar una proposición de este tipo.
Adviértase que en cierto sentido SELECT es la más fundamental de las cuatro
operaciones de DML, pues las otras tres deben ir siempre precedidas –al menos en
forma implícita, si no explícita- por una selección apropiada. Por ejemplo, en el caso de
DELETE el sistema debe ejecutar antes una selección implícita para localizar los datos
que debe eliminar.
Ejemplo:
Para todas las partes rojas y azules tales que la cantidad total suministrada sea mayor o
igual que 350 (excluyendo del total todos los envíos cuyas cantidades sean menores o
iguales a 200), obtener el número de parte, el peso en gramos, el color y la cantidad
máxima suministrada de esa parte; y clasificar el resultado en orden descendente por
número de parte dentro de un orden ascendente según esa escala máxima.
SELECT P.P#, ‘peso en gramos=’, P.PESO *454, P.COLOR,
‘ cant.máx.embarcada=’, MAX (SP.CANT)
FROM P, SP
WHERE P.P# = SP.P#
AND (P.COLOR= ‘rojo’ OR P.COLOR = ’azul ’)
AND SP.CANT > 200
GROUP BY P.P# , P.PESO, P.COLOR
HAVING SUM (CANT) >350
ORDER BY 6, P.P# DESC;
Resultado:
P#
P1
P5
P3
peso en gramos = 5448
peso en gramos = 5448
peso en gramos = 7718
COLOR
rojo cant. Máx enviada = 300
azul cant. Máx enviada = 400
azul cant. Máx enviada = 400
Debe entenderse que el algoritmo recién descrito se presenta como una explicación
puramente conceptual de la forma como se evalúa la proposición SELECT
(seleccionar). Sin duda es correcta, en cuanto a que se producirá con certeza el resultado
correcto; de hecho, puede tomarse como definición de cual debe ser el resultado. No
obstante si se le ejecutara en realidad, lo más probable es que fuera bastante ineficiente.
Por ejemplo, no sería conveniente, por razones de espacio de almacenamiento y también
el tiempo de ejecución, la construcción del producto cartesiano sugerida en el paso 1.
Consideraciones como ésta son precisamente las que justifican la necesidad de un
optimizador de sistema relacionales. De hecho, el objetivo del optimizador puede
definirse como encontrar un procedimiento que produzca el mismo resultado producido
por el algoritmo conceptual antes descrito pero que sea más eficiente en términos de
espacio o de tiempo ( o de ambos, si es posible).
Por último, acerca del ejemplo de consulta en sí: la proposición SELECT mostrada es
desde luego bastante compleja, pero pensemos en todo el trabajo que realiza. Un
programa convencional para efectuar la misma tarea, escrito en el lenguaje de COBOL,
podría ocupar con facilidad nueve páginas, en vez de solo nueve renglones, y la labor
requerida para poner en funcionamiento ese programa sería bastante mayor que la
implicada en la construcción de la versión de SQL mostrada. En la practica, por
supuesto, la mayor parte de las consultas serán de todos modos más sencillas que ésta.
Ejercicios.
Todos los ejercicios utilizan la base de datos de proveedores, partes y proyectos (véanse
los ejercicios del capitulo 5). En casi todos se pide al lector que escriba una proposición
o conjunto de proposiciones en SQL para la operación indicada. Por conveniencia
repetimos aquí la estructura de la base de datos.
S ( S#, SNOMBRE, SITUACION, CIUDAD)
P (P#, PNOMBRE, COLOR,PESO,CIUDAD)
J (J#, JNOMBRE,CIUDAD)
SPJ (S#, P#, J#, CANT)
Dentro de cada subsección, los ejercicios se presentan en orden aproximado de
dificultad creciente. Se recomienda intentar al menos algunos de los más difíciles en
cada grupo. Los números 34 a40 son bastante difíciles.
Consultas sencillas:
6.1 Obtener los detalles completos de los proyectos.
6.2 Obtener los detalles completos de los proyectos de Londres
6.3 Obtener los números de los proveedores que suministran partes al proyecto J1 ,
ordenados por el número del proveedor.
6.4 Obtener todos los envíos en los cuales la cantidad está en el intervalo de 300 a 750
inclusive.
6.5 Obtener una lista de todas las combinaciones parte-color / parte-ciudad, eliminando
todas las parejas color / ciudad repetidas.
Reuniones.
6.6 Obtener todas las tripletas número de proveedor /número de parte/ número de
proyecto tales que el proveedor, la parte y el proyecto indicados estén en la misma
ciudad.
6.7 Obtener todas las tripletas número de proveedor /número de parte/ número de
proyecto tales que el proveedor, la parte y el proyecto indicados no estén todos
cosituados.
6.8 obtener todas las tripletas número de proveedor /número de parte/ número de
proyecto tales que el proveedor, la parte y el proyecto indicados estén todos en diferente
ciudad.
6.9 Obtener los números de las partes suministradas por algún proveedor de Londres.
6.10 Obtener los números de las partes suministradas por algún proveedor de Londres a
un proyecto en Londres.
6.11 obtener todas las parejas de nombres de ciudades tales que un proveedor de a
primera ciudad suministre partes a un proyecto en la segunda ciudad.
6.12 obtener los números de las partes suministradas a un proyecto por un proveedor
situado en la misma ciudad que en el proyecto.
6.13 obtener los números de los proyectos a los cuales suministra partes por lo menos
un proveedor situado en diferente ciudad.
6.14 obtener todas las parejas de números de partes tales que algún proveedor
suministre dos partes indicadas.
FUNCIONES AGREGADAS
6.15 obtener el número total de proyectos a los cuales suministra partes el proveedor S1
6.16 obtener la cantidad total de la parte P1 suministrada por el proveedor S1
6.17 para cada parte suministrada a un proyecto, obtener el número de parte, el número
de proyecto y la cantidad total correspondiente.
6.18 obtener los números de las partes suministradas a algún proyecto tales que la
cantidad promedio suministrada sea mayor que320.
DIVERSAS
6.19 obtener todos los envíos para los cuales la cantidad no sea nula
6.20 obtener número de proyecto y ciudades en los cuales la segunda letra del nombre
de la ciudad sea una “o”.
6.21 obtener los nombres de los proyectos a los cuales suministra partes el proveedor S1
6.22 Obtener los colores de las partes suministradas por el proveedor S1
6.23 Obtener los números de las partes suministradas a cualquier proyecto en Londres
6.24 Obtener los números de los proyectos donde se utilice al menos una de las partes
suministradas por el proveedor S1.
6.25 obtener los números de los proveedores que suministren por lo menos unas de las
partes suministradas por al menos uno de los proveedores que suministran por lo menos
una parte roja.
6.26 obtener los números de proveedores cuya situación sea inferior a la del proveedor
S1.
6.27 obtener los números de los proyectos cuya ciudad sea la primera en la lista
alfabética de las ciudades donde hay proyectos.
6.28 Obtener los números de los proyectos a los cuales se suministre la parte P1 en una
cantidad promedio mayor que la cantidad máxima en la cual se suministra alguna parte
al proyecto J1
6.29 Obtener los números de los proveedores que suministren la parte P1 a algún
proyecto en una cantidad mayor que la cantidad promedio enviada de la parte P1 para
ese proyecto.
EXISTS (existe)
6.30 Repetir el ejercicio 6.23 utilizando exists en la solución.
6.31 repetir el ejercicio 6.24 utilizando exists en la solución.
6.32 obtener los números de los proyectos a los cuales no suministra ninguna parte roja
ninguno de los proveedores de Londres.
6.33 Obtener los números de los proyectos para los cuales S1 es el único proveedor
6.34 Obtenr los números de las partes suministradas a todos los proyectos en nombres.
6.35 Obtener los números de los proveedores que suministren la misma parte a todos los
proyectos.
6.36 Obtener los números de los proyectos a los cuales se suministren por lo menos
todas las partes suministradas por el proveedor S1.
En los siguientes cuatro ejercicios (6.37 a 6.40) convertir la proporción SELECT de
SQL mostrada a su equivalente en español.
6.37
SELECT DISTINC J#
FROM SPJ SPJX
WHERE NOT EXISTS
(SELECT *
FROM SPJ SPJX
WHERE SPJX.J# = SPJX.J#
AND NOT EXISTS
(SELECT *
FROM SPJ SPJZ
WHERE SPJZ.P# = SPJY.P#
AND SPJZ.S# = ‘S1’ ));
6.38
SELECT DISTINC J#
FROM SPJ SPJX
WHERE NOT EXISTS
(SELECT *
FROM SPJ SPJX
WHERE EXISTS
(SELECT *
FROM SPJ SPJA
WHERE SPJA.S# = ‘S1’
AND SPJA.P# = SPJY.P#)
AND NOT EXISTS
( SELECT *
FROM SPJ SPJB
WHERE SPJB.S# = ‘S1’
AND SPJB.P# = SPJY.P#
AND SPJB.J# = SPJX.J#));
6.39
SELECT DISTINC J#
FROM SPJ SPJX
WHERE NOT EXISTS
(SELECT *
FROM SPJ SPJY
WHERE EXISTS
(SELECT *
FROM SPJ SPJA
WHERE SPJA.P# = SPJY.P#
AND SPJA.J# = SPJX.J#)
AND NOT EXISTS
(SELECT *
FROM SPJ SPJB
WHERE SPJB.S# = ’S1’
AND SPJB.P# = SPJY.P#
AND SPJB.J# = SPJX.J#));
6.40
SELECT DISTINC J#
FROM SPJ SPJX
WHERE NOT EXISTS
(SELECT *
FROM SPJ SPJY
WHERE EXISTS
(SELECT *
FROM SPJ SPJA
WHERE SPJA.S# = SPJY.S#
AND SPJA.P# IN
(SELECT P#
FROM P
WHERE COLOR = ’rojo’)
AND NOT EXISTS
(SELECT *
FROM SPJ SPJB
WHERE SPJB.S# = SPJY.S#
AND SPJB.J# = SPJX.J#)));
UNION
6.41 Construir una lista ordenada de todas las ciudades en las cuales este situado por lo
menos un proveedor, una parte o un proyecto.
6.42 Mostrar el resultado de la siguiente selección:
SELECT P.COLOR
FROM P
UNION
SELECT P.COLOR
FROM P.
OPERACIONES DE ACTUALIZACION
6.43 Cambiar a gris el color de todas las partes rojas
6.44 Eliminar todos los proyectos para los cuales no haya envíos.
6.45 Insertar un nuevo proveedor (S10) en la tabla S. El nombre y la ciudad son Salazar
y Nueva York, respectivamente; la situación no se conoce todavía.
6.46 Construir una tabla con los números de las partes suministradas ya sea por un
proveedor de Londres o un proyecto en Londres.
6.47 Construir una tabla con los números de los proyectos situados en Londres a los
cuales suministren partes algún proveedor de Londres.
RESPUESTA A EJERCICIOS SELECTOS.
Las siguientes soluciones no son por fuerza las únicas posibles.
6.1
SELECT J#, JNOMBRE, CIUDAD
FROM J;
6.2
SELECT J#, JNOMBRE, CIUDAD
FROM J
WHERE CIUDAD = ‘Londres’;
6.3
SELECT DISTINC S#
FROM SPJ
WHERE J# = ‘J1’
ORDER BY S#;
6.4
SELECT S#, P#, J# CANT
FROM SPJ
WHERE CANT > = 300
AND CANT <= 750
6.5
SELECT DISTINC COLOR, CIUDAD
FROM P;
6.6
SELECT S#, P#, J#
FROM S, P, J
WHERE S.CIUDAD=P.CIUDAD
AND P.CIUDAD= J.CIUDAD;
6.7
SELECT S#, P#, J#
FROM S,P,J
WHERE NOT
(S.CIUDAD = P.CIUDAD AND P.CIUDAD = J.CIUDAD );
6.8
SELECT S#, P#, J#
FROM P,J
WHERE S.CIUDAD <> P.CIUDAD
AND P.CIUDAD <> J.CIUDAD
AND J.CIUDAD <> S.CIUDAD;
6.9
SELECT DISTINC
FROM SPJ, S
WHERE SPJ.S# = S.S#
AND CIUDAD =’ LONDRES
6.10
SELECT DISTINC P*
FROM SPJ, S, J
WHERE SPJ. S# = S.S#
AND SPJ.J# = J.J#
AND S.CIUDAD = ‘ LONDRES’
AND J.CIUDAD = ‘LONDRES’;
6.11
SELECT DISTINC S.CIUDAD, J.CIUDAD
FROM S, SPJ, J
WHERE S.S# SPJ.S#
AND SPJ.J# = J.J#;
6.12
SELECT DISTINC P#
FROM SPJ, S, J
WHERE SPJ.S# = S.S#
AND SPJ.J# = J.J#
AND S.CIUDAD <> J.CIUDAD;
6.14
SELECT SPJX.P#, SPJY.P#
FROM SPJX, SPJ, SPJY
WHERE SPJX.S# = SPJY.S#
AND SPJX.P# > SPJY.P#;
6.15
SELECT COUNT (DISTINC J#)
FROM SPJ
WHERE S# = ‘S1’;
6.16
SELECT SUM (CANT)
FROM SPJ
WHERE P# = ‘P1’
AND S# = ‘S1’;
6.17
SELECT P#, J#, SUM (CANT)
FROM SPJ
GRUOP BY P#, J#;
6.18
SELECT DISTINC P#
FROM SPJ
GROUP BY P#, J#
HAVING AVG (CANT) > 320;
6.19
SELECT S#, P#, J#, CANT
FROM SPJ
WHERE CANT IS NOT NULL;
6.20
SELECT J#, CIUDAD
FROM J
WHERE CIUDAD LIKE ‘_o%’;
6.21
SELECT JNOMBRE
FROM J
WHERE J#
(SELECT J#
FROM SPJ
WHERE S# = ‘S1’);
Documentos relacionados
Descargar