Está en la página 1de 44

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 nombre Apellidos edad departamento cargo salario
QN105 LINA DEL CARMEN GONZALEZ LOZOYA 39 33 CONTADOR 16000
QN109 EDUARDO JUAN ELOY DIAZ NAVARRO 54 33 CONTADOR 17000
QN118 GILDA MENDEZ JAMANGAPE 42 33 SECRETARIA 14000
QN119 IRASEMA BAUTISTA GAMBOA 31 33 JEFE DE OFICINA 36000
QN120 JAVIER PEREZ PEÑARON 33 33 CONTADOR 15000
QN216 ESTEBAN ALVAREZ DUARTE 22 33 AUXILIAR 27000
QN103 MIGUEL ANGEL URDAPILLETA RIVERA 46 46 JEFE DE OFICINA 19000
QN125 AMILCAR QUINTERO LEON 36 46 ALMACENISTA 13000
QN159 JOSE MANUEL VEGA LEON 42 46 AUXILIAR 17000
QN185 RUBI RODRIGUEZ SANDOVAL 32 46 SECRETARIA 11000
QN131 MAYRA ELVIRA GONZALEZ GUTIERREZ 56 56 SECRETARIA 10000
QN158 MANUEL NAZARIO CAMPOS QUEZADA 23 56 JEFE DE OFICINA 18000
QN165 JUAN IGNACIO MESTAS ARJONA 22 56 TECNICO 12000
QN203 BERNARDO NEYRA ZARRAGA 37 56 INGENIERO 15000
QN106 EMA LOURDES ONTIVEROS VALENZUELA 47 47 SECRETARIA 15000
QN132 JAVIER EDUARDO MORALES VELASCO 51 47 AUXILIAR 17000
QN141 RICARDO LEON VALDIVIA 57 47 JEFE DE OFICINA 22000
QN150 FERMIN AVILA GARCIA 36 47 PROFESOR 16000
QN163 ALVARO GUADALUPE RIVERA FLORES 54 47 PROFESOR 20000
QN205 ELIN ROLANDO GARCIA DOMINGUEZ 22 47 PROFESOR 19000
QN104 VICTOR MANUEL HERNANDEZ SOTO 34 34 AUXILIAR 17000
QN111 CRISTINA LLAMAS PALACIOS 42 34 SECRETARIA 10000
QN117 JUAN RAMON GONZALEZ ARELLANO 25 34 JEFE DE OFICINA 22000
QN187 FRANCISCO MENDIVIL ROMERO 29 34 COMPRADOR 13000
QN211 JOSE LUIS LOMELI ROSAS 38 34 COMPRADOR 12000
QN134 BERNARDO MENDOZA DIAZ 35 35 CONTADOR 12000
QN156 JOAQUIN IGNACIO RODRIGUEZ CASTRO 42 35 AUXILIAR 17000
QN195 BEATRIZ ADRIANA ELIZALDE CARRILLO 41 35 JEFE DE OFICINA 25000
QN213 BLANCA ESTHELA PEREZ ROMERO 28 35 SECRETARIA 11000
QN100 MARCO AURELIO RAMIREZ GARCIA 25 25 JEFE DE OFICINA 42000
QN101 JOSE GERARDO SERNA PEREZ 18 25 AUXILIAR 33000
QN107 MARIA CELINA GUILLEN MEZA 53 25 SECRETARIA 16000
QN121 EVENECER URIARTE VARGAS 21 25 TECNICO 17000
QN113 GERARDO AGRIPINO BELTRAN PEREZ 30 30 INGENIERO 22000
QN115 MIGUEL MORENO MIRAMONTES 49 30 INGENIERO 17000
QN123 IGNACIO VEGA GARCIA 31 30 JEFE DE OFICINA 25000
QN129 ISRAEL CELAYA RODRIGUEZ 34 30 INGENIERO 17000
QN133 ISMAEL MARTINEZ CISNEROS 32 30 INGENIERO 15000
QN139 LAZARO CASTAÑEDA ROBLES 28 30 INGENIERO 15000
QN145 SALVADOR RODRIGUEZ CHACON 33 30 INGENIERO 15000
QN149 PEDRO DAMIAN SILVA 36 30 INGENIERO 20000
QN160 JOSE JAIME AVILA GONZALEZ 57 30 TECNICO 12000
QN191 LIZ EDITH VALDEZ SANCHEZ 34 30 SECRETARIA 11000
QN193 ERVEY ROBERTO PEREZ LEON 31 30 INGENIERO 20000
QN197 JUAN JOSE ANSALDO GUTIERREZ 55 30 DIBUJANTE 13000
QN201 RAMON RUIZ CRUZ 42 30 DIBUJANTE 14000
QN209 ERICK JIMENEZ MORA 23 30 INGENIERO 22000
QN144 GLADIS PEREZ JIMENEZ 23 41 SECRETARIA 9000
QN152 JOSE CARLOS VELAZQUEZ MENDOZA 39 41 JEFE DE OFICINA 21000
QN171 EDGAR VALENCIA GARCIA 31 41 TECNICO 13000
QN208 GERARDO AYVAR YAÑEZ 49 41 TECNICO 13000
QN210 ENRIQUE SOTO MACIAS 41 41 TECNICO 17000
QN130 RIGOBERTO PIZ ROBLES 31 22 INTENDENTE 6000
QN146 GILBERTO SERRANO CABRERA 37 22 INTENDENTE 7000
QN161 JOSE ANTONIO GONZALEZ GONZALEZ 42 22 INTENDENTE 6000
QN192 MA DEL CONSUELO REYES HERNANDEZ 30 22 INTENDENTE 8000
QN200 JESUS MANUEL RUIZ CRUZ 22 22 INTENDENTE 6000
QN147 LEANDRO LOPEZ ALTAMIRANO 51 56 TECNICO 8000
QN153 DANIEL VAZQUEZ PIMENTEL 24 56 TECNICO 7000
QN155 RIGOBERTO DERAS ANDRADE 56 57 TECNICO 10000
QN108 JOSE LUIS TORRES DE LA CRUZ 44 52 JEFE DE OFICINA 21000
QN137 JOSE ANGEL BELTRAN VELAZQUEZ 24 52 AUXILIAR 17000
QN204 ROSA AMELIA MORA RODRIGUEZ 52 52 SECRETARIA 12000
QN154 GILBERTO PEREZ JIMENEZ 28 33 INGENIERO 13000
QN164 JOSE ANTONIO CHAVEZ RODRIGUEZ 21 33 AUXILIAR 15000
QN184 ARMANDO FRAGA LOPEZ 43 33 INGENIERO 13000
QN207 ASMET NUCAMENDI MOLINA 37 33 JEFE DE OFICINA 17000
QN212 ALMA ANGELICA NUÑEZ DE SANTIAGO 33 33 SECRETARIA 9000
QN162 MALAQUIAS CASTAÑEDA MACIAS 53 50 JEFE DE OFICINA 23000
QN168 MA DE JESUS MARTINEZ ESCOBEDO 23 50 SECRETARIA 10000
QN188 JOSE DE JESUS CHAVEZ IBARRA 50 50 AUXILIAR 13000
QN138 ASTRID YARELI ELIZONDO MURO 23 55 AUXILIAR 20000
QN172 MAYRA CHAVEZ RODRIGUEZ 51 55 JEFE DE OFICINA 25000
QN173 FLORA CRUZ MENDOZA GUTIERREZ 56 55 SECRETARIA 12000
QN196 RAFAEL EDGARDO RIVERA RAMIREZ 57 55 PROGRAMADOR 19000
QN206 VICTOR MANUEL JIMENEZ LOPEZ 34 55 PROGRAMADOR 18000
QN215 ROBERTO DE JESUS RODRIGUEZ LEON 55 55 TECNICO 15000
QN116 MA. DE LOURDES CABRERA RAMIREZ 38 22 SECRETARIA 12000
QN124 JACOBO RAMSES RODRIGUEZ CARRILLO 18 22 JEFE DE OFICINA 24000
QN127 SERGIO AVILA GONZALEZ 22 23 AUXILIAR 18000
QN112 JOSE DE JESUS QUINTANILLA GONZALEZ 47 43 CHOFER 9000
QN140 SECUNDINO RINCON AYALA 18 43 CHOFER 8000
QN142 JOSE NOE LLAMAS OCEGUEDA 51 43 CHOFER 9000
QN143 MARCO ANTONIO SAUCEDO VERTIZ 44 43 CHOFER 10000
QN186 JUAN JOSE SALAS UREÑA 43 43 CHOFER 9000
QN102 BUENAVENTURA BARRERAS TRASVIÑA 19 54 VENDEDOR 18000
QN110 MAURICIO NOLAN JIMENEZ RUIZ 50 54 VENDEDOR 19000
QN114 RAMON GONZALO GARCIA BERNAL 52 54 VENDEDOR 20000
QN128 ISRAEL VALDEZ BENAVIDES 44 54 JEFE DE OFICINA 27000
QN136 LIZZETTE RIVERA FLORES 54 54 VENDEDOR 21000
QN148 VICTOR NESTA CASTAÑEDA 33 54 VENDEDOR 20000
QN166 YOLANDA MONROY COVARRUBIAS 27 54 SECRETARIA 12000
QN189 ROSENDO PARADA PONCE 37 54 VENDEDOR 16000
QN190 GUSTAVO ADOLFO SOLDAN CORDOVA 22 54 VENDEDOR 17000
QN198 JAVIER CELAYA RODRIGUEZ 37 54 VENDEDOR 14000
QN199 PETRONILO CELAYA MOTA 56 54 AUXILIAR 21000
QN202 FRANCISCO JAVIER DELGADO CHONG 48 54 VENDEDOR 13000
QN214 JULIA ANABEL SUAREZ ANGUIANO 54 54 VENDEDOR 22000
QN151 ANGEL FLORENCIO RODRIGUEZ PAREDES 23 53 VIGILANTE 6000
QN157 MARIA DE JESUS FLORES LUNA 56 53 VIGILANTE 8000
QN169 GILBERTO CERVANTES CASTRO 33 53 VIGILANTE 7000
QN170 VICTOR MORALES MENDEZ 55 53 VIGILANTE 7000
QN194 ALEJANDRO GOMEZ Y ACOSTA 53 53 VIGILANTE 8000

