SELECT Tutorial

Tutorial Breve y Conciso de consultas SELECT en SQL Prof. J. Ignacio Vázquez Herrera 0. Insumos. Para los ejemplos de

Views 205 Downloads 4 File size 333KB

Report DMCA / Copyright

DOWNLOAD FILE

Recommend stories

Citation preview

Tutorial Breve y Conciso de consultas SELECT en SQL Prof. J. Ignacio Vázquez Herrera

0. Insumos. Para los ejemplos de demostración nos basaremos en el siguiente esquema:

En la relación PERTENECE, la participación tanto de EMPLEADO como de DEPARTAMENTO es obligatoria. La cardinalidad es de uno a muchos (1:M), es decir, en un departamento hay muchos empleados, pero un empleado solo puede pertenecer a un departamento. En la relación DIRIGE la participación de EMPLEADO es opcional o parcial, mientras que la de DEPARTAMENTO es obligatoria o total, es decir, no todo empleado dirige un departamento, mientras que un departamento debe tener forzosamente un gerente o director. La cardinalidad es de uno a uno (1:1). En la relación CONTROLA, la participación de PROYECTO es obligatoria y la de DEPARTAMENTO es parcial, es decir, todo proyecto debe ser controlado por un departamento pero no todos los departamentos controlan proyectos; la cardinalidad es de uno a muchos (1:M), o sea, un departamento puede controlar varios proyectos pero un proyecto es controlado por un solo departamento. Las tablas que se generan a partir del diagrama arriba mostrado son info_empleados, info_departamentos e info_proyectos. Las llaves primarias están marcadas en morado, mientras que las llaves foráneas (que vinculan a una tabla con otra) en color naranja. Info_empleados id_empleado QN105 QN109 QN118 QN119 QN120 QN216 QN103

nombre LINA DEL CARMEN EDUARDO JUAN ELOY GILDA IRASEMA JAVIER ESTEBAN MIGUEL ANGEL

Apellidos GONZALEZ LOZOYA DIAZ NAVARRO MENDEZ JAMANGAPE BAUTISTA GAMBOA PEREZ PEÑARON ALVAREZ DUARTE URDAPILLETA RIVERA

edad 39 54 42 31 33 22 46

departamento 33 33 33 33 33 33 46

cargo CONTADOR CONTADOR SECRETARIA JEFE DE OFICINA CONTADOR AUXILIAR JEFE DE OFICINA

salario 16000 17000 14000 36000 15000 27000 19000

QN125 QN159 QN185 QN131 QN158 QN165 QN203 QN106 QN132 QN141 QN150 QN163 QN205 QN104 QN111 QN117 QN187 QN211 QN134 QN156 QN195 QN213 QN100 QN101 QN107 QN121 QN113 QN115 QN123 QN129 QN133 QN139 QN145 QN149 QN160 QN191 QN193 QN197 QN201 QN209 QN144 QN152 QN171 QN208 QN210 QN130 QN146 QN161 QN192 QN200 QN147 QN153 QN155 QN108 QN137 QN204 QN154 QN164 QN184 QN207 QN212 QN162 QN168 QN188 QN138 QN172 QN173 QN196 QN206 QN215 QN116

AMILCAR JOSE MANUEL RUBI MAYRA ELVIRA MANUEL NAZARIO JUAN IGNACIO BERNARDO EMA LOURDES JAVIER EDUARDO RICARDO FERMIN ALVARO GUADALUPE ELIN ROLANDO VICTOR MANUEL CRISTINA JUAN RAMON FRANCISCO JOSE LUIS BERNARDO JOAQUIN IGNACIO BEATRIZ ADRIANA BLANCA ESTHELA MARCO AURELIO JOSE GERARDO MARIA CELINA EVENECER GERARDO AGRIPINO MIGUEL IGNACIO ISRAEL ISMAEL LAZARO SALVADOR PEDRO JOSE JAIME LIZ EDITH ERVEY ROBERTO JUAN JOSE RAMON ERICK GLADIS JOSE CARLOS EDGAR GERARDO ENRIQUE RIGOBERTO GILBERTO JOSE ANTONIO MA DEL CONSUELO JESUS MANUEL LEANDRO DANIEL RIGOBERTO JOSE LUIS JOSE ANGEL ROSA AMELIA GILBERTO JOSE ANTONIO ARMANDO ASMET ALMA ANGELICA MALAQUIAS MA DE JESUS JOSE DE JESUS ASTRID YARELI MAYRA FLORA CRUZ RAFAEL EDGARDO VICTOR MANUEL ROBERTO DE JESUS MA. DE LOURDES

QUINTERO LEON VEGA LEON RODRIGUEZ SANDOVAL GONZALEZ GUTIERREZ CAMPOS QUEZADA MESTAS ARJONA NEYRA ZARRAGA ONTIVEROS VALENZUELA MORALES VELASCO LEON VALDIVIA AVILA GARCIA RIVERA FLORES GARCIA DOMINGUEZ HERNANDEZ SOTO LLAMAS PALACIOS GONZALEZ ARELLANO MENDIVIL ROMERO LOMELI ROSAS MENDOZA DIAZ RODRIGUEZ CASTRO ELIZALDE CARRILLO PEREZ ROMERO RAMIREZ GARCIA SERNA PEREZ GUILLEN MEZA URIARTE VARGAS BELTRAN PEREZ MORENO MIRAMONTES VEGA GARCIA CELAYA RODRIGUEZ MARTINEZ CISNEROS CASTAÑEDA ROBLES RODRIGUEZ CHACON DAMIAN SILVA AVILA GONZALEZ VALDEZ SANCHEZ PEREZ LEON ANSALDO GUTIERREZ RUIZ CRUZ JIMENEZ MORA PEREZ JIMENEZ VELAZQUEZ MENDOZA VALENCIA GARCIA AYVAR YAÑEZ SOTO MACIAS PIZ ROBLES SERRANO CABRERA GONZALEZ GONZALEZ REYES HERNANDEZ RUIZ CRUZ LOPEZ ALTAMIRANO VAZQUEZ PIMENTEL DERAS ANDRADE TORRES DE LA CRUZ BELTRAN VELAZQUEZ MORA RODRIGUEZ PEREZ JIMENEZ CHAVEZ RODRIGUEZ FRAGA LOPEZ NUCAMENDI MOLINA NUÑEZ DE SANTIAGO CASTAÑEDA MACIAS MARTINEZ ESCOBEDO CHAVEZ IBARRA ELIZONDO MURO CHAVEZ RODRIGUEZ MENDOZA GUTIERREZ RIVERA RAMIREZ JIMENEZ LOPEZ RODRIGUEZ LEON CABRERA RAMIREZ

36 42 32 56 23 22 37 47 51 57 36 54 22 34 42 25 29 38 35 42 41 28 25 18 53 21 30 49 31 34 32 28 33 36 57 34 31 55 42 23 23 39 31 49 41 31 37 42 30 22 51 24 56 44 24 52 28 21 43 37 33 53 23 50 23 51 56 57 34 55 38

46 46 46 56 56 56 56 47 47 47 47 47 47 34 34 34 34 34 35 35 35 35 25 25 25 25 30 30 30 30 30 30 30 30 30 30 30 30 30 30 41 41 41 41 41 22 22 22 22 22 56 56 57 52 52 52 33 33 33 33 33 50 50 50 55 55 55 55 55 55 22

ALMACENISTA AUXILIAR SECRETARIA SECRETARIA JEFE DE OFICINA TECNICO INGENIERO SECRETARIA AUXILIAR JEFE DE OFICINA PROFESOR PROFESOR PROFESOR AUXILIAR SECRETARIA JEFE DE OFICINA COMPRADOR COMPRADOR CONTADOR AUXILIAR JEFE DE OFICINA SECRETARIA JEFE DE OFICINA AUXILIAR SECRETARIA TECNICO INGENIERO INGENIERO JEFE DE OFICINA INGENIERO INGENIERO INGENIERO INGENIERO INGENIERO TECNICO SECRETARIA INGENIERO DIBUJANTE DIBUJANTE INGENIERO SECRETARIA JEFE DE OFICINA TECNICO TECNICO TECNICO INTENDENTE INTENDENTE INTENDENTE INTENDENTE INTENDENTE TECNICO TECNICO TECNICO JEFE DE OFICINA AUXILIAR SECRETARIA INGENIERO AUXILIAR INGENIERO JEFE DE OFICINA SECRETARIA JEFE DE OFICINA SECRETARIA AUXILIAR AUXILIAR JEFE DE OFICINA SECRETARIA PROGRAMADOR PROGRAMADOR TECNICO SECRETARIA

13000 17000 11000 10000 18000 12000 15000 15000 17000 22000 16000 20000 19000 17000 10000 22000 13000 12000 12000 17000 25000 11000 42000 33000 16000 17000 22000 17000 25000 17000 15000 15000 15000 20000 12000 11000 20000 13000 14000 22000 9000 21000 13000 13000 17000 6000 7000 6000 8000 6000 8000 7000 10000 21000 17000 12000 13000 15000 13000 17000 9000 23000 10000 13000 20000 25000 12000 19000 18000 15000 12000

