#Curso SQL: SELECT avanzado e INSERT INTO

Publicado el 19 abril 2018 por Instintobinario

Continuamos en el tercer capítulo de éste curso de SQL. En los artículos anteriores hemos visto las consultas básicas con SELECT, UPDATE y DELETE y las opciones avanzadas para la cláusula WHERE. En éste capítulo seguiremos avanzando en las consultar avanzadas con SELECT.

Existen múltiples opciones y varias cláusulas más para modificar los resultados de consultas SQL obtenidos con SELECT.

Alias

Comenzaremos por lo más simple, la creación de alias para campos y para tablas. Por el momento hemos creado consultas que afectan  a una sola tabla, y por el momento seguiremos así. Sin embargo, es posible crear consultas que afecten a dos o más tablas,  y en dichas tablas puede haber campos que se llamen igual.

ID Nombre

1 Campoamor

2 Piensos Lola

3 Maderas Pepe

Por ejemplo, veamos la tabla ‘Cliente’, que tiene el campo ´Nombre’ y una nueva tabla ‘Proveedor’ que también tiene un campo ‘Nombre’. Imagina que queremos seleccionar todos los clientes y proveedores de  nuestras tablas. Para ello creamos la siguiente sentencia (es un poco tonta pues nos dará todas las combinaciones posibles de Cliente – Proveedor, pero sirve para ilustrar los alias):

SELECT Nombre FROM Cliente, Proveedor;

Ésta consulta nos dará error,  pues ambas tablas tienen el campo ‘Nombre’.  Por eso  tenemos que referirnos al campo utilizando el nombre de la tabla:

SELECT Cliente.Nombre, Proveedor.Nombre FROM Cliente, Proveedor;

Para evitar tener que escribir en nombre  completo de la tabla podemos asignarla un alias. Lo haremos de la siguiente forma:

SELECT C.Nombre, P.Nombre FROM Cliente C, Proveedor P;

Claro que esto nos dará como resultado dos columnas tituladas “Nombre”. Por ello vamos a poner a la columna un  alias también:

SELECT C.Nombre Cliente, P.Nombre Proveedor FROM Cliente C, Proveedor P;

En el caso de las columnas podemos utilizar la palabra AS para indicar el alias a continuación. La siguiente es igual a la anterior:

SELECT C.Nombre AS Cliente, P.Nombre AS Proveedor FROM Cliente C, Proveedor P;

En otros sistemas de bases de datos, todos los alias deben declararse mediante el operador AS, sin embargo Oracle lo admite de ésta forma.

Literales como Alias

Podemos añadir una columna “imaginaria” en la cual ponemos un valor fijo mediante un alias:

SELECT 'Cliente', C.* FROM Cliente C;

Esta sentencia nos devuelve todos los datos de clientes añadiendo un campo que contiene el literal “Cliente” en cada fila. Incluso el título. Si queremos dar un título a este campo utilizamos un Alias:

SELECT 'Cliente' as tipo, C.* FROM Cliente C;

Ordenación de consultas

Por defecto el orden de los datos obtenidos es aquel en que se encuentran almacenados en la base de datos. Sin embargo, en mucha ocasiones nos interesa más obtener los datos con un orden diferente. Para ello tenemos la cláusula ORDER BY. Su uso es sencillo, se detrás del WHERE y se le indica la columna por la que queremos que nos ordene:

SELECT * FROM Cliente
WHERE Ciudad = 'Valladolid'
ORDER BY Nombre;

Observa que he dividido la sentencia en varias líneas. Se puede hacer libremente en cuantas consideremos necesarios, pues los espacios y saltos de línea no la afectan. El final de sentencia viene marcado por el carácter “;” y no se considera finalizada hasta que aparezca éste.

También podemos ordenar por varias columnas. En éste caso el criterio es: ordenar primero por la primera columna indicada y, después, por la segunda y la tercera, etc. Es decir la ordenación por la segunda columna se hará dentro del subconjunto de tuplas que tengan la primar columna de ordenación con el mismo valor. Puedes observar un ejemplo en la siguiente sentencia observando el cambio respecto a la anterior:

SELECT * FROM Cliente
ORDER BY Ciudad, Nombre;

Los valores nulos siempre se colocan  al final de la ordenación.