Info_departamentos
id_departamento nombred gerente
39 ADMINISTRACION QN105
46 ALMACEN QN103
56 CALIDAD QN131
47 CAPACITACION QN106
34 COMPRAS QN104
35 CONTABILIDAD QN134
25 DIRECCION QN100
30 ESTUDIOS QN113
41 INFORMATICA QN210
22 INTENDENCIA QN200
57 MANTENIMIENTO QN155
52 PERSONAL QN204
33 PROTECCION CIVIL QN212
50 SINDICATO QN188
55 SISTEMAS QN215
23 TELECOMUNICACIONES QN127
43 TRANSPORTES QN186
54 VENTAS QN214
53 VIGILANCIA QN194

Info_proyectos
id_proyecto nombrepr numd
5 REESTRUCTURACION FINANCIERA 39
8 REVISION ORGANIZACIONAL 39
13 SISTEMA VIRTUAL DE CAPACITACION 47
17 ACTUALIZACION DE PASIVOS 35
18 ACTUALIZACION DE INVENTARIOS 46
21 ESTUDIO DE IMPACTO AMBIENTAL LA YESCA 30
22 ESTUDIO DE FACTIBILIDAD LA YESCA 30
25 ESTUDIO HIDROENERGETICO RIO YAQUI 30
31 RENOVACION PARQUE INFORMATICO 41
43 MANTENIMIENTO ANUAL 41
45 SISTEMA INSTITUCIONAL DE RECURSOS HUMANOS 52
52 ACTUALIZACION DE GRUPOS ORGANICOS 50
55 SISTEMA DE TECNOLOGIAS DE LA INFORMACION 55
57 COMPACTACION DE CATEGORIAS 50
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 cliente fecha_pedido producto Cantidad
1 10558 1999-01-03 20 2
2 10556 1999-01-05 1 2
2 10556 1999-01-05 12 4
3 10530 1999-01-19 24 2
4 10512 1999-01-20 10 3
5 10525 1999-04-02 15 4
6 10501 1999-04-18 2 1
7 10538 1999-04-20 16 2
7 10538 1999-04-20 22 1
8 10545 1999-06-03 8 5
9 10564 1999-06-03 1 1
10 10562 1999-06-20 21 4
11 10101 1999-06-30 19 3
12 10330 1999-06-30 6 1
13 10101 1999-07-01 7 4
14 10298 1999-07-01 20 1
14 10298 1999-07-01 23 2
15 10515 1999-07-03 12 4
16 10299 1999-07-06 17 1
17 10530 1999-08-05 8 2
18 10449 1999-08-13 13 1
19 10439 1999-08-14 23 2
20 10101 1999-08-18 10 1
21 10449 1999-09-01 25 1
22 10534 1999-09-09 3 2
23 10439 1999-09-18 24 1
24 10298 1999-09-19 12 2
24 10298 1999-09-19 25 2
25 10530 1999-10-16 2 1
26 10530 1999-10-22 16 3
27 10410 1999-10-28 3 1
28 10438 1999-11-01 18 4
29 10438 1999-11-02 1 1
30 10512 1999-11-04 8 4
31 10556 1999-11-20 22 2
32 10298 1999-12-01 6 1
33 10551 1999-12-03 4 4
34 10449 1999-12-15 2 1
35 10551 1999-12-16 23 2
36 10540 1999-12-19 9 2
37 10449 1999-12-22 5 1
38 10101 1999-12-30 8 3
39 10330 2000-01-01 11 4
40 10556 2000-01-01 8 3
41 10101 2000-01-02 12 1
42 10525 2000-01-04 20 2
42 10525 2000-01-04 11 2
43 10299 2000-01-18 9 1
44 10438 2000-01-18 24 1
45 10413 2000-01-19 22 4
46 10520 2000-01-21 16 4
47 10410 2000-01-30 13 1
48 10315 2000-02-02 4 1
49 10520 2000-02-15 23 1
50 10540 2000-02-17 2 2
51 10449 2000-02-29 11 1
52 10101 2000-03-08 3 2
53 10298 2000-03-18 14 1
54 10449 2000-03-19 21 2
55 10518 2000-03-21 10 2
56 10298 2000-04-01 15 1
57 10330 2000-04-19 16 1
57 10330 2000-04-19 23 1
57 10330 2000-04-19 8 2
58 10501 2000-05-02 1 2
59 10551 2000-07-01 19 2
60 10520 2000-07-02 20 2
61 10525 2000-07-20 9 2
62 10339 2000-07-27 18 1
63 10515 2000-08-19 10 3
64 10545 2000-08-19 2 2
64 10545 2000-08-19 14 3
64 10545 2000-08-19 19 2
65 10534 2000-10-03 15 2
66 10556 2000-10-10 3 3
67 10510 2000-11-02 8 3
68 10551 2000-11-04 1 4
69 10525 2000-11-23 16 4
70 10534 2000-02-21 8 2

