36 - Combinación interna (inner join)

Un join es una operación que relaciona dos o más tablas para obtener un resultado que incluya datos (campos y registros) de ambas; las tablas participantes se combinan según los campos comunes a ambas tablas.

Hay tres tipos de combinaciones:

  1. combinaciones internas (inner join o join),
  2. combinaciones externas y
  3. combinaciones cruzadas.

También es posible emplear varias combinaciones en una consulta "select", incluso puede combinarse una tabla consigo misma.

La combinación interna emplea "join", que es la forma abreviada de "inner join". Se emplea para obtener información de dos tablas y combinar dicha información en una salida.

La sintaxis básica es la siguiente:

 select CAMPOS
  from TABLA1
  join TABLA2
  on CONDICIONdeCOMBINACION;

Ejemplo:

 select * 
  from libros
  join editoriales on codigoeditorial=editoriales.codigo;

Analicemos la consulta anterior.

- especificamos los campos que aparecerán en el resultado en la lista de selección;

- indicamos el nombre de la tabla luego del "from" ("libros");

- combinamos esa tabla con "join" y el nombre de la otra tabla ("editoriales"); se especifica qué tablas se van a combinar y cómo;

- cuando se combina información de varias tablas, es necesario especificar qué registro de una tabla se combinará con qué registro de la otra tabla, con "on". Se debe especificar la condición para enlazarlas, es decir, el campo por el cual se combinarán, que tienen en común.
"on" hace coincidir registros de ambas tablas basándose en el valor de tal campo, en el ejemplo, el campo "codigoeditorial" de "libros" y el campo "codigo" de "editoriales" son los que enlazarán ambas tablas. Se emplean campos comunes, que deben tener tipos de datos iguales o similares.

La condición de combinación, es decir, el o los campos por los que se van a combinar (parte "on"), se especifica según las claves primarias y externas.

Note que en la consulta, al nombrar el campo usamos el nombre de la tabla también. Cuando las tablas referenciadas tienen campos con igual nombre, esto es necesario para evitar confusiones y ambiguedades al momento de referenciar un campo. En el ejemplo, si no especificamos "editoriales.codigo" y solamente tipeamos "codigo", SQLite no sabrá si nos referimos al campo "codigo" de "libros" o de "editoriales" y mostrará un mensaje de error indicando que "codigo" es ambiguo.

Entonces, si las tablas que combinamos tienen nombres de campos iguales, DEBE especificarse a qué tabla pertenece anteponiendo el nombre de la tabla al nombre del campo, separado por un punto (.).

Si una de las tablas tiene clave primaria compuesta, al combinarla con la otra, en la cláusula "on" se debe hacer referencia a la clave completa, es decir, la condición referenciará a todos los campos clave que identifican al registro.

Se puede incluir en la consulta join la cláusula "where" para restringir los registros que retorna el resultado; también "order by", etc..

Se emplea este tipo de combinación para encontrar registros de la primera tabla que se correspondan con los registros de la otra, es decir, que cumplan la condición del "on". Si un valor de la primera tabla no se encuentra en la segunda tabla, el registro no aparece.

Para simplificar la sentencia podemos usar un alias para cada tabla:

 select l.codigo,titulo,autor,nombre
  from libros as l
  join editoriales as e on l.codigoeditorial=e.codigo;

En algunos casos (como en este ejemplo) el uso de alias es para fines de simplificación y hace más legible la consulta si es larga y compleja, pero en algunas consultas es absolutamente necesario.

Problema resuelto

Una empresa tiene registrados sus clientes en una tabla llamada "clientes", también tiene una tabla "provincias" donde registra los nombres de las provincias.

Eliminar ambas tablas si existen:

drop table if exists provincias;
drop table if exists clientes;

Creamos las tablas con las siguientes estructuras:

 create table clientes (
  codigo integer primary key,
  nombre text,
  domicilio text,
  ciudad text,
  codigoprovincia integer
 );

 create table provincias(
  codigo integer primary key,
  nombre text
 );