Pero, ¿cómo ordenamos los valores a la inversa? Es sencillo con las sentencias: ASC y DESC. Por defecto coge el valor ASC, y los ordena de forma ascendente. Si queremos indicar que o haga de forma descendente (de mayor a menor), es necesario utilizar DESC:

SELECT * FROM Cliente
ORDER BY Ciudad DESC;

Estos dos valores se pueden alternar en los sucesivos criterios de ordenación. Prueba a variar los valores ASC y DESC en la siguiente sentencia y ver qué pasa:

SELECT * FROM Cliente
ORDER BY Ciudad ASC, Nombre DESC;

Funciones matemáticas y estadísticas

Cuando consultamos una base de datos, no siempre nos interesan los datos tal cual están almacenados. En algunas ocasiones nos interesan ciertas propiedades de los mismos. Para ello tenemos ciertas funciones que nos facilitan mucho la labor.

Supongamos que queremos obtener la edad del cliente más joven o más mayor que tenemos en nuestra base de datos. Para ello ejecutamos respectivamente las siguientes sentencias con las funciones máximo y mínimo:

SELECT MAX(Edad) as Edad FROM Cliente;
SELECT MIN(Edad) as Edad FROM Cliente;

El alias sobre la función no es necesario, pero si no lo escribimos la columna se llamará como la función. Cuando veamos subconsultas veremos más posibilidades de ésta función.

Pero también podemos hacer otros cálculos. Podemos sumar valores, contarlos, o calcular la media.

Pongamos que queremos obtener la suma de todas las edades de nuestros clientes, utilizamos la función SUM:

SELECT SUM(Edad) AS Suma FROM Cliente;

Sumará todas las edades y nos lo devolverá como un único valor. Ten en cuenta que esta función solo funciona con números, no con textos.

Si queremos obtener la media de una serie de datos numéricos, utilizamos la función AVG:

SELECT AVG(Edad) AS Media FROM Cliente;

Ambas funciones se puede utilizar con textos siempre que se componga de números únicamente. De ésta forma, el texto se convierte a su valor numérico y luego se realiza la operación.

Por último, tenemos una función de contar registros. Por ejemplo, si queremos contar todos los clientes que tenemos registrados usamos la función COUNT:

SELECT COUNT(Nombre) AS Cuenta FROM Cliente;

En éste caso da igual la columna que utilicemos, pues realizará el conteo del resultado y devolverá el número obtenido.

En todas éstas funciones (MIN, MAX, SUM, AVG y COUNT), podemos aplicar los filtros WHERE que deseemos. Pruébalo en base a lo aprendido anteriormente.

Agrupación de valores

Las funciones del apartado anterior adquieren mayor utilidad al agrupar los resultados en función de otro campo de la tabla. Para ello utilizamos la cláusula GROUP BY. Para utilizar ésta cláusula, es obligatorio que todas las columnas que seleccionemos estén incluidas en una función agregada. Las funciones agregadas son todas las del apartado anterior.

Así, por ejemplo, podemos obtener cuantos clientes tenemos en cada ciudad de la siguiente forma:

SELECT Ciudad, COUNT(ID) AS Num_Clientes FROM Cliente
GROUP BY Ciudad;

Podemos ordenar los valores obtenidos en función de alguna de las columnas. Por ejemplo, que muestre primero las ciudades con más clientes:

SELECT Ciudad, COUNT(ID) AS Num_Clientes FROM Cliente
GROUP BY Ciudad
ORDER BY Num_Clientes DESC;

También se puede aplicar cualquier filtro que deseemos. Por ejemplo, que cuente solamente los clientes mayores de 30 años:

SELECT Ciudad, COUNT(ID) AS Num_Clientes FROM Cliente
WHERE Edad >= 30
GROUP BY Ciudad
ORDER BY Num_Clientes DESC;

En este caso, las ciudades sin clientes mayores de 30 años, no aparecen en el resultado.

Pero  tenemos un problema al filtrar en base a una función agregada. Imagina que necesitamos obtener solamente las ciudades con más de un cliente, y el número de clientes que tienen. Para ello no se puede utilizar WHERE, pues sus condiciones se evalúan antes que las funciones agregadas y dará error.