info_clientes
id_cliente nombre apellido Ciudad Estado
10101 JUAN LOPEZ GUADALAJARA JALISCO
10298 PEDRO GUTIERREZ CD. JUAREZ CHIHUAHUA
10299 MARTIN HERNANDEZ ZAPOPAN JALISCO
10315 LISA MARTINEZ PUEBLA PUEBLA
10325 ROBERTO JIMENEZ MAZATLAN SINALOA
10329 MARIA MENDOZA TUXTLA CHIAPAS
10330 INES VAZQUEZ VILLAHERMOSA TABASCO
10338 MIGUEL HERRERA VILLAHERMOSA TABASCO
10339 ANTONIO SANCHEZ CHIHUAHUA CHIHUAHUA
10408 ELOY CHAVEZ CHIHUAHUA CHIHUAHUA
10410 ANA GONZALEZ MERIDA YUCATAN
10413 RONALDO SANTANA TLAQUEPAQUE JALISCO
10419 LINDA CERVERA NOGALES SONORA
10429 SARA VILLANUEVA CHILPANCINGO GUERRERO
10438 SERGIO PEREZ DURANGO DURANGO
10439 CONRADO TORRES DURANGO DURANGO
10449 ISABELA MARQUEZ GUADALAJARA JALISCO
10501 RICARDO LOPEZ MORELIA MICHOACAN
10510 MARTHA GONZALEZ LEON GUANAJUATO
10512 PEDRO HERNANDEZ CULIACAN SINALOA
10515 YURIDIA TORRES IRAPUATO GUANAJUATO
10518 ENRIQUE CHAVEZ ZAPOPAN JALISCO
10520 JOSE TERRONES URUAPAN MICHOACAN
10525 MIGUEL SANDOVAL HERMOSILLO SONORA
10530 MARIA MIRELES ACAPULCO GUERRERO
10534 SILVIA SANCHEZ GUADALAJARA JALISCO
10538 JUAN VAZQUEZ GUANAJUATO GUANAJUATO
10540 MARTIN SERRANO MORELIA MICHOACAN
10545 ANA HUERTA GUADALAJARA JALISCO
10551 JIMENA HERNANDEZ PTO PROGRESO YUCATAN
10556 DANIEL PEREZ VERACRUZ VERACRUZ
10558 JAVIER SAUCEDO OAXACA OAXACA
10562 ANTONIO VEGA COLIMA COLIMA
10564 ANDRES VELEZ MANZANILLO COLIMA