Almacenamos algunos registros en ambas tablas:

 insert into provincias (nombre) values('Cordoba');
 insert into provincias (nombre) values('Santa Fe');
 insert into provincias (nombre) values('Corrientes');
 
 insert into clientes(nombre,domicilio,ciudad,codigoprovincia) 
   values ('Lopez Marcos','Colon 111','Córdoba',1);
 insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
   values ('Perez Ana','San Martin 222','Cruz del Eje',1);
 insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
   values ('Garcia Juan','Rivadavia 333','Villa Maria',1);
 insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
   values ('Perez Luis','Sarmiento 444','Rosario',2);
 insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
   values ('Pereyra Lucas','San Martin 555','Cruz del Eje',1);
 insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
   values ('Gomez Ines','San Martin 666','Santa Fe',2);
 insert into clientes(nombre,domicilio,ciudad,codigoprovincia)
   values ('Torres Fabiola','Alem 777','Ibera',3);

Obtener los datos de ambas tablas, usando alias para los nombres de tablas:

 select c.nombre,domicilio,ciudad,p.nombre
  from clientes as c
  join provincias as p on c.codigoprovincia=p.codigo; 

Obtener la misma información anterior pero ordenada por nombre de provincia

 select c.nombre,domicilio,ciudad,p.nombre
  from clientes as c
  join provincias as p on c.codigoprovincia=p.codigo
  order by p.nombre; 

Recuperar los clientes de la provincia de "Santa Fe"

 select c.nombre,domicilio,ciudad
  from clientes as c
  join provincias as p on c.codigoprovincia=p.codigo
  where p.nombre='Santa Fe';  

Problema propuesto

  1. Borrar las tablas "peliculas" y "generos" si existen.

  2. Crear las tablas con las siguientes estructuras:

    create table generos(
    	codigo integer primary key,
    	descripcion text
    );
    
    create table peliculas (
    	codigo integer primary key,
    	titulo text,
    	actor text,
    	duracion integer,
    	genero integer
    );
    
  3. Insertar las siguientes filas en las tablas:

    insert into generos(descripcion) values ('Aventura');
    insert into generos(descripcion) values ('Romance');
    insert into generos(descripcion) values ('Acción');
    
     insert into peliculas (titulo,actor,duracion,genero)
      values('Mision imposible','Tom Cruise',120, 3);
     insert into peliculas (titulo,actor,duracion,genero)
      values('Harry Potter y la piedra filosofal','Daniel R.',180, 1);
     insert into peliculas (titulo,actor,duracion,genero)
      values('Harry Potter y la camara secreta','Daniel R.',190, 1);
     insert into peliculas (titulo,actor,duracion,genero)
      values('Mision imposible 2','Tom Cruise',120, 3);
     insert into peliculas (titulo,actor,duracion,genero)
      values('Mujer bonita','Richard Gere',120, 2);
     insert into peliculas (titulo,actor,duracion,genero)
      values('Elsa y Fred','China Zorrilla',110, 2); 
    
  4. Imprimir todos los datos de las películas inclusive su género.

Solución
drop table if exists generos;
drop table if exists peliculas;

create table generos(
	codigo integer primary key,
	descripcion text
);

create table peliculas (
	codigo integer primary key,
	titulo text,
	actor text,
	duracion integer,
	genero integer
);

insert into generos(descripcion) values ('Aventura');
insert into generos(descripcion) values ('Romance');
insert into generos(descripcion) values ('Acción');

 insert into peliculas (titulo,actor,duracion,genero)
  values('Mision imposible','Tom Cruise',120, 3);
 insert into peliculas (titulo,actor,duracion,genero)
  values('Harry Potter y la piedra filosofal','Daniel R.',180, 1);
 insert into peliculas (titulo,actor,duracion,genero)
  values('Harry Potter y la camara secreta','Daniel R.',190, 1);
 insert into peliculas (titulo,actor,duracion,genero)
  values('Mision imposible 2','Tom Cruise',120, 3);
 insert into peliculas (titulo,actor,duracion,genero)
  values('Mujer bonita','Richard Gere',120, 2);
 insert into peliculas (titulo,actor,duracion,genero)
  values('Elsa y Fred','China Zorrilla',110, 2);  


 select titulo, actor, duracion, descripcion 
   from peliculas as p
   inner join generos as g on g.codigo=p.genero;


Ejecución de ejercicios online

Puede ejecutar comandos de SQLite directamente en el sitio sin tener que instalar nada en su computadora.

Resultado.....