Lenguaje SQL
Introducción
Para comenzar con esta unidad, y continuando desde la Unidad 1 donde vimos
cómo obteníamos el esquema interno, es decir las tablas de nuestra base de datos,
veremos a partir del modelo E-R cómo crear la base de datos y sus tablas.
Aprenderemos a partir de los mismos ejemplos que trabajamos en la Unidad 1
para unir todos los conocimientos adquiridos.
Instalación de MySQL
Para instalar MySQL en tu computadora tendrás que ingresar a esta
URL: [Link]
Luego de tener el MySQL instalado, te preguntarás...
¿Y ahora qué hago?
Ahora es el momento de volver al esquema que habíamos armado en base al relato
de nuestro cliente y comenzar a crear las tablas dentro de una base de datos.
Pero para eso tenés que aprender a interactuar con MySQL.
Recordemos de la Unidad 1 que teníamos dos tipos de lenguaje, DDL y DML. Para
crear las tablas se utilizará DDL. Luego, utilizaremos DML para interactuar con los
datos de dichas tablas, ya sea que los leamos o los modifiquemos.
Interacción con el entorno MySQL
Además de la consola, recordarás que hemos instalado un entorno visual llamado
MySQL Workbench.
En este apartado veremos las partes que lo componen para que puedas iniciarte en
el mismo.
Podrás hacer los ejercicios de la unidad utilizando cualquiera de los dos y así será
mucho más interesante todo lo que aprendas y lo estarás practicando al instante
en tu DBMS.
Lo primero que vemos al iniciar el entorno y conectarnos al DBMS es:
El primer paso es crear el Schema que será el contenedor de nuestros objetos.
Vamos a crear uno llamado “ventas” donde pondremos todas las tablas que vamos
a usar en el resto de los apartados de esta unidad.
Sentencias DDL: CREATE, ALTER y DROP
A partir de ahora comenzaremos a ver las distintas sentencias del lenguaje SQL
(del inglés Structured Query Language) en su forma compatible con ANSI 92. ANSI
es un standard del lenguaje, lo que nos asegura que dicha forma es compatible con
todos los DBMS del mercado.
Es decir, que si escribimos una sentencia de código SQL ANSI 92 la podremos
ejecutar exitosamente en cualquier DBMS. SI la sentencia no es ANSI, podría darse
el caso que se ejecute con éxito en un DBMS (por ejemplo SQL Server) pero no en
otros (por ejemplo Oracle y MySQL).
Como vimos en la Unidad 1, el lenguaje DDL o de definición de datos, contiene
sentencias que permiten crear, modificar o eliminar objetos en el esquema interno
de la base de datos en base al esquema conceptual.
Para ello se utilizan tres sentencias muy potentes, ellas son CREATE, ALTER y
DROP, las que veremos a continuación.
La sentencia CREATE tiene la siguiente estructura en su forma más simple:
CREATE <tipo de objeto> "Nombre de objeto"
Luego, dependiendo del tipo de objeto, la sentencia varía. Como nos vamos a
concentrar por ahora en la creación de tablas, vamos a ver en detalle la sentencia
para este caso:
SQL
CREATE TABLE "Nombre de la tabla" (
Columna1 tipo de dato NULL,
Columna2 tipo de dato NULL,
….
)
Los tipos de datos pueden ser:
● Int: números enteros
● Datetime: fecha y hora
● Varchar (longitud en cantidad de caracteres): cadenas de caracteres o
strings
● Float: números decimales
Son los tipos más comunes que estaremos manejando.
Sentencia CREATE
Retomamos de la Unidad 2 el esquema interno que nos había quedado para el
modelo de los préstamos de libros de la biblioteca, definido por el diagrama E-R
que copiamos aquí:
Para crear la tabla Préstamo (cuidado que no vamos a poner el acento en la e para
el nombre de la tabla):
SQL
CREATE TABLE prestamo (
ID int not NULL,
Fecha datetime NULL,
Fecha_Devolucion datetime NULL,
PRIMARY KEY (ID),
FOREIGN KEY (CodSocio) REFERENCES Socios(Codigo)
)
El NULL es el valor que tiene un atributo cuando no se le ha asignado aún ningún
valor. Por ejemplo, al momento de crear una tabla, ésta no tiene ninguna t-upla.
Luego los usuarios comienzan a agregar datos y puede suceder que no los
conozcan todos, por ejemplo que al dar de alta un libro, no tengan a mano el año de
impresión. Por lo tanto lo dejan vacío. El DBMS va a tomar este valor no ingresado
como NULL.
Cuando creamos una tabla, y definimos en las columnas NULL quiere decir que ese
atributo no es requerido o sea que se podría dejar vacío cuando se ingresan datos.
Si definimos not NULL quiere decir que no permitiremos que esa columna quede
en blanco, es decir que será obligatorio para los usuarios llenar ese campo y el
DBMS se encargará de indicarle al usuario que debe ingresar un valor.
La cláusula Primary Key contiene entre paréntesis el nombre del atributo que
será utilizado como clave de la tabla.
Por último, recordemos que teníamos la clave foránea que correspondía al código
del socio que solicitaba el préstamo. Esa clave foránea se crea con la cláusula
Foreign Key indicando en “References” el nombre de la tabla y el atributo
relacionado.
Para crear la tabla Préstamo (cuidado que no vamos a poner el acento en la e para
el nombre de la tabla):
SQL
CREATE TABLE prestamo (
ID int not NULL,
Fecha datetime NULL,
Fecha_Devolucion datetime NULL,
PRIMARY KEY (ID),
FOREIGN KEY (CodSocio) REFERENCES Socios(Codigo)
)
El NULL es el valor que tiene un atributo cuando no se le ha asignado aún ningún
valor. Por ejemplo, al momento de crear una tabla, ésta no tiene ninguna t-upla.
Luego los usuarios comienzan a agregar datos y puede suceder que no los
conozcan todos, por ejemplo que al dar de alta un libro, no tengan a mano el año de
impresión. Por lo tanto lo dejan vacío. El DBMS va a tomar este valor no ingresado
como NULL.
Cuando creamos una tabla, y definimos en las columnas NULL quiere decir que ese
atributo no es requerido o sea que se podría dejar vacío cuando se ingresan datos.
Si definimos not NULL quiere decir que no permitiremos que esa columna quede
en blanco, es decir que será obligatorio para los usuarios llenar ese campo y el
DBMS se encargará de indicarle al usuario que debe ingresar un valor.
La cláusula Primary Key contiene entre paréntesis el nombre del atributo que
será utilizado como clave de la tabla.
Por último, recordemos que teníamos la clave foránea que correspondía al código
del socio que solicitaba el préstamo. Esa clave foránea se crea con la cláusula
Foreign Key indicando en “References” el nombre de la tabla y el atributo
relacionado.
SENTENCIAS CREATE, ALTER Y DROP
De la misma manera, si queremos crear la tabla Socios, la sentencia será:
SQL
CREATE TABLE socios (
Codigo int not null,
Nombre varchar(30) null,
Apellido varchar(30) null,
Fecha_Alta datetime null,
PRIMARY KEY (Codigo)
)
Además tenemos el atributo multivaluado Email que habíamos visto que se
pasaba como una tabla. Este se crea de la siguiente manera:
SQL
CREATE TABLE Email (
Codigo int not null,
Email varchar(100) null,
PRIMARY KEY (Codigo),
FOREIGN KEY (CodSocio) REFERENCES Socios (Codigo)
)
¿Podés escribir las sentencias de creación de las tablas que faltan?
Mirá nuestra solución
Si seguiste los pasos indicados entonces habrás creado las tablas restantes de la
siguiente manera (recordarás de la Unidad 2 que las relaciones N-M se pasaban
como una tabla adicional con los atributos clave de las tablas participantes en la
relación, como clave de dicha tabla):
SQL
CREATE TABLE Libro (
Codigo int not null,
Título varchar(100) null,
Edición varchar(20) null,
Lugar varchar(50) null,
Año int null,
Fecha_Alta datetime null,
PRIMARY KEY (Codigo)
);
CREATE TABLE Autor (
ID int not null,
Nombre varchar(30) null,
Apellido varchar(30) null,
PRIMARY KEY (ID)
);
CREATE TABLE Libro_Autor (
CodLibro int not null,
CodAutor int not null,
PRIMARY KEY (CodLibro,CodAutor)
FOREIGN KEY (CodLibro)
REFERENCES Libro(Codigo),
FOREIGN KEY (CodAutor)
REFERENCES Autor(ID)
);
CREATE TABLE Prestamo_Libro (
CodLibro int not null,
CodPrestamo int not null,
PRIMARY KEY (CodLibro,CodPrestamo),
FOREIGN KEY (CodLibro)
REFERENCES Libro(Codigo),
FOREIGN KEY (CodPrestamo)
REFERENCES Prestamo(ID)
);
Ahora bien, te preguntarás...
¿Qué sucede si quisiéramos cambiar algo en la tabla que creamos?
¿Cómo haríamos si quisiéramos agregar una columna?
En ese caso utilizamos la sentencia ALTER.
Para agregar una columna hacemos asi:
SQL
ALTER TABLE nombre de tabla
ADD nombre de columna tipo de dato;
Y para eliminar una columna hacemos así:
SQL
ALTER TABLE nombre de tabla
DROP COLUMN nombre de columna;
Para eliminar un objeto utilizamos la sentencia DROP indicando el tipo de objeto y
su nombre.
Por ejemplo, para eliminar la tabla "socios" hacemos lo siguiente:
DROP TABLE socios;
Sentencias DML: SELECT
Tomaremos el diagrama E-R de nuestro schema Ventas creado en la actividad 2
para interactuar con los objetos derivados del mismo e iremos trabajando en base
a ejemplos prácticos para guiar el aprendizaje.
Para consultar los datos de una o varias tablas, se utiliza la sentencia SELECT. La
forma más básica de esta sentencia es:
SQL
SELECT <lista de atributos> FROM <lista de tablas>
WHERE <lista de condiciones>
ORDER BY <lista de atributos> <asc, desc>
Si quisiéramos seleccionar todos los atributos, en lugar de listarlos de a uno
separados por comas, podemos utilizar el * (asterisco) que simboliza justamente
“todos los campos”.
Por ejemplo utilizando esta forma del SELECT para hacer un listado de las
descripciones y precios de los productos ordenados alfabéticamente hay que
ejecutar la siguiente sentencia:
SQL
SELECT descripcion, precio FROM productos
ORDER BY descripcion;
Con esta consulta obtendríamos un listado como el siguiente:
Descripción Precio
azúcar $15
harina $10
huevo $1,70
leche $22
Si en lugar de querer todos los productos quisiéramos solamente la lista de
aquellos cuyo precio es inferior a $ 20 y ordenados en forma descendente de
acuerdo al precio (es decir los más caros al comienzo de la lista):
SQL
SELECT descripcion, precio FROM productos
WHERE precio<20
ORDER BY precio desc;
Obtendríamos este listado:
Descripción
Precio
azúcar $15
harina $10
huevo $1,70
Vemos que el orden ascendente es el que se toma por defecto y por tanto si no se
ingresa nada en la cláusula ORDER BY significa que es ascendente.
Otras combinaciones del SELECT son
DISTINCT
La instrucción SELECT DISTINCT se usa para devolver solo valores distintos
(diferentes).
Dentro de una tabla, una columna a menudo contiene muchos valores
duplicados; y a veces solo quieres enumerar los diferentes valores (distintos).
La instrucción SELECT DISTINCT se usa para devolver solo valores distintos
(diferentes).
Sintaxis SELECT DISTINCT
SELECT DISTINCT column1, column2, ...
FROM table_name;
LIMIT
La cláusula SELECT LIMIT se usa para especificar el número de registros a
devolver.
La cláusula SELECT LIMIT es útil en tablas grandes con miles de registros.
Devolver una gran cantidad de registros puede afectar el rendimiento.
Sintaxis de MySQL:
SELECT column_name(s)
FROM table_name
WHERE condition
LIMIT number;
Donde number es el número de registros que se quiere obtener. Si luego del
número, se escribe PERCENT, se devuelven la cantidad de registros según el
porcentaje establecido.
La siguiente instrucción SQL selecciona el primer 50% de los registros de la tabla
"Clientes":
Ejemplo
SELECT * FROM Customers LIMIT 50 PERCENT;
Columnas calculadas.
Es posible obtener salidas en las cuales una columna sea el resultado de un cálculo
y no un campo de una tabla.
Si queremos ver los títulos, precio y cantidad de cada libro escribimos la siguiente
sentencia:
select titulo,precio,cantidad from libros;
Si queremos saber el monto total en dinero de un título podemos multiplicar el
precio por la cantidad por cada título, pero también podemos hacer que MySQL
realice el cálculo y lo incluya en una columna extra en la salida:
select titulo, precio,cantidad,precio*cantidad from
libros;
Si queremos saber el precio de cada libro con un 10% de descuento podemos
incluir en la sentencia los siguientes cálculos:
select titulo, precio,precio*0.1,precio-(precio*0.1) from
libros;
Usar ALIAS en tablas y campos
Es recurrente en el desarrollo de consultas o sentencias SQL extensas el uso de
ALIAS, esta propiedad es extensible tanto para tablas como para las columnas o
campos y permite renombrar los nombres originales de tablas o campos de
manera temporal, el uso de ALIAS presenta algunas ventajas: Permite acelerar la
escritura de código SQL
Mejorar la legibilidad de las sentencias
Ocultar/Renombrar los nombres reales de las tablas o campos a usuarios
Permite asignar un nombre a una expresión, fórmula o campo calculado
Unos breves ejemplos de lo antes señalado usando la especificación AS
-- RENOMBRAR COLUMNAS EN UNA CONSULTA
SELECT [Link] AS numero_cliente,
[Link] AS nombre_cliente,
[Link] AS domicilio FROM clientes
-- RENOMBRAR TABLAS O ATRIBUTOS CALCULADOS
SELECT [Link] , [Link], ([Link] * 1.21) AS precio_con_iva, FROM ventas AS A
Cláusula WHERE
Quizás te preguntarás:
¿Cómo se hace si necesitamos obtener los nombres de los clientes y los productos
que compraron, con sus cantidades?
Pues bien, se puede hacer de dos maneras, en la primera utilizaremos la
cláusula WHERE para armar la correspondencia entre las t-uplas que participan
en la relación (la unión entre la clave primaria de la tabla clientes y la clave
primaria de la tabla productos). Para referirse a los atributos o campos de una
tabla, se utiliza la siguiente notación: [Link] de manera que se puedan
diferenciar los nombres de los atributos entre las tablas, sobre todo en los casos en
que el nombre es el mismo (por ejemplo el código).
Escribimos entonces:
SQL
SELECT Clientes.Razon_Social,
[Link],
[Link],
Pedidos_Productos.cant
FROM Productos,
Clientes,
Pedidos_Productos,
Pedidos
WHERE [Link] = Pedidos_Productos.CodProducto and
[Link] = [Link] and
[Link] = Pedidos_Productos.Codpedido;
Se obtendrá una lista como la siguiente:
Descripció Preci Cantida
Razón Social n o d
El Alfil harina 10 31
La azúcar 15 11
Salamandra
La huevo 1,70 12
Salamandra
El Alfil huevo 1,70 18
La leche 22 13
Salamandra
El Alfil leche 22 15
La harina 10 8
Salamandra
El Alfil azúcar 15 10
Si necesitamos mostrar todos los atributos de una tabla pero no de la otra,
ingresamos tabla.*, por ejemplo cliente.* se usaría para mostrar todos los
atributos de la tabla clientes. En cambio si utilizamos * sin especificar, se
mostrarán todos los atributos de todas las tablas.
Se pueden usar alias para reemplazar el nombre de las tablas en la consulta y no
tener que escribir tanto, por ejemplo podríamos usar "c" para Clientes, "p" para
Preductos y "cp" para Clientes_Productos.
Entonces el código queda así:
SQL
SELECT c.Razon_Social,
[Link],
[Link],
[Link]
FROM Productos p,
Clientes c,
Pedidos_Productos pp,
Pedidos pe
WHERE [Link] = [Link] and
[Link] = [Link] and
[Link] = [Link]
Si además quisiéramos calcular el monto gastado incluyendo el I.V.A. habría que
realizar este cálculo: precio*cant*1,21 para cada t-upla, llamando a este cálculo
con el nombre (o alias) "monto", es decir se debería modificar la consulta de la
siguiente manera:
SQL
SELECT c.Razon_Social,
[Link],
[Link],
[Link],
[Link]*[Link]*1,21 as monto
FROM Productos p,
Clientes c,
Pedidos_Productos pp,
Pedidos pe
WHERE [Link] = [Link] and
[Link] = [Link] and
[Link] = [Link]
Y, de esta forma, obtenemos así el siguiente listado:
Descripció Preci Cantida Mont
Razón Social n o d o
El Alfil harina 10 31 310
La azúcar 15 11 165
Salamandra
La huevo 1,70 12 19,40
Salamandra
El Alfil huevo 1,70 18 27,90
La leche 22 13 286
Salamandra
El Alfil leche 22 15 330
La harina 10 8 80
Salamandra
El Alfil azúcar 15 10 150
Recordemos que así cómo usamos los operadores lógicos para los lenguajes de
programación también son utilizables para el manejo en el trabajo de búsquedas
de datos en una BD.
Recordamos entonces ……
Operadores de Comparación
Tambien conocidos como operadores relacionales utilizados en MySQL para
comparar igualdades y desigualdades, también existen otros operadores avanzados
que serán expuestos en lo adelante. Los operadores de comparación se utilizan con
la cláusula WHERE para determinar qué registros seleccionar.
Te presentamos una lista de los operadores de comparación que puede utilizar en
MySQL:
OPERADOR DESCRIPCIÓN
IS NOT NULL Verifica si el Valor es diferente de NULL
LIKE Define un patrón de búsqueda y utiliza % y _
= Igual
<> Diferente
!= Diferente
> Mayor que
>= Mayor o igual que
< Menor que
<= Menor o igual que
IN ( ) Valores que coinciden en una lista
BETWEEN Valores en un Rango (incluye los extremos)
IS NULL Verifica si el Valor es NULL
Operador de Igualdad
En MySQL, puede utilizar el operador = para comprobar la igualdad en una consulta.
El operador = sólo puede comprobar igualdad con valores que no son NULL.
Ejemplo:
SELECT * FROM contactos WHERE apellido =
'Jameson';
En este ejemplo, la instrucción SELECT anterior devolverá todas las filas de la tabla
de contactos en la que apellido es igual a Jameson.
Operador de desigualdad
Podemos utilizar los operadores <> o ! = Para comprobar la desigualdad en una
consulta.
Por ejemplo, podríamos comprobar la desigualdad usando el operador <>, como
sigue:
SELECT *
FROM contactos
WHERE apellido <> 'Jameson';
En este ejemplo, la instrucción SELECT devolverá todas las filas de la tabla de
contactos en la que apellido no es igual a Johnson.
O también podría utilizar el operador !=, así como continua:
SELECT *
FROM contactos
WHERE apellido != 'Jameson';
Ambas consultas retornaran los mismos resultados.
Operador Mayor Que
Puede utilizar el operador > en MySQL para comprobar una expresión mayor que.
SELECT * FROM contactos WHERE contacto_id > 50;
En este ejemplo, la instrucción SELECT devolverá todas las filas de la tabla de
contactos donde el contacto_id es mayor que 50. Un contacto_id igual a 50 no se
incluiría en el conjunto de resultados.
Operador Mayor o Igual Que
En MySQL, puede usar el operador >= para comprobar una expresión mayor o
igual que.
SELECT * FROM contactos WHERE contacto_id >= 50;
En este ejemplo, la sentencia SELECT devolverá todas las filas de la tabla de
contactos donde el contacto_id es mayor o igual a 50. En este caso, contacto_id
igual a 50 se incluiría en el conjunto de resultados.
Operador Menor Que
Puede usar el operador < en MySQL para comprobar una expresión menor que.
SELECT *
FROM inventario
WHERE producto_id < 210;
En este ejemplo, la instrucción SELECT devolverá todas las filas de la tabla de
inventario donde el id_producto es menor que 210. Un id_producto igual a 210 no
se incluiría en el conjunto de resultados.
Operador Menor o Igual Que
En MySQL, puede utilizar el operador <= para comprobar una expresión menor o
igual a.
SELECT * FROM inventario WHERE producto_id <=
300;
En este ejemplo, la instrucción SELECT devolverá todas las filas de la tabla de
inventario donde el id_producto es menor o igual que 210. Un id_producto igual a
210 también se incluiría en el conjunto de resultados.
Operador IN()
Puedes hacer uso del operador IN(). para listar uno o más valores, los cuales se
tomaran en cuenta en la busqueda.
SELECT * FROM inventario WHERE producto_id
IN(300,1089,2000,45);
En este ejemplo, la instrucción SELECT devolverá todas las filas de la tabla de
inventario donde el id_producto sea 300, 1089, 2000 y 45. Únicamente los
id_producto que coincidan con los valores que están dentro de IN() se incluiría en
el conjunto de resultados.
Operador BETWEEN
El operador BETWEEN tiene un uso similar al de los operadores “<” y “>”, que este
establece un rango inicial y un rango final, adicional a esto también es necesario
usar el operador AND.
SELECT *
FROM inventario
WHERE producto_id BETWEEN 300 AND 1000;
Con el uso de BETWEEN , la instrucción SELECT devolverá todas las filas de la
tabla de inventario donde el id_producto se encuentre dentro del rango de 300 y
1000 , incluyendo el 300 y el 1000. También podemos combinar este operador
con el operador NOT y este invertirá los resultados.
Observá que el WHERE no se utiliza a menos que sea para reales condiciones que
correspondan a características propias de los datos, por ejemplo si deseamos que
solo muestren los datos de los productos para los cuales el precio sea menor a $20:
SQL
SELECT c.Razon_Social,
[Link],
[Link],
[Link],
[Link]*[Link]*1,21 Monto
FROM Productos p
JOIN Pedidos_Productos pp ON [Link] = [Link]
JOIN Pedidos pe ON [Link] = [Link]
JOIN Clientes c ON [Link] = [Link]
WHERE precio < 20;
Otro ejemplo con IN:
Ahora veremos, cómo obtenemos los códigos de ciertos productos específicos, por
ejemplo Harina, Azúcar y Leche:
SQL
SELECT codigo FROM producto
WHERE descripción = 'Harina' OR
descripción = 'Azúcar' OR
descripción = 'Leche'
Pero si tenemos una lista larga de posibilidades, escribir todas estas cláusulas OR
encadenadas sería muy tedioso, entonces usamos la sentencia IN que funciona de
manera equivalente:
SQL
SELECT codigo FROM producto
WHERE descripción IN ('Harina' ,'Azúcar' ,'Leche')
Siempre después de la cláusula IN va una lista de una sola columna o atributo, y
siempre antes va un atributo que debe coincidir en su tipo de dato con el tipo de
dato de la lista.
Más ejemplos de lo usos de operadores lógicos …..
Queremos recuperar todos los registros cuyo autor sea igual a "Borges" y cuyo
precio no supere los 20 pesos, para ello necesitamos 2 condiciones:
select * from libros where (autor='Borges') and
(precio<=20);
Los registros recuperados en una sentencia que une 2 condiciones con el operador
"and", cumplen con las 2 condiciones.
Queremos ver los libros cuyo autor sea "Borges" y/o cuya editorial sea "Planeta":
select * from libros where autor='Borges' or
editorial='Planeta';
En la sentencia anterior usamos el operador "or", indicamos que recupere los
libros en los cuales el valor del campo "autor" sea "Borges" y/o el valor del campo
"editorial"
es "Planeta", es decir, seleccionará los registros que cumplan con la primera
condición, con la segunda condición o con ambas condiciones.
Los registros recuperados con una sentencia que une 2 condiciones con el
operador "or", cumplen 1 de las condiciones o ambas.
Queremos recuperar los libros que no cumplan la condición dada, por ejemplo,
aquellos cuya editorial NO sea "Planeta":
select * from libros where not
(editorial='Planeta');
El operador "not" invierte el resultado de la condición a la cual antecede.
Los registros recuperados en una sentencia en la cual aparece el operador "not",
no cumplen con la condición a la cual afecta el "NO".
Los paréntesis se usan para encerrar condiciones, para que se evalúen como una
sola expresión.
Cuando explicitamos varias condiciones con diferentes operadores lógicos
(combinamos "and", "or") permite establecer el orden de prioridad de la
evaluación; además permite diferenciar las expresiones más claramente.
Por ejemplo, las siguientes expresiones devuelven un resultado diferente:
select * from libros
where (autor='Borges') or (editorial='Paidos' and
precio<20); select*from libros where (autor='Borges'
or editorial='Paidos') and (precio<20);
Cláusula LIKE
Otra cláusula muy potente del lenguaje SQL es la que se utiliza para comparaciones
con campos de tipo de cadenas de texto. Esta sentencia se podría utilizar por
ejemplo para consultar cuáles son los clientes que viven en una calle que contiene
el nombre Martín, pero que no se sabe si se ha escrito Martín o Martin (o sea que
podría estar sin acento). ¡O sea podríamos tener en esta lista gente que viva en la
localidad de San Martín o en la localidad Martín Coronado o en Martínez!
La cláusula de la que estamos hablando es el LIKE. Veamos cómo se utiliza en este
caso:
SQL
SELECT * FROM Clientes c
WHERE calle LIKE '%Mart[ií]n%'
Analicemos un poco esta comparación para entender mejor como trabaja el LIKE:
Primero que nada:
Las comparaciones que trabajan con LIKE van todas entre comillas simples.
Existen comodines como ser:
% : este comodín representa una cadena de cualquier largo que incluye
texto, números y espacios en blanco
_ : este comodín representa un solo carácter pero este puede ser una letra o
un número
? : este comodín representa un solo carácter de tipo numérico (o sea un
dígito)
[] : entre corchetes vamos a poder colocar todos aquellos caracteres o
números posibles que pueden ir en un solo lugar. O sea es como si
pusiéramos el guion bajo pero le diéramos solo una lista de opciones
posibles refinando así los valores que se pueden ingresar en ese lugar.
Veamos entonces en detalle lo que pasó con nuestra consulta:
Al colocar el % al comienzo y al final estamos representando un texto que no nos
preocupa cómo comienza ni cómo termina, siempre y cuando contenga la palabra
que nos interesa. Como no sabíamos si iba a estar escrito o no con acento entonces
colocamos entre corchetes las dos opciones de" "i (o sea "i" e "í").
Veamos otro ejemplo:
Buscar los nombres de las calles que comiencen con N o J, luego viene una vocal y a
continuación un texto cualquiera que termina con dos números. Esta condición
sería así:
SQL
SELECT * FROM Clientes c
WHERE calle LIKE '[NJ][aeiou]%??'
Sentencias DML: Cláusula JOIN
Habíamos dicho que hay dos formas de hacer consultas que “cruzan” varias tablas
a través de sus relaciones. La primera que es la que vimos recién, involucra el uso
de la cláusula WHERE y la otra forma utiliza una nueva cláusula: JOIN.
El JOIN se utiliza para indicar la manera en que se están relacionando las tablas, es
decir, con qué atributos se está plasmando la relación entre ellas. Se escribe de la
siguiente forma:
SQL
SELECT FROM tabla1
JOIN tabla2 ON tabla1.campo1 = tabla2.campo2
JOIN tabla3 ON tabla2.campo3 = tabla3.campo4
...
Entonces, para escribir la misma consulta que antes pero utilizando el JOIN
haríamos así:
SQL
SELECT c.Razon_Social,
[Link],
[Link],
[Link],
[Link]*[Link]*1,21 Monto
FROM Productos p
JOIN Pedidos_Productos pp ON [Link] = [Link]
JOIN Pedidos pe ON [Link] = [Link]
JOIN Clientes c ON [Link] = [Link];
Sintaxis de SQL DML Funciones de agregación
Las funciones de agregación en SQL nos permiten efectuar operaciones sobre un
conjunto de resultados, pero devolviendo un único valor agregado para todos ellos.
Es decir, nos permiten obtener medias, máximos, etc... sobre un conjunto de valores.
Las funciones de agregación básicas que soportan todos los gestores de datos son
las siguientes:
o COUNT: devuelve el número total de filas seleccionadas por la
consulta.
o MIN: devuelve el valor mínimo del campo que especifiquemos.
o MAX: devuelve el valor máximo del campo que especifiquemos.
o SUM: suma los valores del campo que especifiquemos. Sólo se puede
utilizar en columnas numéricas.
o AVG: devuelve el valor promedio del campo que especifiquemos.
Sólo se puede utilizar en columnas numéricas.
Todas estas funciones se aplican a una sola columna, que especificaremos entre
paréntesis, excepto la función COUNT, que se puede aplicar a una columna o indicar
un “*”. La diferencia entre poner el nombre de una columna o un “*”, es que en el
primer caso no cuenta los valores nulos para dicha columna, y en el segundo si.
Así, por ejemplo, si queremos obtener algunos datos agregados de la tabla de
pedidos, podemos escribir una consulta simple como la siguiente:
SELECT COUNT(*) AS TotalFilas, COUNT(ShipRegion) AS FilasNoNulas,
MIN(ShippedDate) AS FechaMin, MAX(ShippedDate) AS FechaMax,
SUM(Freight) AS PesoTotal, AVG(Freight)
PesoPromedio FROM Orders
y obtendríamos el siguiente resultado en el entorno de pruebas:
De esta manera sabremos que existen en total 830 pedidos en la base de datos, 323
registros que tienen asignada una zona de entrega, la fecha del pedido más antiguo
(el 10 de julio de 1996), la fecha del pedido más reciente (el 6 de mayo de 1998 ¡los
datos de ejemplo son muy antiguos), el total de peso enviado entre todos los
pedidos (64.942,69 Kg o sea, más de 64 toneladas) y el peso promedio del los
envíos (78,2442Kg). No está mal para una consulta tan simple. Como podemos
observar del resultado de la consulta anterior, las funciones de agregación
devuelven una sola fila, salvo que vayan unidas a la cláusula GROUP BY, que
veremos a continuación.
Agrupando Resultados
La cláusula GROUP BY unida a una cláusula SELECT permite agrupar filas
según las columnas que se indiquen, como parámetros y se suelen utilizar
como conjuntos en las funciones de agrupación para obtener datos
resumidos y agrupados por las columnas que se necesiten
Hemos vistos en el ejemplo anterior que obteníamos un solo una fila con los datos
indicados correspondientes a toda la tabla. Ahora vamos a ver con otro, ejemplo
cómo obtener otros datos correspondientes a diversos grupo de filas ,
concretamente agrupados por empleados.
En este caso obtenemos los mismos datos pero agrupándolos por empleado, de
modo que para cada empleado de la base de datos sabemos cuántos pedidos ha
realizado, cuándo fue el primero y el último, etc...:
De hecho nos resultaría muy fácil cruzarla con la tabla de empleados, usando lo
aprendido sobre consultas multitablas y que se devolvieran los mismos resultados
con el nombre y los apellidos de cada empleado.
En este caso fíjate en cómo hemos usado la expresión [Link] + ' ' +
[Link] como parámetro en GROUP BY para que nos agrupe por un
campo compuesto (en SQL Server no podemos usar alias de campos para las
agrupaciones). De esta forma tenemos casi un informe preparado con una simple
consulta de agregación.
Importante: Es muy importante tener en cuenta que cuando utilizamos la cláusula
GROUP BY, los únicos campos que podemos incluir en el SELECT sin que estén
dentro de una función de agregación, son los que vayan especificados en el GROUP
BY..
La cláusula GROUP BY se puede utilizar con más de un campo al mismo tiempo. Si
indicamos más de un campo como parámetro nos devolverá la información
agrupada por los registros.
Por ejemplo, si queremos conocer la cantidad de pedidos que cada empleado ha
enviado a través de cada transportista, podemos escribir una consulta como la
siguiente:
EL utilizar la cláusula GROUP BY no garantiza que los datos se devuelvan
ordenados . Suele ser una práctica recomendable incluir una cláusula ORDER
BY por las mismas columnas que utilicemos en GROUP BY, especificando el orden
que no s interese. Por ejemplo, en el caso anterior
Existe una cláusula especial, parecida a la WHERE qu e ya conocemos que nos
permite especificar las condiciones de filtro para los diferentes grupos de filas que
devuelven estas consultas agregadas.
Esta cláusula es HAVING . HAVING es muy similar a la cláusula WHERE, pero en
vez de afectar a las filas de la t abla, afecta a los grupos obtenidos.
Por ejemplo, si queremos repetir la consulta de pedidos por empleado de hace un
rato, pero obteniendo solamente aquellos que hayan enviado más de 5.000 Kg de
producto, y ordenados por el nombre del empleado, la consulta sería muy sencilla
usando HAVING y ORDER BY:
SELECT [Link] + ' ' + [Link] AS Empleado,
COUNT(*) AS TotalPedidos,
COUNT(ShipRegion) AS FilasNoNulas,
MIN(ShippedDate) AS FechaMin, MAX(ShippedDate) AS FechaMax,
SUM(Freight) PesoTotal, AVG(Freight) PesoPromedio
FROM Orders INNER JOIN Employees ON [Link] =
[Link]
GROUP BY [Link] + ' ' + [Link]
HAVING SUM(Freight) > 5000
ORDER BY [Link] + ' ' + [Link] ASC
Ahora obtenemos los resultados agrupados por empleado también, pero solo
aquellos que cumplan la condición indicada (o condiciones indicadas, pues se
pueden combinar). Antes nos salían 9
Ya nos falta muy poco para dominar por completo las consultas de selección de
datos en cualquier sistema gestor de bases de datos relacionales. En la próxima
entrega estudiaremos cómo realizar algunas consultas que implican el uso de sub-
consultas o que aplican algunas sintaxis especiales para utilizar subconjuntos de
datos y con eso terminaremos este bloque de fundamentos de consultas con SQL,
empleados, y ahora solo 6 pues hay 3 cuyos envíos totales son muy pequeños.
Cláusulas HAVING y WHERE
WHERE opera sobre registros individuales, mientras que HAVING lo hace sobre
un grupo de registros.
La anterior es la diferencia principal entre estas dos cláusulas. Con WHERE podemos
establecer una condición usando registros individuales, aquellos que cumplan con
esta condición serán seleccionados (eliminados o actualizados); ahora bien, con
HAVING podemos establecer una condición sobre un grupo de registros, algo muy
importante es que HAVING acostumbra ir acompañado de la cláusula GROUP BY.
Esto último es así dado que HAVING opera sobre los grupos que nos “retorna”
GROUP BY.
Entonces: WHERE sobre registros individuales y HAVING sobre grupos de
registros, sin embargo no hay nada mejor para interiorizar y terminar de entender
un concepto que un buen ejemplo, y eso es precisamente lo que vamos a hacer a
continuación.
Ejemplo
• Realicemos algunas consultas que implique el uso de HAVING y WHERE
/*1. Una fácil: Obtener el total del recaudo,Director*/
La confusión de que WHERE hace lo mismo que HAVING viene de lo siguiente:
/*Queremos obtener el recaudo de las películas agrupadas por de aquellas cuyo
genero sea drama.*/
-- Con where...
SELECT genero, director, SUM ( recaudo) AS TOTAL FROM peliculas
WHERE genero LIKE '%Drama%'
GROUP BY genero, director;
-- Con having...
SELECT genero, director, SUM ( recaudo) AS TOTAL FROM peliculas
GROUP BY genero, director
HAVING genero LIKE '%Drama%' ;
Las
Las dos consultas anteriores retornan los mismos registros, pero se comportan
totalmente distinto. En la primera, seleccionamos genero, director y la suma del
recaudo siempre y cuando el genero sea ‘Drama’ ( WHERE ) y posteriormente
los agrupamos por genero y director ( GROUP BY ).
En la segunda seleccionamos el genero, director y hacemos la suma del recaudo,
sin importar si el genero es o no ‘Drama’, luego los agrupamos por genero y
director (GROUP BY). Por último seleccionamos solo los registros cuyo genero sea
‘Drama’ (HAVING). Además, si prestaste atención, el resultado de la consulta hecha
con HAVING se demora el doble de tiempo que la consulta hecha con WHERE
(0.008 seg y 0.004 seg respectivamente).
Quizá te estés preguntando ¿cuándo usar HAVING o WHERE?, desde mi punto de
vista, deberíamos usar HAVING solo cuando se vea implicado el uso de funciones
de grupo (AVG, SUM, COUNT, MAX, MIN), debido a que con WHERE no podemos
realizar condiciones que impliquen estas funciones. Por ejemplo, si intentas esto,
tendrás un error:
/*Obtener el promedio del recaudo de las películas, agrupado por director,
teniendo en cuenta solamente aquellos promedios menores a 40 y con autor
conocido*/
SELECT director, AVG(recaudo) AS PROMEDIO FROM peliculas
WHERE AVG(recaudo) < 40 AND director NOT LIKE '%Desconocido%' GROUP BY
director;
La anterior consulta genera error puesto que estamos usando funciones de grupo
con una cláusula WHERE, que solo opera sobre registros individuales, mejor
intenta esto:
/*Obtener el promedio del recaudo de las películas, agrupado por director,
teniendo en cuenta solamente aquellos promedios menores a 40 y con autor
conocido*/
Te recomiendo entonces usar HAVING cuando se vean implicadas las funciones de
grupo. Si tienes una condición simple, que implique comparar campos individuales
entonces usa WHERE ( e.g. que el nombre sea igual a una cadena, que el recaudo de
un registro sea menor a un valor, etc.)
¿Cuál es la diferencia entre la cláusula EXISTS y IN en SQL?
La palabra clave existente puede usarse de esa manera, pero en realidad está
pensada para evitar el conteo:
Esto es más útil cuando se usa sentencias condicionales y con comodines , ya que
existen, pueden ser mucho más rápidas que contar.
La entrada se utiliza mejor cuando tienes una lista estática para pasar:
Cuando tiene una tabla en una instrucción de entrada, tiene más sentido utilizar una
combinación, pero sobre todo no debería importar. El optimizador de consultas
debe devolver el mismo plan de cualquier manera. En algunas implementaciones
(en su mayoría más antiguas, como Microsoft SQL Server 2000), las consultas
siempre obtendrán un plan nested join, mientras que las consultas de unión usarán
las anidadas, merge o hash, según corresponda.
Otro ejemplo:
La siguiente consulta muestra los datos de los empleados con uno o más hijos:
CÓDIGO: SELECCIONAR TODO
select *
from EMPLEADOS
where ID_EMPLEADO in (select distinct ID_EMPLEADO
from PARENTESCO
where TIPO = 'H')
En esta consulta el motor SQL recorrera la tabla PARENTESCO una sola vez para
establecer la lista de empleados a seleccionar. Posteriormente realizara busquedas,
que no recorridos, sobre la lista de empleados obtenida para determinar si
satisfacen la claúsula IN. Realizará tantas busquedas como registros tiene la tabla
EMPLEADOS. Cabe destacar que esta lista esta en RAM y no en disco, por lo que
vamos a suponer que las busquedas no tienen apenas coste, o si quieres, este es
[Link] pues que recorrerá la tabla PARENTESCO una vez y la
EMPLEADOS tambien una [Link] ahora EXISTS para obtener lo mismo:
CÓDIGO: SELECCIONAR TODO
select *
from EMPLEADOS E
where exists (select 1
from PARENTESCO P
where P.ID_EMPLEADO = E.ID_EMPLEADO
and [Link] = 'H')
En este caso el motor SQL realizará busquedas, que no recorridos, sobra la tabla
PARENTESCO para determinar si satisface o no la clausula IN.
Inserción, modificación y eliminación de registros.
Vamos a ver como modificar la BD. Los registros de una tabla pueden ser
modificados de tres modos: Crear nuevos registros, modificarlos o bien
eliminarlos. No se va a profundizar en este sentido, esto lo dejaremos para un
posible curso avanzado de SQL.
Por razones obvias no podrá usar el banco de pruebas para probar estas
instrucciones, de modo que para ello deberá usar su propia BD.
Insert SQL
La instrucción INSERT permite crear o insertar nuevos registros en una tabla,
veamos su sintaxis con un ejemplo práctico, la inserción de un registro en la tabla
ALUMNOS:
Observe como todo lo que se explicó en referencia a los tipos de datos es valido
para la instrucción INSERT. Los datos de tipo numérico no se entrecomillan, a
diferencia de los datos de tipo cadena y fecha.
En general la sintaxis de la instrucción INSERT es la siguiente:
Donde cada dato de la lista VALUES se corresponde y se asigna a cada campo de la
tabla en el mismo orden de aparición de la sentencia INSERT. Cabe mencionar que
si la clave primaria que identifica el registro que se pretende insertar ya la usa un
registro existente el SGBD rechazaría la operación y devolvería un error de clave
primaria duplicada.
Así que cuando usted rellena un formulario en Internet por ejemplo, y los datos
son almacenados en una BD, en algún momento del proceso se realizará una
instrucción INSERT con los datos que usted ha cumplimentado.
Update SQL
La instrucción UPDATE permite actualizar registros de una tabla. Debemos por lo
tanto indicar que registros se quiere actualizar mediante la cláusula WHERE, y que
campos mediante la cláusula SET, además se deberá indicar que nuevo dato va a
guardar cada campo.
Así por ejemplo supongamos que para el curso que carecía de profesor finalmente
ya se ha decidido quien lo va a impartir, la sintaxis que permite actualizar el profesor
que va a impartir un curso sería la siguiente:
Todo lo expuesto sobre lógica booleana es válido para la cláusula WHERE de la
instrucción UPDATE, en todo caso dicha cláusula se comporta igual que en una
consulta, solo que ahora en lugar de seleccionar registros para mostrarnos algunos
o todos los campos, seleccionará registros para modificar algunos o todos sus
campos. Por lo tanto omitir la cláusula WHERE en una instrucción UPDATE implica
aplicar la actualización a todos los registros de la tabla.
La instrucción anterior asignará un 2 en el campo ID_PROFE de la tabla CURSOS en
los registros cuyo valor en el campo ID_CURSO sea 5. Como sabemos que el campo
ID_CURSO es la clave primaria de la tabla, tan solo se modificará un solo registro si
es que existe. Obviamente en este caso, dado que el campo que se pretende
actualizar es clave foránea de la tabla PROFESORES, si no existe un registro en dicha
tabla con identificador 2 el SGBD devolverá un error de clave no encontrada.
Veamos otro ejemplo, esta vez se modificarán varios campos y registros con una sola
instrucción.
Recordemos la tabla EMPLEADOS, en ella se guardan los datos de cada empleado, el
sueldo y supongamos que también se guarda en el campo PRECIO_HORA el precio
de la hora extra que cobra cada empleado en el caso que las trabaje. Bien, con el
cambio de ejercicio se deben subir los sueldos y el precio por hora extra trabajada,
digamos que un 2% el sueldo y un 1 % el precio de la hora extra. Sin embargo la
política de empresa congela el salario a directivos que cobran 3000 euros o más.
¿Qué instrucción actualizaría estos importes según estas premisas? :
Por lo tanto solo se está actualizando el salario y el precio de la hora extra de
aquellos empleados que su salario es inferior a 3000 euros.
En general la sintaxis de la instrucción UPDATE es la siguiente:
CÓDIGO: SELECCIONAR TODO
UPDATE nombre_tabla
SET campo1 = valor1,
campo2 = valor2,
...
campoN = valorM
WHERE condiciones
Vaciar una tabla en MySQL
Sintaxis de TRUNCATE TABLE en MySQL
Vamos con la sintaxis de TRUNCATE TABLE extraída de su web oficial:
TRUNCATE TABLE nombre_tabla;
Tal y como podemos ver la sintaxis en bien sencilla, solo tenemos que indicar el
nombre de la tabla a vaciar de contenido. La tabla seguirá con la misma estructura
pero con 0 filas.
Ejemplo de TRUNCATE TABLE
El ejemplo podemos decir que es idéntico a la sintaxis pero ahí va:
TRUNCATE TABLE usuarios;
Cuando manejamos una base de datos SQL, además de manejar creaciones de
tablas (CREATE TABLE), inserciones (INSERT), consultas (SELECT) y
actualizaciones (UPDATE); dentro de las operaciones básicas también tenemos las
que implican borrado. Borrado de diferentes tipos: de filas que cumplan una serie
de condiciones, de todos los datos de una tabla o de la tabla con su estructura.
Veamos cada una de ellas, con su sintaxis y un ejemplo.
Manejamos para el ejemplo una tabla entradas, que trata sobre la entradas de un
blog y que almacena básicamente la siguiente información: identificador, título,
cuerpo y tiempo de salida.
DELETE
Borra una serie de filas de la tabla. Podemos usar una cláusula WHERE para limitar
las filas a borrar, a las que cumplan una condición. La sintaxis sería:
DELETE FROM nombre_tabla WHERE
condicion Para nuestro caso:
DELETE FROM entradas WHERE id = 2;
TRUNCATE A diferencia de DELETE, TRUNCATE elimina todas las filas de la tabla
sin borrar la tabla. También resetea los contadores de auto incremento a 0. No
borra la tabla como tal, la llamada estructura, por lo que luego puede comenzar a
hacer inserciones. La sintaxis es:
TRUNCATE TABLE nombre_tabla;
Y para nuestro caso:
TRUNCATE TABLE entradas;
DROP
Finalmente llegamos a DROP. Que en diferencia al anterior no solo elimina los
datos sino también la estructura de los datos.
Resumen
Con las instrucciones INSERT, DELETE y UPDATE el SGBD permite crear eliminar o
modificar registros.
La cláusula WHERE de las instrucciones DELETE y UPDATE se comporta igual que
en las consultas y permite
descartar o considerar registros mediante condiciones por la instrucción de
actualización o de borrado.
Omitir la cláusula WHERE implica aplicar la operación a todos los registros de la
tabla.
Al insertar eliminar o actualizar datos, deben respetarse las restricciones. Si estas
están montadas en la BD, cosa por otro lado muy recomendable, podemos tener
errores de tres tipos:
• Violación de integridad referencial (se pretende dejar huérfanos registros que
apuntan al registro
padre al intentarlo eliminar o modificar).
• Clave padre no encontrada (al actualizar o insertar una clave foránea que no
existe en la tabla padre a la que apunta)