info_productos
id_producto Descripción precio
1 ALMOHADA 150
2 BICICLETA 3800
3 BOLSA DE DORMIR 600
4 BRUJULA 120
5 CANOA 2800
6 CASCO 280
7 CHALECO SALVAVIDAS 700
8 CHAMARRA 450
9 COLCHON INFABLE 320
13 GUANTES 345
10 IMPERMEABLE 205
11 LAMPARA 280
12 LINTERNA 170
14 NAVAJA DE BOLSILLO 300
15 OREJERAS 135
16 PALA 180
17 PARACAIDAS 12500
18 PARAGUAS 80
19 PASAMONTA¥AS 500
20 PATINES 460
21 REMO PARA CANOA 450
22 SILLA DE JARDIN 250
23 SUETER 600
24 TIENDA 900
25 ZAPATOS DE NIEVE 1200
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 [ALL | DISTINCT] columna1[,columna2]


FROM tabla1[,tabla2]
[WHERE "condiciones"]
[GROUP BY "lista-columnas"]
[HAVING "condiciones"]
[ORDER BY "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 | 56 | 21000.00
JULIA ANABEL | 54 | 22000.00
MARIA DE JESUS | 56 | 8000.00
VICTOR | 55 | 7000.00
ALEJANDRO | 53 | 8000.00
(24 filas)

Operadores Relacionales (de Comparación)


= Igual
> Mayor que
< Menor que
>= Mayor o igual que
<= Menor o igual que
<> o != Diferente de
LIKE Compara una cadena con un patrón

Ejemplo:

SELECT nombre, cargo, departamento


FROM info_empleados
WHERE cargo LIKE 'PRO%';

Esta sentencia devolverá el nombre, cargo y departamento de los empleados cuyo cargo
comience con 'PRO', como “PROGRAMADOR” o “PROFESOR”. La cláusula LIKE checa si el
valor de una cadena concuerda con un patrón dado. Se pueden usar 2 comodines: El símbolo
‘%’ que significa “cero o más caracteres” y el símbolo ‘_’ que significa “uno y solo un carácter”.

nombre | cargo | departamento


------------------+-------------+--------------
FERMIN | PROFESOR | 47
ALVARO GUADALUPE | PROFESOR | 47
ELIN ROLANDO | PROFESOR | 47
RAFAEL EDGARDO | PROGRAMADOR | 55
VICTOR MANUEL | PROGRAMADOR | 55
(5 filas)

ALL y DISTINCT son palabras reservadas para elegir TODOS (default) los registros o los
“únicos” o distintos registros en los resultados de una consulta. Si queremos obtener registros
no repetidos en determinadas columnas, podemos usar la cláusula "DISTINCT". DISTINCT
descartará los registros duplicados para las columnas especificadas después de la sentencia
"SELECT". Por ejemplo: Devolver las edades únicas (sin repetir) en la tabla info_empleados.

SELECT DISTINCT edad


FROM info_empleados;
edad
------
34
43
32
25
42
...
...
...
31
35
52
44
37
(36 filas)

ALL desplegará "todos" los valores de las columnas especificadas, incluyendo los duplicados.
La cláusula ALL es la usada por omisión.

Un último ejemplo: Desplegar todos los empleados cuya segunda letra del nombre sea ‘I’ y su
primer apellido comience con ‘M’.

SELECT nombre, apellidos


FROM info_empleados
WHERE nombre LIKE '_I%' AND apellidos LIKE 'M%';

nombre | apellidos
--------+-------------------
GILDA | MENDEZ JAMANGAPE
MIGUEL | MORENO MIRAMONTES
VICTOR | MORALES MENDEZ
(3 filas)

Ejercicios de Repaso:

1.1 De la tabla partidas_pedidos, listar los productos adquiridos por el cliente 10449.
desplegar id_pedido, cliente, producto y cantidad para dicho cliente.
1.2 Listar todas las columnas de la tabla info_productos para aquellos productos que
cuesten más de 300 pesos.
1.3 Listar los valores de nombre, apellido y ciudad de la tabla info_clientes para
cualquier cliente cuyo apellido contenga una doble ‘R’ (“RR”).
1.4 Listar los valores de id_pedido, cliente y producto de la tabla partidas_pedidos, cuya
compra se haya efectuado en un mes de abril. Suponga que el campo fecha_pedido
sea de tipo char(10).
1.5 Liste todas las fechas en las que se efectuó alguna compra, sin que se repitan.
2. Combinando condiciones y Operadores Booleanos (lógicos)

El operador AND puede ser usado para unir dos o más condiciones en la cláusula WHERE.
Ambos lados de la condición AND deben ser verdaderos para que ésta se cumpla y se
desplieguen las filas.

El operador OR también puede ser usado para unir dos o más condiciones en la cláusula
WHERE. Sin embargo, basta con que cualquiera de los lados del operador OR sea verdadero
para que la condición se cumpla y las filas sean desplegadas. Con el operador OR, uno o ambos
lados de la expresión pueden ser verdaderos.

Por ejemplo:

SELECT id_empleado, nombre, apellidos, cargo, salario


FROM info_empleados
WHERE salario >= 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 id_empleado, nombre, apellidos, cargo, salario


FROM info_empleados
WHERE (salario >= 50000.00) AND (cargo = 'PROGRAMADOR');

Este otro ejemplo:

SELECT nombre, apellidos, cargo, salario


FROM info_empleados
WHERE (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 | JIMENEZ RUIZ | VENDEDOR | 19000.00
RAMON GONZALO | GARCIA BERNAL | VENDEDOR | 20000.00
LIZZETTE | RIVERA FLORES | VENDEDOR | 21000.00
VICTOR | NESTA CASTANEDA | VENDEDOR | 20000.00
ROSENDO | PARADA PONCE | VENDEDOR | 16000.00
GUSTAVO ADOLFO | SOLDAN CORDOVA | VENDEDOR | 17000.00
JAVIER | CELAYA RODRIGUEZ | VENDEDOR | 14000.00
FRANCISCO JAVIER | DELGADO CHONG | VENDEDOR | 13000.00
JULIA ANABEL | SUAREZ ANGUIANO | VENDEDOR | 22000.00
(12 filas)

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 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.
2.2 listar la descripción y precio de todos los productos que comienzan con las letras 'S', 'P',
o 'C'.
2.3 Mostrar el nombre y apellidos de los clientes cuyo nombre comiencen con ‘R’ y sean de
JALISCO o MICHOACAN.
2.4 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).
2.5 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 Listar los nombres (descripción) de los productos cuyo precio sea mayor al de una
‘TIENDA’.
3.2 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.
3.3 Listar, sin repetirse, los números de los pedidos hechos por ‘INES VAZQUEZ’. Utilizar
subconsultas.
3.4 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).
3.5 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 <= 40;