QN124 QN127 QN112 QN140 QN142 QN143 QN186 QN102 QN110 QN114 QN128 QN136 QN148 QN166 QN189 QN190 QN198 QN199 QN202 QN214 QN151 QN157 QN169 QN170 QN194

JACOBO RAMSES SERGIO JOSE DE JESUS SECUNDINO JOSE NOE MARCO ANTONIO JUAN JOSE BUENAVENTURA MAURICIO NOLAN RAMON GONZALO ISRAEL LIZZETTE VICTOR YOLANDA ROSENDO GUSTAVO ADOLFO JAVIER PETRONILO FRANCISCO JAVIER JULIA ANABEL ANGEL FLORENCIO MARIA DE JESUS GILBERTO VICTOR ALEJANDRO

RODRIGUEZ CARRILLO AVILA GONZALEZ QUINTANILLA GONZALEZ RINCON AYALA LLAMAS OCEGUEDA SAUCEDO VERTIZ SALAS UREÑA BARRERAS TRASVIÑA JIMENEZ RUIZ GARCIA BERNAL VALDEZ BENAVIDES RIVERA FLORES NESTA CASTAÑEDA MONROY COVARRUBIAS PARADA PONCE SOLDAN CORDOVA CELAYA RODRIGUEZ CELAYA MOTA DELGADO CHONG SUAREZ ANGUIANO RODRIGUEZ PAREDES FLORES LUNA CERVANTES CASTRO MORALES MENDEZ GOMEZ Y ACOSTA

18 22 47 18 51 44 43 19 50 52 44 54 33 27 37 22 37 56 48 54 23 56 33 55 53

22 23 43 43 43 43 43 54 54 54 54 54 54 54 54 54 54 54 54 54 53 53 53 53 53

JEFE DE OFICINA AUXILIAR CHOFER CHOFER CHOFER CHOFER CHOFER VENDEDOR VENDEDOR VENDEDOR JEFE DE OFICINA VENDEDOR VENDEDOR SECRETARIA VENDEDOR VENDEDOR VENDEDOR AUXILIAR VENDEDOR VENDEDOR VIGILANTE VIGILANTE VIGILANTE VIGILANTE VIGILANTE

Info_departamentos id_departamento 39 46 56 47 34 35 25 30 41 22 57 52 33 50 55 23 43 54 53

nombred ADMINISTRACION ALMACEN CALIDAD CAPACITACION COMPRAS CONTABILIDAD DIRECCION ESTUDIOS INFORMATICA INTENDENCIA MANTENIMIENTO PERSONAL PROTECCION CIVIL SINDICATO SISTEMAS TELECOMUNICACIONES TRANSPORTES VENTAS VIGILANCIA

gerente QN105 QN103 QN131 QN106 QN104 QN134 QN100 QN113 QN210 QN200 QN155 QN204 QN212 QN188 QN215 QN127 QN186 QN214 QN194

Info_proyectos id_proyecto 5 8 13 17 18 21 22 25 31 43 45 52 55 57

nombrepr REESTRUCTURACION FINANCIERA REVISION ORGANIZACIONAL SISTEMA VIRTUAL DE CAPACITACION ACTUALIZACION DE PASIVOS ACTUALIZACION DE INVENTARIOS ESTUDIO DE IMPACTO AMBIENTAL LA YESCA ESTUDIO DE FACTIBILIDAD LA YESCA ESTUDIO HIDROENERGETICO RIO YAQUI RENOVACION PARQUE INFORMATICO MANTENIMIENTO ANUAL SISTEMA INSTITUCIONAL DE RECURSOS HUMANOS ACTUALIZACION DE GRUPOS ORGANICOS SISTEMA DE TECNOLOGIAS DE LA INFORMACION COMPACTACION DE CATEGORIAS

numd 39 39 47 35 46 30 30 30 41 41 52 50 55 50

24000 18000 9000 8000 9000 10000 9000 18000 19000 20000 27000 21000 20000 12000 16000 17000 14000 21000 13000 22000 6000 8000 7000 7000 8000

Por otro lado, para los ejercicios propuestos se utilizará el siguiente esquema:

En la relación PEDIDOS, la participación tanto de CLIENTE como de PRODUCTO es obligatoria. La cardinalidad es de muchos a muchos (M:M), es decir, un cliente puede hacer varios pedidos y un producto se vende en muchos pedidos. Debido a esto se tiene que crear otra tabla para la relación pedidos con sus respectivos atributos, más las llaves de las entidades CLIENTE y PRODUCTO como llaves foráneas. La llave primaria la forman la combinación de las llaves foráneas mencionadas y el atributo id. Las tablas que se generan a partir del diagrama anterior son partidas_pedidos, info_clientes e info_productos. partidas_pedidos id_pedido 1 2 2 3 4 5 6 7 7 8 9 10 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 24 25 26 27 28 29

cliente 10558 10556 10556 10530 10512 10525 10501 10538 10538 10545 10564 10562 10101 10330 10101 10298 10298 10515 10299 10530 10449 10439 10101 10449 10534 10439 10298 10298 10530 10530 10410 10438 10438

fecha_pedido 1999-01-03 1999-01-05 1999-01-05 1999-01-19 1999-01-20 1999-04-02 1999-04-18 1999-04-20 1999-04-20 1999-06-03 1999-06-03 1999-06-20 1999-06-30 1999-06-30 1999-07-01 1999-07-01 1999-07-01 1999-07-03 1999-07-06 1999-08-05 1999-08-13 1999-08-14 1999-08-18 1999-09-01 1999-09-09 1999-09-18 1999-09-19 1999-09-19 1999-10-16 1999-10-22 1999-10-28 1999-11-01 1999-11-02

producto 20 1 12 24 10 15 2 16 22 8 1 21 19 6 7 20 23 12 17 8 13 23 10 25 3 24 12 25 2 16 3 18 1

Cantidad 2 2 4 2 3 4 1 2 1 5 1 4 3 1 4 1 2 4 1 2 1 2 1 1 2 1 2 2 1 3 1 4 1

30 31 32 33 34 35 36 37 38 39 40 41 42 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 57 57 58 59 60 61 62 63 64 64 64 65 66 67 68 69 70

10512 10556 10298 10551 10449 10551 10540 10449 10101 10330 10556 10101 10525 10525 10299 10438 10413 10520 10410 10315 10520 10540 10449 10101 10298 10449 10518 10298 10330 10330 10330 10501 10551 10520 10525 10339 10515 10545 10545 10545 10534 10556 10510 10551 10525 10534

1999-11-04 1999-11-20 1999-12-01 1999-12-03 1999-12-15 1999-12-16 1999-12-19 1999-12-22 1999-12-30 2000-01-01 2000-01-01 2000-01-02 2000-01-04 2000-01-04 2000-01-18 2000-01-18 2000-01-19 2000-01-21 2000-01-30 2000-02-02 2000-02-15 2000-02-17 2000-02-29 2000-03-08 2000-03-18 2000-03-19 2000-03-21 2000-04-01 2000-04-19 2000-04-19 2000-04-19 2000-05-02 2000-07-01 2000-07-02 2000-07-20 2000-07-27 2000-08-19 2000-08-19 2000-08-19 2000-08-19 2000-10-03 2000-10-10 2000-11-02 2000-11-04 2000-11-23 2000-02-21

8 22 6 4 2 23 9 5 8 11 8 12 20 11 9 24 22 16 13 4 23 2 11 3 14 21 10 15 16 23 8 1 19 20 9 18 10 2 14 19 15 3 8 1 16 8

4 2 1 4 1 2 2 1 3 4 3 1 2 2 1 1 4 4 1 1 1 2 1 2 1 2 2 1 1 1 2 2 2 2 2 1 3 2 3 2 2 3 3 4 4 2

info_clientes id_cliente

nombre

10101 10298 10299 10315 10325 10329 10330 10338 10339 10408 10410 10413 10419 10429 10438 10439 10449 10501 10510 10512 10515

JUAN PEDRO MARTIN LISA ROBERTO MARIA INES MIGUEL ANTONIO ELOY ANA RONALDO LINDA SARA SERGIO CONRADO ISABELA RICARDO MARTHA PEDRO YURIDIA

apellido

Ciudad

Estado

LOPEZ GUTIERREZ HERNANDEZ MARTINEZ JIMENEZ MENDOZA VAZQUEZ HERRERA SANCHEZ CHAVEZ GONZALEZ SANTANA CERVERA VILLANUEVA PEREZ TORRES MARQUEZ LOPEZ GONZALEZ HERNANDEZ TORRES

GUADALAJARA CD. JUAREZ ZAPOPAN PUEBLA MAZATLAN TUXTLA VILLAHERMOSA VILLAHERMOSA CHIHUAHUA CHIHUAHUA MERIDA TLAQUEPAQUE NOGALES CHILPANCINGO DURANGO DURANGO GUADALAJARA MORELIA LEON CULIACAN IRAPUATO

