domingo, 13 de mayo de 2012

39 - Clave primaria compuesta.

Las claves primarias pueden ser simples, formadas por un solo campo o compuestas, más de un campo.
Recordemos que una clave primaria identifica 1 solo registro en una tabla. Para un valor del campo clave existe solamente 1 registro. Los valores no se repiten ni pueden ser nulos.

Retomemos el ejemplo de la playa de estacionamiento que almacena cada día los datos de los vehículos que ingresan en la tabla llamada "vehiculos" con los siguientes campos:

 - patente char(6) not null,
 - tipo char (4),
 - horallegada time not null,
 - horasalida time,
 
Necesitamos definir una clave primaria para una tabla con los datos descriptos arriba. No podemos usar la patente porque un mismo auto puede ingresar más de una vez en el día a la playa; tampoco podemos usar
la hora de entrada porque varios autos pueden ingresar a una misma hora. Tampoco sirven los otros campos.

Como ningún campo, por si solo cumple con la condición para ser clave, es decir, debe identificar un solo registro, el valor no puede repetirse, debemos usar 2 campos.

Definimos una clave compuesta cuando ningún campo por si solo cumple con la condición para ser clave.

En este ejemplo, un auto puede ingresar varias veces en un día a la playa, pero siempre será a distinta hora.

Usamos 2 campos como clave, la patente junto con la hora de llegada, así identificamos unívocamente cada registro.

Para establecer más de un campo como clave primaria usamos la siguiente sintaxis:

 create table vehiculos(
  patente char(6) not null,
  tipo char(4),
  horallegada time not null
  horasalida time,
  primary key(patente,horallegada)
 );
 
Nombramos los campos que formarán parte de la clave separados por comas.

Si vemos la estructura de la tabla con "describe" vemos que en la columna "key", en ambos campos aparece "PRI", porque ambos son clave primaria.

Un campo que es parte de una clave primaria puede ser autoincrementable sólo si es el primer campo que compone la clave, si es secundario no se permite.

Es posible eliminar un campo que es parte de una clave primaria, la clave queda con los campos restantes.

Esto, siempre que no queden registros con clave repetida. Por ejemplo, podemos eliminar el campo "horallegada":

 alter table vehiculos drop horallegada;
 
siempre que no haya registros con "patente" duplicada, en ese caso aparece un mensaje de error y la eliminación del campo no se realiza.

En caso de ejecutarse la sentencia anterior, la clave queda formada sólo por el campo "patente".


Problema Resuelto: 

Una playa de estacionamiento guarda cada día los datos de los vehículos que ingresan a la playa en una tabla llamada "vehiculos".

Eliminamos la tabla, si existe:

 drop table if exists vehiculos;
 
Para crear una tabla con clave primaria compuesta usamos la siguiente sintaxis:

 create table vehiculos(
  patente char(6) not null,
  tipo char(4),
  horallegada time not null,
  horasalida time,
  primary key(patente,horallegada)
 );
 
Veamos la estructura de la tabla:

 describe vehiculos;
 
Vemos que en la columna "key", en ambos campos aparece "PRI", porque ambos son clave primaria.
Ingresemos los siguientes registros:

 insert into vehiculos (patente,tipo,horallegada,horasalida)
  values('ACD123','auto','8:30','9:40');
 insert into vehiculos (patente,tipo,horallegada,horasalida)
  values('AKL098','auto','8:45','11:10');
 insert into vehiculos (patente,tipo,horallegada,horasalida)
  values('HGF123','auto','9:30','11:40');
 insert into vehiculos (patente,tipo,horallegada,horasalida)
  values('DRT123','auto','15:30',null);
 insert into vehiculos (patente,tipo,horallegada,horasalida)
  values('FRT545','moto','19:45',null);
 insert into vehiculos (patente,tipo,horallegada,horasalida)
  values('GTY154','auto','20:30','21:00');
 
4- Intente ingresar un vehículo con clave primaria repetida:

 insert into vehiculos (patente,tipo,horallegada,horasalida)
   values('ACD123','auto','16:00',null);
 
Aparece un mensaje de error indicando que la clave está duplicada.

5- Si ingresamos un registro con patente repetida, no hay problemas, siempre que la hora de ingreso sea diferente, sino, repetimos el valor de la clave:

 insert into vehiculos (patente,tipo,horallegada,horasalida)
  values('ACD123','auto','16:00',null);
 
6- Si ingresamos un registro con hora de ingreso repetida, no hay problemas, siempre que la patente sea diferente, sino, repetimos el valor de la clave:

 insert into vehiculos (patente,tipo,horallegada,horasalida)
  values('ADF123','moto','8:30','10:00');
 
7- Intente eliminar el campo "horallegada":

 alter table vehiculos drop horallegada;
 
No se puede porque quedarían registros con clave repetida.

8- Elimine los registros con patente "ACD123":

 delete from vehiculos
  where patente='ACD123';
 