Se puede usar el operador NOT BETWEEN para excluir valores entre el rango especificado.

SELECT id_empleado, edad, apellidos, salario


FROM info_empleados
WHERE edad NOT BETWEEN 30 AND 40;
id_empleado | edad | apellidos | salario
-------------+------+----------------------+----------
QN109 | 54 | DIAZ NAVARRO | 17000.00
QN118 | 42 | MENDEZ JAMANGAPE | 14000.00
QN216 | 22 | ALVAREZ DUARTE | 27000.00
QN103 | 46 | URDAPILLETA RIVERA | 19000.00
QN159 | 42 | VEGA LEON | 17000.00
QN131 | 56 | GONZALEZ GUTIERREZ | 10000.00
QN158 | 23 | CAMPOS QUEZADA | 18000.00
QN165 | 22 | MESTAS ARJONA | 12000.00
QN106 | 47 | ONTIVEROS VALENZUELA | 15000.00
QN132 | 51 | MORALES VELASCO | 17000.00
QN141 | 57 | LEON VALDIVIA | 22000.00
QN163 | 54 | RIVERA FLORES | 20000.00
QN205 | 22 | GARCIA DOMINGUEZ | 19000.00
QN111 | 42 | LLAMAS PALACIOS | 10000.00
...
...
...
QN110 | 50 | JIMENEZ RUIZ | 19000.00
QN114 | 52 | GARCIA BERNAL | 20000.00
QN128 | 44 | VALDEZ BENAVIDES | 27000.00
QN136 | 54 | RIVERA FLORES | 21000.00
QN166 | 27 | MONROY COVARRUBIAS | 12000.00
QN190 | 22 | SOLDAN CORDOVA | 17000.00
QN199 | 56 | CELAYA MOTA | 21000.00
QN202 | 48 | DELGADO CHONG | 13000.00
QN214 | 54 | SUAREZ ANGUIANO | 22000.00
QN151 | 23 | RODRIGUEZ PAREDES | 6000.00
QN157 | 56 | FLORES LUNA | 8000.00
QN170 | 55 | MORALES MENDEZ | 7000.00
QN194 | 53 | GOMEZ Y ACOSTA | 8000.00
(72 filas)