JALISCO CHIHUAHUA JALISCO PUEBLA SINALOA CHIAPAS TABASCO TABASCO CHIHUAHUA CHIHUAHUA YUCATAN JALISCO SONORA GUERRERO DURANGO DURANGO JALISCO MICHOACAN GUANAJUATO SINALOA GUANAJUATO

10518 10520 10525 10530 10534 10538 10540 10545 10551 10556 10558 10562 10564

ENRIQUE JOSE MIGUEL MARIA SILVIA JUAN MARTIN ANA JIMENA DANIEL JAVIER ANTONIO ANDRES

CHAVEZ TERRONES SANDOVAL MIRELES SANCHEZ VAZQUEZ SERRANO HUERTA HERNANDEZ PEREZ SAUCEDO VEGA VELEZ

ZAPOPAN URUAPAN HERMOSILLO ACAPULCO GUADALAJARA GUANAJUATO MORELIA GUADALAJARA PTO PROGRESO VERACRUZ OAXACA COLIMA MANZANILLO

info_productos id_producto

Descripción

precio

1 2 3 4 5 6 7 8 9 13 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25

ALMOHADA BICICLETA BOLSA DE DORMIR BRUJULA CANOA CASCO CHALECO SALVAVIDAS CHAMARRA COLCHON INFABLE GUANTES IMPERMEABLE LAMPARA LINTERNA NAVAJA DE BOLSILLO OREJERAS PALA PARACAIDAS PARAGUAS PASAMONTA¥AS PATINES REMO PARA CANOA SILLA DE JARDIN SUETER TIENDA ZAPATOS DE NIEVE

150 3800 600 120 2800 280 700 450 320 345 205 280 170 300 135 180 12500 80 500 460 450 250 600 900 1200

JALISCO MICHOACAN SONORA GUERRERO JALISCO GUANAJUATO MICHOACAN JALISCO YUCATAN VERACRUZ OAXACA COLIMA COLIMA

1. Introducción a la sentencia SELECT. La sentencia SELECT se utiliza para consultar la BD y obtener datos que cumplan el criterio o condición que se especifica. Tiene cinco cláusulas principales a elegir, sin embargo, FROM es la única obligatoria. Cada una de las cláusulas tiene una vasta selección de opciones, parámetros, etc. Todas se listan a continuación, aunque se ven con más detalle más adelante. Formato de la sentencia SELECT: SELECT FROM [WHERE [GROUP BY [HAVING [ORDER BY

[ALL | DISTINCT] columna1[,columna2] tabla1[,tabla2] "condiciones"] "lista-columnas"] "condiciones"] "lista-columnas" [ASC | DESC] ]

Ejemplo: SELECT nombre, edad, salario FROM info_empleados WHERE edad > 50;

La clausula SELECT elige las columnas a mostrar en el resultado, en FROM declaramos las tablas a utilizar en la consulta, mientras que WHERE selecciona un número de filas en base a un predicado o condición. El orden de ejecución de las tres clausulas es: FROM, WHERE y finalmente SELECT. La sentencia anterior devolverá todos los valores de las columnas nombre, edad, y salario de la tabla empleado, cuya edad sea mayor de 50. nombre | edad | salario -------------------+------+---------EDUARDO JUAN ELOY | 54 | 17000.00 MAYRA ELVIRA | 56 | 10000.00 JAVIER EDUARDO | 51 | 17000.00 RICARDO | 57 | 22000.00 ALVARO GUADALUPE | 54 | 20000.00 MARIA CELINA | 53 | 16000.00 JOSE JAIME | 57 | 12000.00 JUAN JOSE | 55 | 13000.00 LEANDRO | 51 | 8000.00 RIGOBERTO | 56 | 10000.00 ROSA AMELIA | 52 | 12000.00 MALAQUIAS | 53 | 23000.00 MAYRA | 51 | 25000.00 FLORA CRUZ | 56 | 12000.00 RAFAEL EDGARDO | 57 | 19000.00 ROBERTO DE JESUS | 55 | 15000.00 JOSE NOE | 51 | 9000.00 RAMON GONZALO | 52 | 20000.00 LIZZETTE | 54 | 21000.00

PETRONILO JULIA ANABEL MARIA DE JESUS VICTOR ALEJANDRO (24 filas)

| | | | |

56 54 56 55 53

| 21000.00 | 22000.00 | 8000.00 | 7000.00 | 8000.00

Operadores Relacionales (de Comparación) = Igual > Mayor que < Menor que >= Mayor o igual que = 15000.00 AND cargo = 'PROGRAMADOR'; id_empleado | nombre | apellidos | cargo | salario -------------+----------------+----------------+-------------+---------QN196 | RAFAEL EDGARDO | RIVERA RAMIREZ | PROGRAMADOR | 19000.00 QN206 | VICTOR MANUEL | JIMENEZ LOPEZ | PROGRAMADOR | 18000.00 (2 filas)

Seleccionará id_empleado, nombre, apellido, cargo, y salario de la tabla info_empleados, donde el salario sea mayor o igual a 50000.00 y se tenga el cargo de 'PROGRAMADOR'. Para que las filas sean mostradas ambas condiciones deben ser verdaderas. Aunque no son requeridos, se pueden utilizar paréntesis alrededor de la expresión condicional, para hacerla más legible: SELECT FROM WHERE

id_empleado, nombre, apellidos, cargo, salario info_empleados (salario >= 50000.00) AND (cargo = 'PROGRAMADOR');

Este otro ejemplo: SELECT FROM WHERE

nombre, apellidos, cargo, salario info_empleados (cargo = 'VENDEDOR') OR (cargo = 'PROGRAMADOR');

nombre | apellidos | cargo | salario ------------------+-------------------+-------------+---------RAFAEL EDGARDO | RIVERA RAMIREZ | PROGRAMADOR | 19000.00 VICTOR MANUEL | JIMENEZ LOPEZ | PROGRAMADOR | 18000.00 BUENAVENTURA | BARRERAS TRASVINA | VENDEDOR | 18000.00

MAURICIO NOLAN RAMON GONZALO LIZZETTE VICTOR ROSENDO GUSTAVO ADOLFO JAVIER FRANCISCO JAVIER JULIA ANABEL (12 filas)

| | | | | | | | |

JIMENEZ RUIZ GARCIA BERNAL RIVERA FLORES NESTA CASTANEDA PARADA PONCE SOLDAN CORDOVA CELAYA RODRIGUEZ DELGADO CHONG SUAREZ ANGUIANO

| | | | | | | | |

VENDEDOR VENDEDOR VENDEDOR VENDEDOR VENDEDOR VENDEDOR VENDEDOR VENDEDOR VENDEDOR

| | | | | | | | |

19000.00 20000.00 21000.00 20000.00 16000.00 17000.00 14000.00 13000.00 22000.00

Seleccionará el nombre, apellido, cargo, y salario de la tabla info_empleados donde cargos sea igual a 'VENDEDOR' o 'PROGRAMADOR'.

Ejercicios de Repaso: 2.1 2.2 2.3 2.4 2.5

Mostrar id_producto, nombre y precio de la tabla info_productos para todos los productos que no sean “OREJERAS” o “GUANTES”. Desplegar las filas mientras no contengan alguno de los productos mencionados. listar la descripción y precio de todos los productos que comienzan con las letras 'S', 'P', o 'C'. Mostrar el nombre y apellidos de los clientes cuyo nombre comiencen con ‘R’ y sean de JALISCO o MICHOACAN. Listar los pedidos en los que se haya adquirido el producto con código ‘20’ durante el año de 1999. Supóngase que el campo fecha_pedido es un char(10). Desplegar la información de los clientes cuyo apellido empiece con ‘H’ y termine con ‘A’ y viva en un estado cuyo nombre lo formen 7 letras.

3. Subconsultas Ya que finalmente el resultado de una consulta es otra relación o tabla, es factible anidar una consulta dentro de otra. Un ejemplo sencillo es aquel que se puede escribir en lugar del que se realizó en la sección anterior: Encontrar los atributos id_empleado, nombre, apellido, cargo, y salario de la tabla

info_empleados, donde el salario sea mayor o igual a 50,000.00 y se tenga el cargo de 'PROGRAMADOR'. SELECT id_empleado, nombre, apellidos, cargo, salario FROM (SELECT * FROM info_empleados WHERE cargo='PROGRAMADOR') AS temp WHERE salario >= 15000.00; id_empleado | nombre | apellidos | cargo | salario -------------+----------------+----------------+-------------+---------QN196 | RAFAEL EDGARDO | RIVERA RAMIREZ | PROGRAMADOR | 19000.00 QN206 | VICTOR MANUEL | JIMENEZ LOPEZ | PROGRAMADOR | 18000.00 (2 filas)