9- Intente nuevamente eliminar el campo "horallegada":

 alter table vehiculos drop horallegada;

Ahora si lo permite.

10- Vea la estructura de la tabla para ver cómo quedó la clave primaria:

  describe vehiculos;
 
 
 
Problema Propuesto:
 
 
Una pequeña biblioteca de barrio registra los préstamos de sus libros en 
una tabla llamada "prestamos". En ella almacena la siguiente información:
 
 -título del libro,
 -documento de identidad del socio a quien se le presta el libro,
 -fecha de préstamo,
 -fecha de devolución del libro,
 -devuelto: si el libro ha sido o no devuelto.

1- Elimine la tabla "prestamos" si existe.

2- Necesitamos una clave que identifique cada registro en la tabla "prestamos". 
El mismo libro no puede prestarse en la misma fecha.

3- Cree la tabla:
 
 create table prestamos(
  titulo varchar(40) not null,
  documento char(8) not null,
  fechaprestamo date not null,
  fechadevolucion date,
  devuelto char(1) default 'N',
  primary key(titulo,fechaprestamo)
 );

4- Ingrese los siguientes registros para la tabla "prestamos":
 
 insert into prestamos (titulo,documento,fechaprestamo)
  values('Manual de 1 grado','22333444','2006-07-10');
 insert into prestamos (titulo,documento,fechaprestamo)
  values('Manual de 1 grado','22333444','2006-07-20');
 insert into prestamos (titulo,documento,fechaprestamo)
  values('Manual de 1 grado','23333444','2006-07-15');
 insert into prestamos (titulo,documento,fechaprestamo)
  values('El aleph','22333444','2006-07-10');
 insert into prestamos (titulo,documento,fechaprestamo)
  values('El aleph','30333444','2006-08-10'); 
 
Note que un mismo libro fue prestado a un mismo socio pero en una fecha 
distinta.

5- Intente ingresar un valor de clave primaria repetida:
 
 insert into prestamos (titulo,documento,fechaprestamo)
  values('Manual de 1 grado','25333444','2006-07-10');
 
 
 
Otros problemas:
 
 
A) Un consultorio médico en el cual trabajan 3 médicos registra las consultas 
de los pacientes en una tabla llamada "consultas".

1- Elimine la tabla si existe.

2- La tabla contiene los siguientes datos:
 
 - fechayhora: datetime not null, fecha y hora de la consulta,
  - medico: varchar(30), not null, nombre del médico (Perez,Lopez,Duarte),
  - documento: char(8) not null, documento del paciente,
  - paciente: varchar(30), nombre del paciente,
  - obrasocial: varchar(30), nombre de la obra social ('IPAM','PAMI').
 );

3- Un médico sólo puede atender a un paciente en una fecha y hora 
determianada. 
 
En una fecha y hora determinada, varios médicos atienden a distintos 
pacientes. 
 
Cree la tabla definiendo una clave primaria compuesta:
 
 create table consultas(
  fechayhora datetime not null,
  medico varchar(30) not null,
  documento char(8) not null,
  paciente varchar(30),
  obrasocial varchar(30),
  primary key(fechayhora,medico)
 );

4- Ingrese varias consultas para un mismo médico en distintas horas el mismo día.

5- Ingrese varias consultas para diferentes médicos en la misma fecha y hora.

6- Intente ingresar una consulta para un mismo médico en la misma hora el mismo 
día.


B) Un club dicta clases de distintos deportes. En una tabla llamada "inscriptos" 
almacena la información necesaria.

1- Elimine la tabla "inscriptos" si existe.

2- La tabla contiene los siguientes campos:
 
 - documento del socio alumno: char(8) not null
 - nombre del socio: varchar(30),
 - nombre del deporte (tenis, futbol, natación, basquet): varchar(15) not null,
 - año de inscripcion: year,
 - matrícula: si la matrícula ha sido o no pagada ('s' o 'n').

3- Necesitamos una clave primaria que identifique cada registro. Un socio puede 
inscribirse en varios deportes en distintos años. Un socio no puede inscribirse 
en el mismo deporte el mismo año. 
 
varios socios se inscriben en un mismo deporte. Cree la tabla con una clave 
compuesta: 
 
create table inscriptos(
  documento char(8) not null, 
  nombre varchar(30),
  deporte varchar(15) not null,
  año year,
  matricula char(1),
  primary key(documento,deporte,año)
 );

4- Inscriba a varios alumnos en el mismo deporte en el mismo año.

5- Inscriba a un mismo alumno en varios deportes en el mismo año.

6- Ingrese un registro con el mismo documento de socio en el mismo deporte en 
distintos años.

7- Intente inscribir a un socio alumno en un deporte en el cual ya esté inscripto 
en un año en el cual ya se haya inscripto.

8- Intente eliminar un campo parte de la clave.


C) Un comercio guarda la información de sus ventas en una tabla llamada "facturas".