Ejercicios de Repaso:

4.1 Listar el apellido, ciudad, y estado de los clientes cuyo estado sea: CHIHUAHUA,
JALISCO, MICHOACAN, DURANGO, o CHIAPAS (Usar IN).
4.2 Desplegar el nombre y apellido de todos aquellos clientes que no han hecho ningún
pedido (Usar NOT IN).
4.3 Mostrar el id del pedido, fecha e id del producto adquirido de la tabla partidas_pedidos
para todos aquellos registros cuyo producto adquirido tenga un valor esté entre 400 y
800 pesos (Usar IN, BETWEEN y una subconsulta).
5. Cláusula ORDER BY

ORDER BY es una cláusula opcional que permite mostrar los resultados de la consulta de
forma ordenada (ya sea ascendente o descendente), basada en las columnas que se
especificaron como criterio de ordenamiento.

Sintaxis de la cláusula ORDER BY:

SELECT column1, SUM(columna2)


FROM "lista-de-tablas"
ORDER BY "lista-columnas" [ASC | DESC];

[ ] = opcional

ASC = Orden Ascendente – por omisión


DESC = Orden Descendente

Por ejemplo: Seleccionar los campos id_empleado, departamento, nombre, edad, y salario de
la tabla info_empleados donde el departamento sea igual a “Ventas” y listar los resultados en
orden ascendente (por omisión) de acuerdo a su salario.

SELECT id_empleado, departamento, nombre, edad, salario


FROM info_empleados
WHERE departamento = '30'
ORDER BY salario;

id_empleado | departamento | nombre | edad | salario


-------------+--------------+------------------+------+----------
QN191 | 30 | LIZ EDITH | 34 | 11000.00
QN160 | 30 | JOSE JAIME | 57 | 12000.00
QN197 | 30 | JUAN JOSE | 55 | 13000.00
QN201 | 30 | RAMON | 42 | 14000.00
QN139 | 30 | LAZARO | 28 | 15000.00
QN133 | 30 | ISMAEL | 32 | 15000.00
QN145 | 30 | SALVADOR | 33 | 15000.00
QN129 | 30 | ISRAEL | 34 | 17000.00
QN115 | 30 | MIGUEL | 49 | 17000.00
QN149 | 30 | PEDRO | 36 | 20000.00
QN193 | 30 | ERVEY ROBERTO | 31 | 20000.00
QN209 | 30 | ERICK | 23 | 22000.00
QN113 | 30 | GERARDO AGRIPINO | 30 | 22000.00
QN123 | 30 | IGNACIO | 31 | 25000.00
(14 filas)

Si se quiere el ordenamiento en base a múltiples columnas, se separan cada una de ellas con
comas. Por ejemplo:
SELECT id_empleado, departamento, nombre, edad, salario
FROM info_empleados
WHERE departamento = '30'
ORDER BY salario, edad DESC;

id_empleado | departamento | nombre | edad | salario


-------------+--------------+------------------+------+----------
QN191 | 30 | LIZ EDITH | 34 | 11000.00
QN160 | 30 | JOSE JAIME | 57 | 12000.00
QN197 | 30 | JUAN JOSE | 55 | 13000.00
QN201 | 30 | RAMON | 42 | 14000.00
QN145 | 30 | SALVADOR | 33 | 15000.00
QN133 | 30 | ISMAEL | 32 | 15000.00
QN139 | 30 | LAZARO | 28 | 15000.00
QN115 | 30 | MIGUEL | 49 | 17000.00
QN129 | 30 | ISRAEL | 34 | 17000.00
QN149 | 30 | PEDRO | 36 | 20000.00
QN193 | 30 | ERVEY ROBERTO | 31 | 20000.00
QN113 | 30 | GERARDO AGRIPINO | 30 | 22000.00
QN209 | 30 | ERICK | 23 | 22000.00
QN123 | 30 | IGNACIO | 31 | 25000.00
(14 filas)

Aparte de ordenar los resultados en orden ascendente de acuerdo al salario, cuando hay más de
1 registro con el mismo salario se ordenan éstos en orden descendente de acuerdo al nombre
del empleado.