Primero se seleccionaron a aquellos empleados que tienen el cargo de ‘PROGRAMADOR’ (en azul, entre paréntesis), al resultado se le asigna un alias (temp), para después efectuar la consulta externa. El siguiente ejemplo, en cambio, no se puede resolver como en la anterior sección, sino solo con subconsultas: Relacionar los empleados que ganan más que VICTOR MANUEL JIMENEZ LOPEZ, cuyo id de empleado es QN206. SELECT * FROM info_empleados WHERE salario >= (SELECT salario FROM info_empleados WHERE id_empleado='QN206'); id_empleado | nombre | apellidos | edad | dep | cargo | salario -------------+----------------+--------------------+------+-----+-----------------+---------QN119 | IRASEMA | BAUTISTA GAMBOA | 31 | 33 | JEFE DE OFICINA | 36000.00 QN216 | ESTEBAN | ALVAREZ DUARTE | 22 | 33 | AUXILIAR | 27000.00 QN103 | MIGUEL ANGEL | URDAPILLETA RIVERA | 46 | 46 | JEFE DE OFICINA | 19000.00 QN158 | MANUEL NAZARIO | CAMPOS QUEZADA | 23 | 56 | JEFE DE OFICINA | 18000.00 QN141 | RICARDO | LEON VALDIVIA | 57 | 47 | JEFE DE OFICINA | 22000.00 ... ... ... QN128 | ISRAEL | VALDEZ BENAVIDES | 44 | 54 | JEFE DE OFICINA | 27000.00 QN136 | LIZZETTE | RIVERA FLORES | 54 | 54 | VENDEDOR | 21000.00 QN148 | VICTOR | NESTA CASTANEDA | 33 | 54 | VENDEDOR | 20000.00 QN199 | PETRONILO | CELAYA MOTA | 56 | 54 | AUXILIAR | 21000.00 QN214 | JULIA ANABEL | SUAREZ ANGUIANO | 54 | 54 | VENDEDOR | 22000.00 (33 filas)

Es posible en ocasiones utilizar subconsultas para resolver problemas en los que participan 2 o más tablas, por ejemplo: Encontrar el nombre del departamento donde labora el empleado cuyo id es QN206. SELECT nombred FROM info_departamentos WHERE id_departamento = (SELECT departamento FROM info_empleados WHERE id_empleado='QN206'); nombred ---------SISTEMAS (1 fila)

Primero se encuentra el código del departamento del empleado QN206 utilizando la tabla info_empleados. Después, a partir de la tabla info_departamentos, se selecciona la tupla o fila donde se encuentra dicho código, para finalmente mostrar el atributo nombred de la fila mencionada. Como se aprecia el orden de ejecución fue: Subconsulta, clausula FROM, clausula WHERE, clausula SELECT.

Ejercicios de Repaso: 3.1 3.2 3.3 3.4 3.5

Listar los nombres (descripción) de los productos cuyo precio sea mayor al de una ‘TIENDA’. Mostrar los IDs de los clientes, sin repetirse, que en algún pedido hayan comprado más de dos ejemplares de un mismo producto (cantidad) durante 1999, utilizando subconsultas. Listar, sin repetirse, los números de los pedidos hechos por ‘INES VAZQUEZ’. Utilizar subconsultas. Mostrar los nombres (descripciones) de los productos que se compraron durante un mes de diciembre (utilizar una subconsulta). Considerar que el campo fecha es un char(10). Relacionar a los empleados más jóvenes que IRASEMA BAUTISTA GAMBOA y que además no laboran en el departamento de ADMINISTRACION.

4. Operadores IN, NOT IN, ALL, ANY y BETWEEN El operador condicional IN es realmente un operador que evalúa la pertenencia a un conjunto. Esto es, se usa para verificar si un valor está o no “en” la lista de valores proporcionada después de la palabra reservada IN. Por ejemplo: SELECT id_empleado, nombre, apellidos, salario FROM info_empleados WHERE apellidos IN ('VEGA GARCIA', 'PIZ ROBLES', 'RINCON AYALA', 'PEREZ JIMENEZ'); id_empleado | nombre | apellidos | salario -------------+-----------+---------------+---------QN144 | GLADIS | PEREZ JIMENEZ | 9000.00 QN130 | RIGOBERTO | PIZ ROBLES | 6000.00 QN154 | GILBERTO | PEREZ JIMENEZ | 13000.00 QN140 | SECUNDINO | RINCON AYALA | 8000.00 (4 filas)

Esta sentencia mostrará los campos id_empleado, nombre, apellidos, salario de tabla info_clientes donde los apellidos son igual ya sea a: VEGA GARCIA, PIZ ROBLES, RINCON AYALA, o PEREZ JIMENEZ. Devolverá las filas que contengan ALGUNO de estos valores. En casos como éste, sin embargo, el operador condicional IN puede ser reescrito utilizando condiciones compuestas que usen el operador = en combinación con un OR, obteniendo los mismos resultados: SELECT id_empleado, nombre, apellidos, salario FROM info_empleados WHERE apellidos = 'VEGA GARCIA' OR apellidos = 'PIZ ROBLES' OR apellidos = 'RINCON AYALA' OR apellidos = 'PEREZ JIMENEZ';

Aunque, como se puede ver, el operador IN es mucho más corto y fácil de leer cuando se están probando más de dos o tres valores. Un ejemplo utilizando subconsultas. Listar los nombres y apellidos de aquellos empleados que sean gerentes de departamento: SELECT nombre,apellidos FROM info_empleados WHERE id_empleado IN (SELECT gerente FROM info_departamentos);

nombre | apellidos ------------------+---------------------JOSE DE JESUS | CHAVEZ IBARRA RIGOBERTO | DERAS ANDRADE VICTOR MANUEL | HERNANDEZ SOTO SERGIO | AVILA GONZALEZ ROBERTO DE JESUS | RODRIGUEZ LEON MAYRA ELVIRA | GONZALEZ GUTIERREZ JUAN JOSE | SALAS URENA BERNARDO | MENDOZA DIAZ MIGUEL ANGEL | URDAPILLETA RIVERA ENRIQUE | SOTO MACIAS ROSA AMELIA | MORA RODRIGUEZ JESUS MANUEL | RUIZ CRUZ ALMA ANGELICA | NUNEZ DE SANTIAGO LINA DEL CARMEN | GONZALEZ LOZOYA MARCO AURELIO | RAMIREZ GARCIA JULIA ANABEL | SUAREZ ANGUIANO GERARDO AGRIPINO | BELTRAN PEREZ ALEJANDRO | GOMEZ Y ACOSTA EMA LOURDES | ONTIVEROS VALENZUELA (19 filas)

Por el contrario el operador NOT IN se usa para excluir ciertas filas de la lista. Por ejemplo: Listar los nombres de los departamentos que no controlen ningún proyecto. SELECT nombred FROM info_departamentos WHERE id_departamento NOT IN (SELECT DISTINCT numd FROM info_proyectos); nombred -------------------CALIDAD COMPRAS DIRECCION INTENDENCIA MANTENIMIENTO PROTECCION CIVIL TELECOMUNICACIONES TRANSPORTES VENTAS VIGILANCIA (10 filas)

El operador ALL se utiliza en una subconsulta para comparar todos los registros devueltos en base a un operador relacional. Devolver los nombres de los empleados cuyo salario es mayor que todos los empleados del departamento 22:

SELECT apellidos, nombre FROM info_empleados WHERE salario > ALL(SELECT salario FROM info_empleados WHERE departamento = 22); apellidos | nombre -------------------+----------------BAUTISTA GAMBOA | IRASEMA ALVAREZ DUARTE | ESTEBAN ELIZALDE CARRILLO | BEATRIZ ADRIANA RAMIREZ GARCIA | MARCO AURELIO SERNA PEREZ | JOSE GERARDO VEGA GARCIA | IGNACIO CHAVEZ RODRIGUEZ | MAYRA VALDEZ BENAVIDES | ISRAEL (8 filas)

El operador ANY se utiliza en una subconsulta para verificar que al menos uno de los registros devueltos cumpla una condición en base a un operador relacional. Devolver los nombres de los empleados cuyo salario sea mayor que cuando menos alguno de los empleados del departamento 22: SELECT apellidos, nombre FROM info_empleados WHERE salario > ANY(SELECT salario FROM info_empleados WHERE departamento = 22); apellidos | nombre -------------------+----------------BAUTISTA GAMBOA | IRASEMA ALVAREZ DUARTE | ESTEBAN ELIZALDE CARRILLO | BEATRIZ ADRIANA RAMIREZ GARCIA | MARCO AURELIO SERNA PEREZ | JOSE GERARDO VEGA GARCIA | IGNACIO CHAVEZ RODRIGUEZ | MAYRA VALDEZ BENAVIDES | ISRAEL (8 filas)

El operador condicional BETWEEN se utiliza para ver si un valor se encuentra o no “ENTRE” dos valores proporcionados después de la palabra reservada BETWEEN. Por ejemplo: SELECT id_empleado, edad, apellidos, salario FROM info_empleados WHERE edad BETWEEN 30 AND 40;

