Maestría en Bioinformática Bases de Datos y Sistemas de Información SQL: SELECT Ing. Alfonso Vicente, PMP [email protected] Agenda SELECT en una tabla Joins Proyección y selección DISTINCT Funciones escalares ORDER BY GROUP BY / Funciones de agregación Agenda SELECT en una tabla Joins Producto cartesiano Equi joins Outer joins Agenda SELECT en una tabla Joins Proyección y selección DISTINCT Funciones escalares ORDER BY GROUP BY / Funciones de agregación SELECT en una tabla Proyección y selección • La proyección permite seleccionar las columnas, la selección permite seleccionar las tuplas SELECT en una tabla Proyección y selección • Sintaxis básica SELECT <lista_columnas> FROM <tabla> WHERE <predicado>; -- proyección -- selección • Ejemplo SELECT id, nombre, apellido, mail FROM empleados WHERE sueldo > 80000; SELECT en una tabla DISTINCT • Al realizar proyección, se pueden perder las claves y pueden aparecer tuplas repetidas • La cláusula DISTINCT permite eliminar las tuplas duplicadas • Ejemplo SELECT DISTINCT apellido FROM empleados WHERE sueldo > 80000; SELECT en una tabla Funciones escalares • Los predicados pueden incluir funciones escalares built-in (predefinidas) o creadas por el usuario. Algunas son: +, -, *, /, abs, pow, length, substr, hex, locate, replace, add_months, to_char, nlv, coalesce (muchas dependen del RDBMS) • Ejemplos: SELECT id, nombre, apellido, mail FROM empleados WHERE length(nombre) > 10; SELECT id, nombre, apellido, mail FROM empleados WHERE soundex(nombre) = soundex('maicol'); -- Sólo en DB2 SELECT en una tabla Funciones escalares • Hay funciones para modificar los nulos, de forma de interpretarlos y presentarlos correctamente en un reporte • Ejemplo: SELECT id, nombre, apellido, nvl(to_char(sueldo), 'no percibe sueldo') sueldo FROM empleados WHERE sueldo < 20000 or sueldo is null; SELECT en una tabla ORDER BY • No se puede asumir ningún orden, a menos que se explicite mediante la cláusula ORDER BY • Ejemplos: SELECT sueldo, nombre, apellido, mail FROM empleados WHERE departamento = 3 ORDER BY sueldo DESC; SELECT apellido, nombre, telefono FROM empleados ORDER BY apellido, nombre; SELECT en una tabla GROUP BY / Funciones de agregación • La cláusula GROUP BY permite agrupar los datos que tengan valores iguales por algún conjunto de columnas • Ejemplos: SELECT departamento, count(*) FROM empleados GROUP BY departamento ORDER BY departamento; SELECT departamento, min(sueldo) FROM empleados GROUP BY departamento ORDER BY departamento; SELECT en una tabla GROUP BY / Funciones de agregación • Funciones de agregación: count, min, max, sum, avg (otras dependen del RDBMS) • HAVING: Permite filtrar sobre los resultados de las funciones de agregación • Ejemplo: departamentos y cantidad de empleados, de los departamentos que tengan al menos 10 empleados SELECT departamento, count(*) FROM empleados GROUP BY departamento HAVING count(*) >= 10; Agenda SELECT en una tabla Joins Producto cartesiano Equi joins Outer joins Joins Producto cartesiano • Basados en la idea de producto y división entre relaciones • El producto cartesiano entre dos relaciones R1 x R2, es la combinación de todas las parejas (t1, t2) donde t1 es una tupla de R1 y t2 es una tupla de R2 • Si R1 tiene cardinalidad N y R2 cardinalidad M el producto cartesiano R1 x R2 tendrá cardinalidad N x M • ¿Qué obtenemos del producto cartesiano de una tabla de clientes con 2.000 tuplas y una tabla de teléfonos con 4.000 tuplas? ¿todas las tuplas nos interesan? Joins Producto cartesiano SQL> select id, nombre, apellido 2 from clientes; SQL> select id_cliente, telefono 2 from telefonos_cliente; ID ---------1 2 ID_CLIENTE TELEFONO ---------- ---------1 24002425 2 23087373 2 44722020 NOMBRE ---------Juan Martin APELLIDO ---------Lopez Garcia SQL> select c.id, c.nombre, c.apellido, t.id_cliente, t.telefono 2 from clientes c, telefonos_cliente t; ID ---------1 1 1 2 2 2 NOMBRE ---------Juan Juan Juan Martin Martin Martin APELLIDO ID_CLIENTE TELEFONO ---------- ---------- ---------Lopez 1 24002425 Lopez 2 23087373 Lopez 2 44722020 Garcia 1 24002425 Garcia 2 23087373 Garcia 2 44722020 ? Joins Equi joins • Nos interesan las tuplas donde matchea el valor de clientes.id con el de telefonos_cliente.id_cliente SQL> select c.id, c.nombre, c.apellido, t.id_cliente, t.telefono 2 from clientes c, telefonos_cliente t 3 where c.id = t.id_cliente; ID ---------1 2 2 NOMBRE ---------Juan Martin Martin APELLIDO ID_CLIENTE TELEFONO ---------- ---------- ---------Lopez 1 24002425 Garcia 2 23087373 Garcia 2 44722020 • Ya que el ID se repite, podemos omitir una de las columnas, o incluso omitir las dos ya que es una surrogate key Joins Equi joins • Ejemplo: reporte de clientes y teléfonos SQL> break on cliente skip 1 -- Específico de Oracle SQL> select c.nombre||' '||c.apellido cliente, t.telefono 2 from clientes c, telefonos_cliente t 3 where c.id = t.id_cliente; CLIENTE TELEFONO --------------------- ---------Juan Lopez 24002425 Martin Garcia 23087373 44722020 Joins Outer joins • Motivación: ¿por qué faltan empleados en el reporte? SQL> select e.nombre, e.apellido, d.nom_departamento 2 from empleados e, departamentos d 3 where e.departamento = d.id_departamento; NOMBRE --------------Guzman ... APELLIDO --------------Perez ... NOM_DEPARTAMENTO -------------------Administracion ... 15 rows selected. SQL> select count(*) from empleados; COUNT(*) ---------18 Joins Outer joins • No hay un departamento con ID NULL en la tabla de departamentos, y aunque lo hubiera, NULL = NULL se evalúa como falso • Podemos querer relajar el join para aceptar tuplas de una de las tablas aunque tengan valor NULL en alguna columna por la que se realiza el join • En el caso anterior, querríamos las tuplas “de la izquierda”: Nombre Apellido Departamento ---------- ---------- ------------ Matías Pereyra <null> Joins Outer joins • El outer join permite hacer exactamente eso (left, nos da las columnas de la izquierda que no matchean): SQL> select e.nombre, e.apellido, d.nom_departamento 2 from empleados e left outer join departamentos d 3 on e.departamento = d.id_departamento; NOMBRE --------------Luis ... Luisa Matias Juana Jorge APELLIDO --------------Rodriguez ... Herrera Pereyra Garcia Lopez 18 rows selected. NOM_DEPARTAMENTO -------------------Administracion ... Investigacion Joins Outer joins • Right, nos da las columnas de la derecha que no matchean: SQL> select e.nombre, e.apellido, d.nom_departamento 2 from empleados e right outer join departamentos d 3 on e.departamento = d.id_departamento; NOMBRE --------------Guzman ... Emiliano Astrid Santiago Guillermo Martin APELLIDO --------------Perez ... Pereira Brandner Fontenla Eastman Beracochea 16 rows selected. NOM_DEPARTAMENTO -------------------Administracion ... Investigacion Investigacion Investigacion Investigacion Investigacion Sistemas Joins Outer joins • Left outer join nos introduce tuplas en el join, que sólo existen en la tabla de la izquierda • Right outer join nos introduce tuplas en el join, que sólo existen en la tabla de la derecha • Existe también el full outer join, que nos introduce en el join las tuplas que introduce el left y el right outer join (probarlo) • Oracle tiene una sintaxis alternativa (pero propietaria) para especificar los outer joins en el predicado: where e.departamento(+) = d.id_departamento; Joins Subconsultas • El resultado de una consulta (result-set) se puede usar como subconsulta para predicar en otra • Ejemplo: queremos los empleados de Ventas e Investigación SQL> 2 3 4 5 6 7 select nombre, apellido from empleados where departamento in ( select id_departamento from departamentos where nom_departamento in ('Ventas', 'Investigacion') ); • Usamos “in” porque el result-set es un conjunto … Joins Subconsultas • Si estamos seguros que el result-set es de cardinalidad 1, podemos usar “=“ • Ejemplo: queremos los empleados de Ventas SQL> 2 3 4 5 6 7 select nombre, apellido from empleados where departamento = ( select id_departamento from departamentos where nom_departamento = 'Ventas' ); NOMBRE --------------Fernando ... APELLIDO --------------Pereyra ... Joins Subconsultas • Si nos equivocamos, y el result-set es de cardinalidad > 1, obtendremos un error SQL> select nombre, apellido 2 from empleados 3 where departamento = ( 4 select id_departamento 5 from departamentos 6 ); select id_departamento * ERROR at line 4: ORA-01427: single-row subquery returns more than one row Joins Operaciones de conjuntos • Se pueden realizar las operaciones de conjuntos UNION, INTERSECT y MINUS, con sus variantes “ALL” SQL> select sysdate fecha from dual 2 union select sysdate fecha from dual; FECHA ---------23/05/2012 SQL> select sysdate fecha from dual 2 union all select sysdate fecha from dual; FECHA ---------23/05/2012 23/05/2012 Ejercicios Ejercicios • Obtener los nombres y apellidos de los empleados que tendrán más de un año de antigüedad al 01/06/2012 • Obtener los subtotales de sueldos de cada departamento y el total de sueldos, en la misma consulta • Obtener el nombre de todos los empleados, con el nombre de su cargo y el nombre de su departamento Ejercicios Nombres y apellidos de los empleados que tendrán más de un año de antigüedad al 01/06/2012 SQL> 2 3 4 select nombre, apellido from empleados where add_months(fecha_ingreso, 12) <= to_date('01/06/2012', 'dd/mm/yyyy'); NOMBRE --------------Matias ... Rodrigo Emiliano Astrid Santiago Guillermo APELLIDO --------------Pereyra ... Lemos Pereira Brandner Fontenla Eastman 14 rows selected. Ejercicios Subtotales de sueldos de cada departamento y el total de sueldos, en la misma consulta SQL> 2 3 4 5 6 7 8 select nvl(d.nom_departamento, 'Sin departamento') departamento, sum(e.sueldo) sueldos from empleados e left outer join departamentos d on e.departamento = d.id_departamento group by d.nom_departamento union all select 'Total', sum(sueldo) from empleados; DEPARTAMENTO SUELDOS -------------------- ---------Ventas 232000 Investigacion 547000 Sin departamento 100000 Administracion 232000 Total 1111000 Ejercicios Nombre de todos los empleados, con el nombre de su cargo y el nombre de su departamento SQL> select e.nombre, e.apellido, c.nom_cargo, d.nom_departamento 2 from (empleados e left outer join departamentos d 3 on e.departamento = d.id_departamento), cargos c 4 where e.cargo = c.id_cargo; NOMBRE --------------Rosana ... Karina Luisa Matias Juana Jorge APELLIDO -----------Nu??ez ... Garcia Herrera Pereyra Garcia Lopez 18 rows selected. NOM_CARGO ---------------------Administrativo senior ... Subgerente Gerente Director Socio Director Socio Director NOM_DEPARTAMENTO ----------------Administracion ... Investigacion Investigacion