Las clausulas LIMIT y OFFSET

Se puede limitar el despliegue de una consulta a un número determinado de consultas


utilizando la clausula LIMIT. Por ejemplo, si en el ejercicio anterior queremos solo mostrar los
primeros 5 registros encontrados:

SELECT id_empleado, departamento, nombre, edad, salario


FROM info_empleados
WHERE departamento = '30'
ORDER BY salario, edad DESC
LIMIT 5;

id_empleado | departamento | nombre | edad | salario


-------------+--------------+------------+------+----------
QN191 | 30 | LIZ EDITH | 34 | 11000.00
QN160 | 30 | JOSE JAIME | 57 | 12000.00
QN197 | 30 | JUAN JOSE | 55 | 13000.00
QN201 | 30 | RAMON | 42 | 14000.00
QN145 | 30 | SALVADOR | 33 | 15000.00
(5 filas)
Si además queremos obtener los segundos cinco registros hay que utilizar la clausula OFFSET
para definir dicho desplazamiento. Esto es útil cuando se requiere mostrar los registros
obtenidos de forma paginada.

SELECT id_empleado, departamento, nombre, edad, salario


FROM info_empleados
WHERE departamento = '30'
ORDER BY salario,edad DESC
LIMIT 5
OFFSET 5;

id_empleado | departamento | nombre | edad | salario


-------------+--------------+--------+------+----------
QN133 | 30 | ISMAEL | 32 | 15000.00
QN139 | 30 | LAZARO | 28 | 15000.00
QN115 | 30 | MIGUEL | 49 | 17000.00
QN129 | 30 | ISRAEL | 34 | 17000.00
QN149 | 30 | PEDRO | 36 | 20000.00
(5 filas)

Es necesario utilizar subconsultas para problemas más complejos, por ejemplo: Encontrar los
nombres y apellidos de los 5 gerentes de departamento más jóvenes.

SELECT nombre, apellidos, edad


FROM info_empleados
WHERE id_empleado IN (SELECT gerente FROM info_departamentos)
ORDER BY edad
LIMIT 5;

nombre | apellidos | edad


------------------+-------------------+------
SERGIO | AVILA GONZALEZ | 22
JESUS MANUEL | RUIZ CRUZ | 22
MARCO AURELIO | RAMIREZ GARCIA | 25
GERARDO AGRIPINO | BELTRAN PEREZ | 30
ALMA ANGELICA | NUNEZ DE SANTIAGO | 33
(5 filas)

Obsérvese el uso de LIMIT y ORDER BY para hallar a los gerentes más jóvenes.
Ejercicios de Repaso:

5.1 Mostrar nombre, apellido y ciudad de todos los clientes de la tabla info_clientes.
Desplegar los resultados en orden descendente de acuerdo al apellido.
5.2 Listar la descripción y precio para todos los productos donde el precio sea mayor de 500
pesos. Desplegar los resultados en orden ascendente de acuerdo al precio.
5.3 Desplegar los nombres de los 10 productos más caros.
5.4 Mostrar el id de los clientes que compraron los 10 productos más caros (Utilizar una
subconsulta).
6. Operadores Aritméticos y Funciones Matemáticas

ANSI SQL soporta los siguientes primeros cuatro operadores básicos:

+ Suma
- Resta
* Multiplicación
/ División
% Módulo

El operador módulo devuelve el residuo de una división entera. No es un operador ANSI SQL,
sin embargo, la mayoría de los motores de bases de datos lo soportan. Existen además algunas
funciones matemáticas, que aunque no están tampoco dentro de la especificación ANSI SQL,
son soportadas por la mayoría de los motores de bases de bases de datos.

Funciones matemáticas básicas


ABS(x) Devuelve el valor absoluto de x
SIGN(x) Devuelve el signo de la entrada x como -1, 0, o 1 (negativo, cero, o
positivo respectivamente)
MOD(x,y) Módulo – devuelve el residuo de la división entera x/y
FLOOR(x) Devuelve el entero inmediato inferior o igual a x
CEILING(x) or Devuelve el entero inmediato inferior o igual a x
CEIL(x)
POWER(x,y) Devuelve el valor de x elevado a la potencia y
ROUND(x) Redondea x al entero más cercano
ROUND(x,d) Devuelve el valor de x redondeado al número de cifras decimales
especificadas por el valor d
SQRT(x) Devuelve el valor de la raíz cuadrada de x

Por ejemplo:

SELECT round(salario * 1.15), nombre


FROM info_empleados
WHERE salario > 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 Mostrar la descripción y el precio de los productos, pero considerando un aumento


general del 12%.
6.2 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.
6.3 Igual al ejemplo anterior, pero solo aplicar el impuesto cuando se adquieren más de una
pieza de un artículo determinado.
6.4 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 Regresa el valor mínimo en una columna dada
MAX Regresa el valor máximo en una columna dada
SUM Regresa la suma de los valores numéricos en una columna dada
AVG Regresa el valor promedio de una columna dada
COUNT Regresa el número total de valores en una columna dada
COUNT(*) 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 AVG(salario) AS “Promedio Programador”