id_empleado | edad | apellidos | salario -------------+------+--------------------+---------QN105 | 39 | GONZALEZ LOZOYA | 16000.00 QN119 | 31 | BAUTISTA GAMBOA | 36000.00 QN120 | 33 | PEREZ PENARON | 15000.00 QN125 | 36 | QUINTERO LEON | 13000.00 QN185 | 32 | RODRIGUEZ SANDOVAL | 11000.00 QN203 | 37 | NEYRA ZARRAGA | 15000.00 QN150 | 36 | AVILA GARCIA | 16000.00 QN104 | 34 | HERNANDEZ SOTO | 17000.00 QN211 | 38 | LOMELI ROSAS | 12000.00 QN134 | 35 | MENDOZA DIAZ | 12000.00 QN113 | 30 | BELTRAN PEREZ | 22000.00 QN123 | 31 | VEGA GARCIA | 25000.00 QN129 | 34 | CELAYA RODRIGUEZ | 17000.00 QN133 | 32 | MARTINEZ CISNEROS | 15000.00 QN145 | 33 | RODRIGUEZ CHACON | 15000.00 QN149 | 36 | DAMIAN SILVA | 20000.00 QN191 | 34 | VALDEZ SANCHEZ | 11000.00 QN193 | 31 | PEREZ LEON | 20000.00 QN152 | 39 | VELAZQUEZ MENDOZA | 21000.00 QN171 | 31 | VALENCIA GARCIA | 13000.00 QN130 | 31 | PIZ ROBLES | 6000.00 QN146 | 37 | SERRANO CABRERA | 7000.00 QN192 | 30 | REYES HERNANDEZ | 8000.00 QN207 | 37 | NUCAMENDI MOLINA | 17000.00 QN212 | 33 | NUNEZ DE SANTIAGO | 9000.00 QN206 | 34 | JIMENEZ LOPEZ | 18000.00 QN116 | 38 | CABRERA RAMIREZ | 12000.00 QN148 | 33 | NESTA CASTANEDA | 20000.00 QN189 | 37 | PARADA PONCE | 16000.00 QN198 | 37 | CELAYA RODRIGUEZ | 14000.00 QN169 | 33 | CERVANTES CASTRO | 7000.00 (31 filas)

Esta sentencia mostrará los campos id_empleado, edad, apellidos, y salario de la tabla info_empleados donde la edad se encuentre entre 30 y 40 (incluyendo a ambos). La sentencia anterior se puede escribir también sin el operador BETWEEN: SELECT id_empleado, edad, apellidos, salario FROM info_empleados WHERE edad >= 30 AND edad 25000; round | nombre -------+--------------41400 | IRASEMA 31050 | ESTEBAN 48300 | MARCO AURELIO 37950 | JOSE GERARDO 31050 | ISRAEL (5 filas)

Esta sentencia mostrará el salario redondeado al entero más cercano y el nombre de cada uno de los empleados que ganan más de 25,000 y a quienes se les está aplicando un sobresueldo del 15% como compensación. Si se desea que la columna calculada se despliegue con un nombre en particular utilizamos un alias con la clausula AS: SELECT round(salario * 1.15) AS salario_nuevo, nombre FROM info_empleados WHERE salario > 25000; salario_nuevo | nombre ---------------+--------------41400 | IRASEMA 31050 | ESTEBAN 48300 | MARCO AURELIO 37950 | JOSE GERARDO 31050 | ISRAEL (5 filas)

En algunos casos es necesario utilizar subconsultas, por ejemplo: Supóngase que el incremento en el caso anterior se daría solo a los gerentes de departamento: SELECT round(salario * 1.15) AS salario_nuevo, nombre FROM info_empleados WHERE id_empleado IN (SELECT gerente FROM info_departamentos); salario_nuevo | nombre ---------------+-----------------14950 | JOSE DE JESUS 11500 | RIGOBERTO 19550 | VICTOR MANUEL 20700 | SERGIO 17250 | ROBERTO DE JESUS 11500 | MAYRA ELVIRA 10350 | JUAN JOSE 13800 | BERNARDO 21850 | MIGUEL ANGEL 19550 | ENRIQUE 13800 | ROSA AMELIA 6900 | JESUS MANUEL 10350 | ALMA ANGELICA 18400 | LINA DEL CARMEN 48300 | MARCO AURELIO 25300 | JULIA ANABEL 25300 | GERARDO AGRIPINO 9200 | ALEJANDRO 17250 | EMA LOURDES (19 filas)

Ejercicios de Repaso: 6.1 6.2 6.3 6.4

Mostrar la descripción y el precio de los productos, pero considerando un aumento general del 12%. Hacienda ha decidido cargar con un impuesto especial a los artículos deportivos, igual a 3 pesos por pieza. Mostrar cada una de las partidas listando: el id del pedido, el id del producto y el total de impuesto pagado. Igual al ejemplo anterior, pero solo aplicar el impuesto cuando se adquieren más de una pieza de un artículo determinado. Igual al ejercicio 2, pero ahora supóngase que dicho impuesto solo se aplicará a las partidas donde el cliente sea de “JALISCO”.

7. Funciones Agregadas Lista de las funciones agregadas más comunes MIN MAX SUM AVG COUNT COUNT(*)

Regresa el valor mínimo en una columna dada Regresa el valor máximo en una columna dada Regresa la suma de los valores numéricos en una columna dada Regresa el valor promedio de una columna dada Regresa el número total de valores en una columna dada Regresa el número de filas en una columna dada

Las funciones agregadas se utilizan para efectuar cálculos a partir de los datos numéricos de las “columnas devueltas” por una sentencia SELECT. Básicamente resumen los resultados de una columna particular de ciertos datos seleccionados. Se cubren aquí ya que se requieren para el siguiente tema: "GROUP BY". Aunque pueden ser usadas en cualquier otro caso. Por ejemplo: SELECT AVG(salario) FROM info_empleados; avg -------------------15650.485436893204 (1 fila)

Si se quiere que la columna resultante tenga un nombre personalizado, se maneja un alias: SELECT AVG(salario) AS “Promedio salarial” FROM info_empleados; Promedio salarial -------------------15650.485436893204 (1 fila)

Las sentencias anteriores devuelven el promedio de todos los valores de la columna salario de la tabla info_empleados. Otro ejemplo: mostrar el salario promedio de todos los empleados con cargo de 'PROGRAMADOR'. SELECT FROM WHERE

AVG(salario) AS “Promedio Programador” info_empleados cargo = 'PROGRAMADOR';

Promedio Programador ---------------------18500.000000000000 (1 fila)

Un ejemplo más: SELECT COUNT(*) AS “Num. Empleados” FROM info_empleados; Num. Empleados ---------------103 (1 fila)

Esta sentencia es un poco diferente a las otras funciones agregadas ya que no se proporciona ninguna columna en la función count. Devolverá el número de filas de la tabla info_empleados. Si se quiere saber cuántos empleados ganan más de 20,000: SELECT COUNT(salario) FROM info_empleados WHERE salario > 20000; count ------19 (1 fila)

Aunque se pudo haber obtenido el mismo resultado con: SELECT COUNT(*) FROM info_empleados WHERE salario > 20000;

¿Hay alguna diferencia entonces entre el valor devuelto por count(*) y count(atributo)? Solo cuando el atributo permite valores nulos. En ese caso puede ser que no coincidan los resultados devueltos. Finalmente, al igual que en otras secciones, es necesario indicar que en ocasiones se requiere el uso de subconsultas. Por ejemplo: encontrar el salario más alto de todos los gerentes. SELECT MAX(salario) FROM info_empleados WHERE id_empleado IN (SELECT gerente FROM info_departamentos); max ---------42000.00 (1 fila)

Ejercicios de Repaso: 7.1 7.2 7.3 7.4

Desplegar el nombre del producto más caro (Tip: Se puede resolver usando la función MAX y una subconsulta). ¿Cuál es el número total de filas de la tabla partidas_pedidos? Desplegar el precio más barato de los productos ordenados en partidas_pedidos. Para la tabla partidas_pedidos, desplegar aquellos pedidos (id_pedido) en los que se ordenó el producto más barato (Utilizar subconsultas y la función MIN).

8. Agrupamientos (Cláusula GROUP BY) Sintaxis de GROUP BY: SELECT FROM GROUP BY

columna1, FUNCIÓN(columna2) "lista-de-tablas" "lista-columnas";

La cláusula GROUP BY agrupará todas las filas que contengan datos en la(s) columna(s) especificadas y permitirá que se apliquen funciones agregadas a una o más de ellas. Eso se puede explicar mejor con un ejemplo: digamos que nos gustaría obtener una lista de los salarios más altos de cada departamento. SELECT MAX(salario), departamento FROM info_empleados GROUP BY departamento; max | departamento ----------+-------------22000.00 | 34 10000.00 | 43 19000.00 | 46 42000.00 | 25 25000.00 | 55 25000.00 | 30 23000.00 | 50 36000.00 | 33 18000.00 | 56 27000.00 | 54 8000.00 | 53 10000.00 | 57 22000.00 | 47 21000.00 | 41 18000.00 | 23 25000.00 | 35 21000.00 | 52 24000.00 | 22 (18 filas)