1- Elimine la tabla si existe.

2- Intente crear la tabla con la siguiente estructura:
 
 create table facturas(
  serie char(1) not null,
  numero int(10) zerofill auto_increment,
  descripcion varchar(30),
  precioporunidad decimal(5,2) unsigned,
  cantidad tinyint unsigned,
  primary key (serie,numero) 
 );

3- Aparece un mensaje de error, la tabla no puede ser creada porque el campo 
definido como "auto_increment" es secundario (primero está "serie") y sabemos 
que un campo "auto_increment" debe estar primero en orden al ser definido parte 
de la clave compuesta.

4- Cree la tabla cambiando el orden de los campos estabecidos como clave primaria:
 
 create table facturas(
  serie char(1) not null,
  numero int(10) zerofill auto_increment,
  numeroitem smallint unsigned not null,
  descripcion varchar(30),
  precioporunidad decimal(5,2) unsigned,
  cantidad tinyint unsigned,
  primary key (numero,serie,numeroitem) 
 );
 
 Tenga en cuenta al ingresar registros que el campo "numero" se autoincrementará 
sin tener en cuenta los demás campos.

5- Ingrese 3 registros con igual "serie", "numero" y distintos números de items:
 
 insert into facturas (serie,numero,numeroitem,descripcion,precioporunidad,cantidad)
  values('A',100,1,'escuadra 20 cm.',2.50,20);
 insert into facturas (serie,numero,numeroitem,descripcion,precioporunidad,cantidad)
  values('A',100,2,'escuadra 50 cm.',5,30);
 insert into facturas (serie,numero,numeroitem,descripcion,precioporunidad,cantidad)
  values('A',100,3,'goma lapiz-tinta',0.35,100);

6- Ingrese los siguientes registros:
 
 insert into facturas (serie,numero,numeroitem,descripcion,precioporunidad,cantidad)
  values('A',102,1,'lapices coloresx6',4.40,50);
 insert into facturas (serie,numero,numeroitem,descripcion,precioporunidad,cantidad)
  values('A',102,2,'lapices coloresx12',8,60);
 insert into facturas (serie,numero,numeroitem,descripcion,precioporunidad,cantidad)
  values('B',102,1,'lapices coloresx24',12.35,100);
 insert into facturas (serie,numero,numeroitem,descripcion,precioporunidad,cantidad)
  values('B',102,2,'goma lapiz-tinta',0.35,200);

7- Ingrese los siguientes registros y vea qué valor da al "numero" que no se 
ingresa:
 
 insert into facturas (serie,numeroitem,descripcion,precioporunidad,cantidad)
  values('A',1,'compas plastico',12,50);
 
 insert into facturas (serie,numeroitem,descripcion,precioporunidad,cantidad)
  values('A',1,'compas metal',18.90,80);

8- Intente ingresar un registro con valores de clave repetida:
 
 insert into facturas (serie,numero,numeroitem,descripcion,precioporunidad,cantidad)
  values('A',104,1,'compas metal',18.90,80);

9- Muestre los registros concatenando "serie" con "numero", usando un alias para 
esa columna, muestre los demás campos y ordene por el alias:
 
 
10- Agrupe los registros por serie y número de factura y muestre el total 
(en una columna calculada) de cada factura:
 


5 comentarios:

  1. USE academico;

    CREATE TABLE `estumat`(
    id_materia varchar(10) NOT NULL,
    EXPEDIENTE int(10) DEFAULT NULL,
    PRIMARY KEY(id_materia EXPEDIENTE),
    FOREIGN(id_materia) REFERENCES materia (id_materia),
    FOREIGN(EXPEDIENTE) REFERENCES alumnos (EXPEDIENTE)
    );

    espero me puedan ayudar, me da error al tratar de crear esta tabla :( MySQL ha dicho: Documentación
    #1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'EXPEDIENTE),
    FOREIGN(id_materia) REFERENCES materia (id_materia),
    FOREIGN(EXPE' at line 4

    ResponderEliminar
  2. Tiene que ser "PRIMARY KEY(id_materia,EXPEDIENTE)," ... se te olvidó colocar la coma al lado de "id_materia", lo más probable sea eso que te ocasionaba el error.

    ResponderEliminar
  3. Hola, una pregunta, soy nuevo en MySQL y se me han complicado un poco las cosas, estoy familiarizado con SQL Server y SQL Wharehouse. Me gustaría preguntarte cual sería la query para que una vez creada la tabla, pueda yo decirle que sea compuesta, ya que al momento de crear la tabla no le dije que fuera compuesta.

    Saludos.

    ResponderEliminar
  4. Muchas gracias por tu ayuda, me sirvió bastante

    ResponderEliminar
  5. Hola! Te agradezco me indiques si es posible hacer que esa llave compuesta sea una llave foranea en otra tabla y como se hace?

    Saludos;

    VictoriaB.

    ResponderEliminar