FROM info_empleados
WHERE 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 Desplegar el nombre del producto más caro (Tip: Se puede resolver usando la función
MAX y una subconsulta).
7.2 ¿Cuál es el número total de filas de la tabla partidas_pedidos?
7.3 Desplegar el precio más barato de los productos ordenados en partidas_pedidos.
7.4 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 columna1, FUNCIÓN(columna2)


FROM "lista-de-tablas"
GROUP BY "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 departamento, COUNT(salario), salario


FROM info_empleados
GROUP BY departamento, salario
ORDER BY 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 ¿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.
8.2 De la tabla partidas_pedidos, calcular la suma de unidades vendidas por cada producto.
Tip: Los productos necesitarán separarse en grupos aparte.
8.3 En la tabla partidas_pedidos ¿Cuántas partidas hay por cada cliente? Desplegar
id_cliente y número de pedidos.
8.4 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 columna1, SUM(columna2)


FROM "lista-de-tablas"
GROUP BY "lista-columnas"
HAVING "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 departamento, avg(salario)
FROM info_empleados
GROUP BY departamento
HAVING 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 departamento, avg(salario)


FROM info_empleados
GROUP BY departamento
WHERE 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 departamento, avg(salario)


FROM info_empleados
WHERE edad > 40
GROUP BY departamento
HAVING 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 ¿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.
9.2 ¿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.
9.3 De la tabla partidas_pedidos, desplegar los productos que vendieron más de 4 unidades.
Mostrar id del producto y las unidades vendidas.
9.4 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"
FROM tabla1,tabla2 [, tabla3, ... tabla_n]
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 nombre Apellido ciudad estado fecha producto cantidad precio


10982 Juan Perez Guadalajara JAL 032299 orejeras 2 15.00
10982 Juan Perez Guadalajara JAL 082899 pala 3 35.00
10982 Juan Perez Guadalajara JAL 091199 guantes 2 15.00
10982 Juan Perez Guadalajara JAL 100999 linterna 4 35.00
10982 Juan Perez Guadalajara JAL 022900 pala 2 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 | CELAYA RODRIGUEZ | VENTAS
PETRONILO | CELAYA MOTA | VENTAS
FRANCISCO JAVIER | DELGADO CHONG | VENTAS
JULIA ANABEL | SUAREZ ANGUIANO | VENTAS
ANGEL FLORENCIO | RODRIGUEZ PAREDES | VIGILANCIA
MARIA DE JESUS | FLORES LUNA | VIGILANCIA
GILBERTO | CERVANTES CASTRO | VIGILANCIA
VICTOR | MORALES MENDEZ | VIGILANCIA
ALEJANDRO | GOMEZ Y ACOSTA | VIGILANCIA
(103 filas)

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 que deseamos los nombres de los proyectos y el nombre y apellidos de los
gerentes que los controlan. La información requerida se encuentra en dos tablas:
info_empleados e info_proyectos, pero ¿Cómo saber que empleados son gerentes? Es
necesario entonces reunir también la tabla info_departamentos, quedando la consulta de la
siguiente manera:

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 lista_de_atributos
FROM tabla_1
INNER JOIN table_2
ON “condición de reunión”
[WHERE “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 nombre, apellidos, nombred


FROM info_empleados
INNER JOIN info_departamentos
ON 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 | CELAYA RODRIGUEZ | VENTAS
PETRONILO | CELAYA MOTA | VENTAS
FRANCISCO JAVIER | DELGADO CHONG | VENTAS
JULIA ANABEL | SUAREZ ANGUIANO | VENTAS
ANGEL FLORENCIO | RODRIGUEZ PAREDES | VIGILANCIA
MARIA DE JESUS | FLORES LUNA | VIGILANCIA
GILBERTO | CERVANTES CASTRO | VIGILANCIA
VICTOR | MORALES MENDEZ | VIGILANCIA
ALEJANDRO | GOMEZ Y ACOSTA | VIGILANCIA
(103 filas)

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 nombre, apellidos, nombrepr


FROM info_empleados
INNER JOIN info_departamentos
ON id_empleado = gerente
INNER JOIN info_proyectos
ON id_departamento = numd
WHERE 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 nombre, apellidos, nombrepr
FROM info_empleados
JOIN info_departamentos
ON id_empleado = gerente
JOIN info_proyectos
ON id_departamento = numd
WHERE nombrepr = ‘COMPACTACION DE CATEGORIAS’;

Ejercicios de Repaso (combinando productos cartesianos en FROM y condiciones


de reunión en WHERE):

10.1 Listar el nombre, apellido y el id del producto que cada uno de los clientes adquirió para
cada una de las partidas.
10.2 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.
10.3 Repetir el ejercicio #1, pero desplegar los resultados ordenados por estado en orden
descendente (mostrar además el campo estado).
10.4 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 Listar el nombre, apellido y el id del producto que cada uno de los clientes adquirió para
cada una de las partidas.
10.6 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.
10.7 Repetir el ejercicio #1, pero desplegar los resultados ordenados por estado en orden
descendente (mostrar además el campo estado).
10.8 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.

También podría gustarte