Esta sentencia seleccionará el salario máximo para las personas de cada departamento único. Básicamente, se mostrará el salario de la persona que gana más en cada departamento. Se devolverá su salario y su departamento. ¿Qué tal si TAMBÍEN queremos mostrar los apellidos del empleado? Estamos tentados a hacerlo de la siguiente manera:

SELECT apellidos, MAX(salario), departamento FROM info_empleados GROUP BY departamento; ERROR: la columna «info_empleados.apellidos» debe aparecer en la cláusula GROUP BY o ser usada en una función de agregación LÍNEA 1: SELECT apellidos, MAX(salario), departamento ^

Como se aprecia el motor de BDs nos informa que la columna apellidos debe aparecer también en la clausula GROUP BY. Intentémoslo: SELECT apellidos, MAX(salario), departamento FROM info_empleados GROUP BY apellidos, departamento; apellidos | max | departamento ----------------------+----------+------------RINCON AYALA | 8000.00 | 43 LOMELI ROSAS | 12000.00 | 34 SOTO MACIAS | 17000.00 | 41 GONZALEZ GUTIERREZ | 10000.00 | 56 SAUCEDO VERTIZ | 10000.00 | 43 GONZALEZ LOZOYA | 16000.00 | 33 MORALES MENDEZ | 7000.00 | 53 HERNANDEZ SOTO | 17000.00 | 34 RAMIREZ GARCIA | 42000.00 | 25 DERAS ANDRADE | 10000.00 | 57 DIAZ NAVARRO | 17000.00 | 33 GUILLEN MEZA | 16000.00 | 25 NUNEZ DE SANTIAGO | 9000.00 | 33 ... ... ... AVILA GARCIA | 16000.00 | 47 MENDOZA GUTIERREZ | 12000.00 | 55 MENDEZ JAMANGAPE | 14000.00 | 33 TORRES DE LA CRUZ | 21000.00 | 52 ALVAREZ DUARTE | 27000.00 | 33 CELAYA RODRIGUEZ | 17000.00 | 30 PEREZ JIMENEZ | 9000.00 | 41 MONROY COVARRUBIAS | 12000.00 | 54 MENDIVIL ROMERO | 13000.00 | 34 ELIZONDO MURO | 20000.00 | 55 ANSALDO GUTIERREZ | 13000.00 | 30 NEYRA ZARRAGA | 15000.00 | 56 CELAYA MOTA | 21000.00 | 54 ONTIVEROS VALENZUELA | 15000.00 | 47 RODRIGUEZ SANDOVAL | 11000.00 | 46 CHAVEZ RODRIGUEZ | 15000.00 | 33 (103 filas)

No se ha obtenido algo con verdadero significado. Y es que no tiene sentido obtener un resumen agrupando una columna que tiene valores únicos, como es el caso de los apellidos. En cambio: SELECT FROM GROUP BY ORDER BY

departamento, COUNT(salario), salario info_empleados departamento, salario departamento;

departamento | count | salario --------------+-------+---------22 | 3 | 6000.00 22 | 1 | 12000.00 22 | 1 | 7000.00 22 | 1 | 24000.00 22 | 1 | 8000.00 23 | 1 | 18000.00 25 | 1 | 33000.00 25 | 1 | 16000.00 25 | 1 | 17000.00 25 | 1 | 42000.00 ... ... ... 55 | 1 | 18000.00 55 | 1 | 19000.00 55 | 1 | 15000.00 55 | 1 | 20000.00 55 | 1 | 25000.00 55 | 1 | 12000.00 56 | 1 | 10000.00 56 | 1 | 15000.00 56 | 1 | 8000.00 56 | 1 | 12000.00 56 | 1 | 7000.00 56 | 1 | 18000.00 57 | 1 | 10000.00 (86 filas)

Devuelve el número de ocurrencias de cada salario dentro de un departamento. A esto se le llama "agrupamiento múltiple de columnas". Nótese como se agruparon los datos de acuerdo al departamento, pero para cada departamento, se agruparon los datos de acuerdo a los grupos de salarios.

Ejercicios de Repaso: 8.1 8.2 8.3 8.4

¿Cuántas personas hay en cada estado en la tabla info_clientes? Seleccionar los estados y desplegar el número de personas en cada uno. Tip: count se usa para contar filas en una columna, sum solo funciona en datos numéricos. De la tabla partidas_pedidos, calcular la suma de unidades vendidas por cada producto. Tip: Los productos necesitarán separarse en grupos aparte. En la tabla partidas_pedidos ¿Cuántas partidas hay por cada cliente? Desplegar id_cliente y número de pedidos. Similar al anterior, pero ahora mostrar solo los clientes que viven en el estado de ‘JALISCO’.

9. Cláusula HAVING La cláusula HAVING permite especificar condiciones sobre las filas de cada grupo, en otras palabras, él que filas deberían ser seleccionadas se basará en las condiciones que se especifiquen. De ser usada, la cláusula HAVING deberá ir después de GROUP BY. Ejemplo de sintaxis de la cláusula HAVING: SELECT FROM GROUP BY HAVING

columna1, SUM(columna2) "lista-de-tablas" "lista-columnas" "condición";

HAVING puede ser mejor descrita con un ejemplo. Digamos que tenemos una tabla empleado que contiene el nombre, departamento, salario, y edad de cada empleado. Si quisiéramos obtener el salario promedio para cada empleado en cada departamento, ingresaríamos: SELECT departamento, avg(salario) FROM info_empleados GROUP BY departamento; departamento | avg --------------+----------------------34 | 14800.000000000000 43 | 9000.000000000000 46 | 15000.000000000000 25 | 27000.000000000000 55 | 18166.666666666667 30 | 17000.000000000000 50 | 15333.333333333333 33 | 17454.545454545455 56 | 11666.666666666667 54 | 18461.538461538462 53 | 7200.000000000000 57 | 10000.000000000000 47 | 18166.666666666667 41 | 14600.000000000000 23 | 18000.000000000000 35 | 16250.000000000000 52 | 16666.666666666667 22 | 9857.142857142857 (18 filas)

Pero, supongamos que SOLO queremos calcular y mostrar el promedio, si el salario pasa de 15,000 pesos:

SELECT FROM GROUP BY HAVING

departamento, avg(salario) info_empleados departamento avg(salario) > 15000;

departamento | avg --------------+-----------------------25 | 27000.000000000000 55 | 18166.666666666667 30 | 17000.000000000000 50 | 15333.333333333333 33 | 17454.545454545455 54 | 18461.538461538462 47 | 18166.666666666667 23 | 18000.000000000000 35 | 16250.000000000000 52 | 16666.666666666667 (10 filas)

Alguien pudo haberse sentido tentado a utilizar WHERE en lugar de HAVING: SELECT FROM GROUP BY WHERE

departamento, avg(salario) info_empleados departamento avg(salario) > 15000;

Pero obtiene un error. Siempre que se pretenda usar una condición con GROUP BY habrá que utilizar HAVING. Sin embargo, cumpliéndose lo anterior aún se puede utilizar WHERE, como en: SELECT FROM WHERE GROUP BY HAVING

departamento, avg(salario) info_empleados edad > 40 departamento avg(salario) > 15000;

departamento | avg --------------+-----------------------46 | 18000.000000000000 25 | 16000.000000000000 55 | 17750.000000000000 47 | 18500.000000000000 35 | 21000.000000000000 52 | 16500.000000000000 50 | 18000.000000000000 54 | 20428.571428571429 (8 filas)

En la sentencia anterior se obtuvieron los promedios salariales de los empleados mayores de 40 años, por departamento, siempre y cuando el promedio sea mayor de 15,000 pesos. Ejercicios de Repaso: (nota: aunque son similares a los ejercicios GROUP BY, éstos requieren el uso de la cláusula HAVING). 9.1 9.2 9.3 9.4

¿Cuántos clientes hay en cada estado de la tabla info_clientes? Listar estado y desplegar el número de personas, siempre que sean más de 1. ¿Cuántos pedidos hizo cada cliente? Usar la tabla partidas_pedidos. Listar el campo cliente y el número de pedidos que efectuó si es que compró más de 2 productos. De la tabla partidas_pedidos, desplegar los productos que vendieron más de 4 unidades. Mostrar id del producto y las unidades vendidas. En la tabla partidas_pedidos ¿Cuántas partidas hay por cada cliente del estado de ‘JALISCO’? Desplegar id_cliente y número de partidas. Mostrar solo los resultados en los que haya más de 2 partidas.