Por este motivo tenemos otra cláusula que se evalúa después de las funciones agregadas: HAVING. Los filtros que admite son los mismos que en WHERE, pero con funciones agregadas, no a campos de la tabla. Es importante saber que HAVING no admite realizar las comparaciones mediante alias, por lo que hay que poner la función agregada.

Veamos dos ejemplos, uno con cláusula HAVING y otro combinando HAVING y WHERE:

SELECT Ciudad, COUNT(ID) AS Num_Clientes FROM Cliente
GROUP BY Ciudad
HAVING COUNT(ID)>1;
SELECT Ciudad, COUNT(ID) AS Num_Clientes FROM Cliente
WHERE Edad > 30
GROUP BY Ciudad
HAVING COUNT(ID)>1;

Función null

Vamos a suponer que necesitamos obtener la edad de cada uno de nuestros clientes dentro de 10 años. Para ello podemos sumar “on live”, en la propia sentencia 10 años a la columna Edad:

SELECT (Edad + 10) AS "Edad+10" FROM Cliente;

El problema es que si uno de los clientes tiene el valor de la edad a NULL, el resultado será NULL. Si queremos evitarlo y considerar que el valor NULL es 0, utilizamos la función NVL:

SELECT ( NVL(Edad,0) + 10) AS "Edad+10" FROM Cliente;

En este ejemplo de la edad parece un poco absurdo, pero no lo es tanto cuando hablamos de cuentas de gastos o ingresos agregados.

Limitando y guardando los registros obtenidos

En una base de datos, el número de registros almacenados puede ser realmente grande. En nuestra base de datos de ejemplo tenemos solo 9 clientes como muestra, pero en una empresa grande se pueden tener centenares de miles, incluso millones. Por ello puede que nos interese limitar en número de registros a utilizar.

Si queremos, hacer una consulta sobre los primero 4 registros de una tabla, podemos utilizar la variable reservada ROWNUM.

SELECT * FROM Cliente
WHERE ROWNUM <= 3;

Esto solo funciona para Oracle, en otros sistemas de bases de datos la función es distinta. Así,  en SQL Server o MS Access, la misma consulta se escribiría:

SELECT TOP 3 * FROM Cliente;

En estos dos sistemas, podemos indicar un porcentaje en lugar de un número absoluto:

SELECT TOP 50 PERCENT * FROM Cliente;

Por su parte,  el Sistema MySQL utiliza la Cláusula LIMIT:

SELECT * FROM Cliente
LIMIT 3;

En el entorno de pruebas, tal cual lo señalo abajo, solamente funcionará la sentencia correspondiente a Oracle. La otras dos las indico aquí para señalar que esta operación  no se realiza de la misma forma en todos los sistemas.

Por último, veremos en éste capítulo del curso como guardar los resultados de una consulta SELECT. Hasta ahora hemos realizado consultas que nos muestran un resultado, pero no se guarda dicho  resultado en ningún lugar. Éstas son útiles para consultas puntuales, o para programas externos que almacenarán los resultados a su manera.

Si queremos guardar estos resultados en la propia base de datos, tenemos la posibilidad de utilizar INSERT INTO con SELECT. La nueva tabla debe estar creada de antemano. Veamos el ejemplo ejecutando la siguiente sentencia:

INSERT INTO ClientesSantander
 SELECT * FROM Cliente
 WHERE Ciudad = 'Santander';

Si no se indica filtros con WHERE, esto nos puede servir para hacer copias de seguridad de tablas enteras. Antes de manipular el contenido con UPDATE o DELETE hacemos la copia por si nos equivocamos en las condiciones evitar perder datos.

Introducción de datos en las tablas

Dado que hemos visto una opción para insertar datos con INSERT INTO, voy a acabar la explicación de ésta cláusula. Si lo que queremos es introducir un cliente nuevo cuyos datos no existen, utilizamos la misma, pero de la siguiente forma:

INSERT INTO Cliente(Id, Dni, Nombre, Apellidos, Edad, Telefono, Ciudad)
VALUES (10,'12345678M', 'Olivia', 'Lerma Merino', 49, '878898565', 'Zaragoza');

Lo que indicamos en esta sentencia es: “Introduce en la tabla cliente un nuevo registro con las siguientes columnas rellenadas con éstos valores”. Por este sistema podemos dejar algunos de los valores nulos de la siguiente forma:

INSERT INTO Cliente(Id, Nombre, Apellidos, Edad)
VALUES (11, ' Alejandro', 'Hernandez Fernandez', 34);

Si introducimos todos los datos en el mismo orden que están declaradas las columnas, nos podemos saltar éstas:

INSERT INTO Cliente
VALUES (12,'72987654Y', 'Nuria', 'Vigo Lomas', 21, '999999999', 'Sevilla');

Probando los ejemplos de código de éste artículo

Para probar los ejemplos de código y experimentar con las consultas puedes ir al siguiente enlace:

http://sqlfiddle.com/#!4/1d4f8

Si está en blanco el cuadro de texto sobre el botón “Build Schema”, pegar el siguiente código y pulsar sobre dicho botón.

CREATE TABLE Cliente (
  Id int,
  Dni varchar(9),
  Nombre varchar(255),
  Apellidos varchar(255),
  Edad number(3),
  Telefono varchar (255),
  Ciudad varchar (255)
);

CREATE TABLE ClientesSantander AS SELECT * FROM Cliente;

INSERT INTO Cliente(Id, Dni, Nombre, Apellidos, Edad, Telefono, Ciudad)
VALUES (1,'11111111A', 'Juan', 'Pérez Mora', 19, '111111111', '');

INSERT INTO Cliente(Id, Dni, Nombre, Apellidos, Edad, Telefono, Ciudad)
VALUES (2,'22222222B', 'Isabel', 'Jimeno Hoyo', 23, '22222222', 'Madrid');

INSERT INTO Cliente(Id, Dni, Nombre, Apellidos, Edad, Telefono, Ciudad)
VALUES (3,'33333333C', 'Patricia', 'Rodriguez Denia', null, '333333333', 'Valladolid');

INSERT INTO Cliente(Id, Dni, Nombre, Apellidos, Edad, Telefono, Ciudad)
VALUES (4,'44444444D', 'Mario', 'Fernandez Bosque', 31, '444444444', 'Zamora');

INSERT INTO Cliente(Id, Dni, Nombre, Apellidos, Edad, Telefono, Ciudad)
VALUES (5,'55555555E', 'Lucia', 'Cobo Valero', 34, '555555555', 'Santander');

INSERT INTO Cliente(Id, Dni, Nombre, Apellidos, Edad, Telefono, Ciudad)
VALUES (6,'66666666F', 'Clarise', 'Dupon', 32, '666666666', 'Sevilla');

INSERT INTO Cliente(Id, Dni, Nombre, Apellidos, Edad, Telefono, Ciudad)
VALUES (7,'77777777G', 'Guillermo', 'Tuy Higuera', 60, '777777777', 'Zamora');

INSERT INTO Cliente(Id, Dni, Nombre, Apellidos, Edad, Telefono, Ciudad)
VALUES (8,'88888888H', 'Juan', 'Dima Niquel', 58, '888888888', 'Bilbao');

INSERT INTO Cliente(Id, Dni, Nombre, Apellidos, Edad, Telefono, Ciudad)
VALUES (9,'99999999I', 'Julieta', 'Montesco Lomas', 27, '', 'Valladolid');

Create Table Proveedor (
  Id int,
  Nombre varchar(255)
);
INSERT INTO Proveedor(Id, Nombre) VALUES (1, 'Campoamor');
INSERT INTO Proveedor(Id, Nombre) VALUES (2, 'Piensos Lola');
INSERT INTO Proveedor(Id, Nombre) VALUES (3, 'Maderas Pepe');

En el recuadro de la derecha se escriben las consultas y se ejecutan pulsando sobre “Run SQL”. En la parte inferior se mostrarán los resultados de la ejecución de la consulta. Para ver la diferencia después de las sentencias UPDATE o DELETE, ejecuta la sentencia:

SELECT * FROM Cliente;

Artículos anteriores del curso de SQL:

Capítulo 1: Introducción al SQL y las bases de datos relacionales

Capítulo 2: La cláusula WHERE, filtrando datos

Capítulo 3: SELECT Avanzado e INSERT INTO

El artículo #Curso SQL: SELECT avanzado e INSERT INTO apareció por primera vez en Instinto Binario.