10. Reuniones Hasta ahora todas las consultas han sido de utilidad, pero se han aplicado sobre una sola tabla, y cuando se han utilizado subconsultas para manipular más de una, hemos tenido algunas limitaciones. Es momento de introducirnos a una de las características de mayor utilidad de SQL y los sistemas de bases de datos relacionales: la “Reunión”. Para ponerlo más simple: La “Reunión” es lo que convierte a los sistemas de bases de datos en “Relacionales”. Las reuniones permiten enlazar datos de una o más tablas en una sola consulta, mediante una sentencia SELECT. Se reconoce una “Reunión” en una sentencia SQL SELECT si se especifica más de una tabla en la cláusula FROM (producto cartesiano) y además se utiliza una condición de reunión en la cláusula WHERE. La sintaxis: SELECT "lista-de-columnas" tabla1,tabla2 [, tabla3, ... tabla_n] FROM WHERE "condiciones de reunión y/o selección"

Las reuniones se pueden explicar de manera más sencilla al demostrar que pasaría se trabaja con una sola tabla, y no se tuviera la habilidad de usar “reuniones”. Este tipo de bases de datos de una sola tabla se conoce a menudo como “tabla plana” o base de datos “plana”. Supongamos que tenemos una sola tabla para llevar el control de los clientes y de lo que compran en nuestra tienda: Id nombre apellido ciudad estado fecha producto cantidad precio

Cada vez que se inserta una nueva fila en la tabla, se actualizarán todas las columnas, resultando en innecesarios “datos redundantes”. Por ejemplo, cuando Juan Perez compra algo se insertan las siguientes filas: Id 10982 10982 10982 10982 10982

nombre Juan Juan Juan Juan Juan

Apellido Perez Perez Perez Perez Perez

ciudad Guadalajara Guadalajara Guadalajara Guadalajara Guadalajara

estado JAL JAL JAL JAL JAL

fecha 032299 082899 091199 100999 022900

producto orejeras pala guantes linterna pala

cantidad 2 3 2 4 2

precio 15.00 35.00 15.00 35.00 35.00

Como se observa se repiten tanto los datos del cliente, como en algunas ocasiones el producto comprado (pala). La solución es normalizarla, dividiéndola en 2 o más tablas. Una base de datos ideal tendrá 3 tablas:

1. Una que lleve el registro de los clientes (info_clientes). 2. Una que lleve el registro de lo los productos en existencia (info_productos). 3. Otra que guarde la información de las compras de cada cliente (partidas_pedidos). Tabla "info_clientes": id_cliente nombre apellido ciudad estado Tabla "info_productos": id_producto descripción precio Tabla "partidas_pedidos": id_pedido cliente fecha_pedido producto cantidad Ahora, cada vez que se hace una compra por parte de un cliente existente, solamente la 3a. tabla, “partidas_pedidos”, necesita ser actualizada. Hemos eliminado los datos redundantes, es decir, hemos normalizado la base de datos. Se conoce como normalización al proceso mediante el cual dividimos una tabla grande en 2 o más pequeñas que puedan guardar estructuras más fáciles de mantener, y que permitan evitar valores redundantes o nulos. Nótese como las tablas info_clientes y partidas_pedidos tienen un campo común (id_cliente y cliente). Estas columnas o atributos llamadas llave primaria y llave foránea, respectivamente, representan la relación entre ambas y guardan el número único de cliente que será usado para REUNIR las dos tablas. Por otro lado las tablas info_productos y partidas_pedidos tienen también un campo común (id_producto y producto), las llaves primaria y foránea, respectivamente Regresando al primer grupo de tablas (info_empleados, info_departamentos e info_proyectos) aplica exactamente lo mismo. Las tablas info_empleados e info_departamentos tienen un campo común que las relaciona: departamento e id_departamento, respectivamente. Las tablas info_departamentos e info_proyectos tienen a id_departamento y numd, respectivamente, como atributos vinculantes. Ambas relaciones son las llamadas “PERTENECE A” y “CONTROLA” descritas en el diagrama Entidad-Relación mostrado al inicio. Además la relación “DIRIGE” está representada por la pareja de atributos id_empleado y gerente. Supongamos que queremos desplegar el nombre y apellidos de los empleados, y el id del departamento al que pertenecen: SELECT nombre, apellidos, departamento FROM info_empleados;

nombre | apellidos | departamento -------------------+----------------------+-------------LINA DEL CARMEN | GONZALEZ LOZOYA | 33 EDUARDO JUAN ELOY | DIAZ NAVARRO | 33 GILDA | MENDEZ JAMANGAPE | 33 IRASEMA | BAUTISTA GAMBOA | 33 JAVIER | PEREZ PENARON | 33 ESTEBAN | ALVAREZ DUARTE | 33 MIGUEL ANGEL | URDAPILLETA RIVERA | 46 AMILCAR | QUINTERO LEON | 46 ... ... ... YOLANDA | MONROY COVARRUBIAS | 54 ROSENDO | PARADA PONCE | 54 GUSTAVO ADOLFO | SOLDAN CORDOVA | 54 JAVIER | CELAYA RODRIGUEZ | 54 PETRONILO | CELAYA MOTA | 54 FRANCISCO JAVIER | DELGADO CHONG | 54 JULIA ANABEL | SUAREZ ANGUIANO | 54 ANGEL FLORENCIO | RODRIGUEZ PAREDES | 53 MARIA DE JESUS | FLORES LUNA | 53 GILBERTO | CERVANTES CASTRO | 53 VICTOR | MORALES MENDEZ | 53 ALEJANDRO | GOMEZ Y ACOSTA | 53 (103 filas)

Pero ¿y si en lugar del id queremos mostrar el nombre del departamento? Aquí es donde entran las reuniones; como el nombre del departamento se halla en otra tabla hay que efectuar la siguiente reunión: SELECT nombre, apellidos, nombred FROM info_empleados, info_departamentos WHERE departamento = id_departamento; nombre | apellidos | nombred -------------------+----------------------+-------------------LINA DEL CARMEN | GONZALEZ LOZOYA | PROTECCION CIVIL EDUARDO JUAN ELOY | DIAZ NAVARRO | PROTECCION CIVIL GILDA | MENDEZ JAMANGAPE | PROTECCION CIVIL IRASEMA | BAUTISTA GAMBOA | PROTECCION CIVIL JAVIER | PEREZ PENARON | PROTECCION CIVIL ESTEBAN | ALVAREZ DUARTE | PROTECCION CIVIL MIGUEL ANGEL | URDAPILLETA RIVERA | ALMACEN AMILCAR | QUINTERO LEON | ALMACEN ... ... ... YOLANDA | MONROY COVARRUBIAS | VENTAS ROSENDO | PARADA PONCE | VENTAS GUSTAVO ADOLFO | SOLDAN CORDOVA | VENTAS

JAVIER PETRONILO FRANCISCO JAVIER JULIA ANABEL ANGEL FLORENCIO MARIA DE JESUS GILBERTO VICTOR ALEJANDRO (103 filas)

| | | | | | | | |

CELAYA RODRIGUEZ CELAYA MOTA DELGADO CHONG SUAREZ ANGUIANO RODRIGUEZ PAREDES FLORES LUNA CERVANTES CASTRO MORALES MENDEZ GOMEZ Y ACOSTA

| | | | | | | | |

VENTAS VENTAS VENTAS VENTAS VIGILANCIA VIGILANCIA VIGILANCIA VIGILANCIA VIGILANCIA

Obsérvese como en la clausula WHERE se maneja la condición de reunión; en ella se igualan las dos claves que las vinculan y representan la relación: “PERTENECE A”. Pero en estas tablas, como habíamos visto antes, existen otras dos claves: id_empleado y gerente. Si modificamos un poco la consulta: SELECT nombre, apellidos, nombred FROM info_empleados, info_departamentos WHERE id_empleado = gerente; nombre | apellidos | nombred ------------------+----------------------+-------------------LINA DEL CARMEN | GONZALEZ LOZOYA | ADMINISTRACION MIGUEL ANGEL | URDAPILLETA RIVERA | ALMACEN MAYRA ELVIRA | GONZALEZ GUTIERREZ | CALIDAD EMA LOURDES | ONTIVEROS VALENZUELA | CAPACITACION VICTOR MANUEL | HERNANDEZ SOTO | COMPRAS BERNARDO | MENDOZA DIAZ | CONTABILIDAD MARCO AURELIO | RAMIREZ GARCIA | DIRECCION GERARDO AGRIPINO | BELTRAN PEREZ | ESTUDIOS ENRIQUE | SOTO MACIAS | INFORMATICA JESUS MANUEL | RUIZ CRUZ | INTENDENCIA RIGOBERTO | DERAS ANDRADE | MANTENIMIENTO ROSA AMELIA | MORA RODRIGUEZ | PERSONAL ALMA ANGELICA | NUNEZ DE SANTIAGO | PROTECCION CIVIL JOSE DE JESUS | CHAVEZ IBARRA | SINDICATO ROBERTO DE JESUS | RODRIGUEZ LEON | SISTEMAS SERGIO | AVILA GONZALEZ | TELECOMUNICACIONES JUAN JOSE | SALAS URENA | TRANSPORTES JULIA ANABEL | SUAREZ ANGUIANO | VENTAS ALEJANDRO | GOMEZ Y ACOSTA | VIGILANCIA (19 filas)

Cambia entonces totalmente el significado de la consulta, desplegando ahora el nombre y apellidos de los gerentes, y el nombre del departamento que dirigen. Aunque no hay una regla escrita que diga que las tablas se tienen que reunir en base a una llave primaria y otra foránea, de no hacerlo se podrían obtener tuplas falsas, en las que habría información no relacionada entre sí. Supongamos ahora gerentes que los info_empleados e necesario entonces siguiente manera:

que deseamos los nombres de los proyectos y el nombre y apellidos de los controlan. La información requerida se encuentra en dos tablas: info_proyectos, pero ¿Cómo saber que empleados son gerentes? Es reunir también la tabla info_departamentos, quedando la consulta de la

SELECT nombre, apellidos, nombrepr FROM info_empleados, info_departamentos, info_proyectos WHERE id_empleado = gerente AND id_departamento = numd; nombre | apellidos | nombrepr ------------------+----------------------+------------------------------------------LINA DEL CARMEN | GONZALEZ LOZOYA | REESTRUCTURACION FINANCIERA LINA DEL CARMEN | GONZALEZ LOZOYA | REVISION ORGANIZACIONAL EMA LOURDES | ONTIVEROS VALENZUELA | SISTEMA VIRTUAL DE CAPACITACION BERNARDO | MENDOZA DIAZ | ACTUALIZACION DE PASIVOS MIGUEL ANGEL | URDAPILLETA RIVERA | ACTUALIZACION DE INVENTARIOS GERARDO AGRIPINO | BELTRAN PEREZ | ESTUDIO DE IMPACTO AMBIENTAL LA YESCA GERARDO AGRIPINO | BELTRAN PEREZ | ESTUDIO DE FACTIBILIDAD LA YESCA GERARDO AGRIPINO | BELTRAN PEREZ | ESTUDIO HIDROENERGETICO RIO YAQUI ENRIQUE | SOTO MACIAS | RENOVACION PARQUE INFORMATICO ENRIQUE | SOTO MACIAS | MANTENIMIENTO ANUAL ROSA AMELIA | MORA RODRIGUEZ | SISTEMA INSTITUCIONAL DE RECURSOS HUMANOS JOSE DE JESUS | CHAVEZ IBARRA | ACTUALIZACION DE GRUPOS ORGANICOS ROBERTO DE JESUS | RODRIGUEZ LEON | SISTEMA DE TECNOLOGIAS DE LA INFORMACION JOSE DE JESUS | CHAVEZ IBARRA | COMPACTACION DE CATEGORIAS (14 filas)

Con la finalidad de evitar ambigüedades y confusiones, la anterior consulta se puede escribir también usando la notación de “tabla.atributo”, quedando: SELECT info_empleados.nombre, info_empleados.apellidos, info_proyectos.nombrepr FROM info_empleados, info_departamentos, info_proyectos WHERE info_empleados.id_empleado = info_departamentos.gerente AND info_departamentos.id_departamento = info_proyectos.numd;

Una variación del ejemplo anterior: Obtener el nombre y apellidos del gerente que controla el proyecto “COMPACTACION DE CATEGORIAS”: SELECT nombre, apellidos, nombrepr FROM info_empleados, info_proyectos, info_departamentos WHERE id_empleado = gerente AND id_departamento = numd AND nombrepr = ‘COMPACTACION DE CATEGORIAS’; nombre | apellidos | nombrepr ---------------+---------------+---------------------------JOSE DE JESUS | CHAVEZ IBARRA | COMPACTACION DE CATEGORIAS (1 fila)

En este ejemplo podemos apreciar algunos problemas que tienen que ver con un fácil entendimiento de la solución. Primeramente vemos que al momento en que se combinan las 3 tablas no se distingue de manera sencilla cuales son las relaciones. Solo después de analizar un poco nos damos cuenta que info_empleados se reúne con info_departamentos y que info_departamentos se reúne con info_proyectos; esto porque no se exige ningún orden en la clausula FROM. Además en la cláusula WHERE se encuentran tanto condiciones de reunión como condiciones de selección (nombrepr = ‘COMPACTACION DE CATEGORIAS’). El estándar ANSI SQL resuelve dichos problemas al proponer una sintaxis mucho más limpia y entendible por medio de las clausulas INNER JOIN y ON: SELECT FROM INNER JOIN ON [WHERE

lista_de_atributos tabla_1 table_2

“condición de reunión” “condiciones de selección”];

El primer ejemplo resuelto arriba: Desplegar el nombre y apellidos de los empleados, y el nombre del departamento al que pertenecen: SELECT FROM INNER JOIN ON

nombre, apellidos, nombred info_empleados info_departamentos departamento = id_departamento;

nombre | apellidos | nombred -------------------+----------------------+-------------------LINA DEL CARMEN | GONZALEZ LOZOYA | PROTECCION CIVIL EDUARDO JUAN ELOY | DIAZ NAVARRO | PROTECCION CIVIL GILDA | MENDEZ JAMANGAPE | PROTECCION CIVIL IRASEMA | BAUTISTA GAMBOA | PROTECCION CIVIL JAVIER | PEREZ PENARON | PROTECCION CIVIL ESTEBAN | ALVAREZ DUARTE | PROTECCION CIVIL

MIGUEL ANGEL AMILCAR ... ... ... YOLANDA ROSENDO GUSTAVO ADOLFO JAVIER PETRONILO FRANCISCO JAVIER JULIA ANABEL ANGEL FLORENCIO MARIA DE JESUS GILBERTO VICTOR ALEJANDRO (103 filas)

| URDAPILLETA RIVERA | QUINTERO LEON

| ALMACEN | ALMACEN

| | | | | | | | | | | |

| | | | | | | | | | | |

MONROY COVARRUBIAS PARADA PONCE SOLDAN CORDOVA CELAYA RODRIGUEZ CELAYA MOTA DELGADO CHONG SUAREZ ANGUIANO RODRIGUEZ PAREDES FLORES LUNA CERVANTES CASTRO MORALES MENDEZ GOMEZ Y ACOSTA

VENTAS VENTAS VENTAS VENTAS VENTAS VENTAS VENTAS VIGILANCIA VIGILANCIA VIGILANCIA VIGILANCIA VIGILANCIA

Si son dos reuniones o más basta con enlazarlas una tras otra. En esta sintaxis alterna además, las condiciones de reunión se definen con la clausula ON, mientras que las de selección con la clausula WHERE. Así la consulta de arriba “Obtener el nombre y apellidos del gerente que controla el proyecto ‘COMPACTACION DE CATEGORIAS’ ” queda como: SELECT FROM INNER JOIN ON INNER JOIN ON WHERE

nombre, apellidos, nombrepr info_empleados info_departamentos id_empleado = gerente info_proyectos id_departamento = numd nombrepr = ‘COMPACTACION DE CATEGORIAS’;

nombre | apellidos | nombrepr ---------------+---------------+---------------------------JOSE DE JESUS | CHAVEZ IBARRA | COMPACTACION DE CATEGORIAS (1 fila)

Ahora si se distingue muy bien que tablas se están reuniendo y además quedan separadas las condiciones de reunión de las condiciones de selección. En este tipo de reuniones (internas) se puede omitir la palabra INNER, de forma que la consulta anterior queda simplificada:

SELECT FROM JOIN ON JOIN ON WHERE

nombre, apellidos, nombrepr info_empleados info_departamentos id_empleado = gerente info_proyectos id_departamento = numd nombrepr = ‘COMPACTACION DE CATEGORIAS’;

Ejercicios de Repaso (combinando productos cartesianos en FROM y condiciones de reunión en WHERE): 10.1 10.2

10.3 10.4

Listar el nombre, apellido y el id del producto que cada uno de los clientes adquirió para cada una de las partidas. Escribir una consulta usando una reunión para determinar cuáles productos fueron ordenados por cada uno de los clientes. Mostrar los campos nombre, apellido, fecha_pedido, producto, y precio por todo lo comprado por cada uno de los clientes de la tabla partidas_pedidos. Repetir el ejercicio #1, pero desplegar los resultados ordenados por estado en orden descendente (mostrar además el campo estado). Escribir una consulta usando una reunión para determinar cuáles productos fueron ordenados por ‘JUAN LOPEZ’ en la tabla info_clientes. Mostrar los campos id_pedido y descripción del producto.

Ejercicios de Repaso (Utilizando las cláusulas JOIN y ON): 10.5 10.6

10.7 10.8

Listar el nombre, apellido y el id del producto que cada uno de los clientes adquirió para cada una de las partidas. Escribir una consulta usando una reunión para determinar cuáles productos fueron ordenados por cada uno de los clientes. Mostrar los campos nombre, apellido, fecha_pedido, producto, y precio por todo lo comprado por cada uno de los clientes de la tabla partidas_pedidos. Repetir el ejercicio #1, pero desplegar los resultados ordenados por estado en orden descendente (mostrar además el campo estado). Escribir una consulta usando una reunión para determinar cuáles productos fueron ordenados por ‘JUAN LOPEZ’ en la tabla info_clientes. Mostrar los campos id_pedido y descripción del producto.