MySQL Tutorial
MySQL Tutorial
c
p
p
El mensaje anterior indica que la base de datos no ha sido creada, por lo tanto
necesitamos crearla.
#
$%& '(&
))
*+
,
p
!
-
p
Bajo el sistema operativo Unix, los nombres de las bases de datos son sensibles al uso
de mayúsculas y minúsculas (no como las palabras clave de SQL), por lo tanto debemos
de tener cuidado de escribir correctamente el nombre de la base de datos. Esto es cierto
también para los nombres de las tablas.
Al crear una base de datos no se selecciona ésta de manera autómatica; debemos hacerlo
de manera explícita, por ello usamos el comando USE en el ejemplo anterior.
La base de datos se crea sólo una vez, pero nosotros debemos seleccionarla cada vez
que iniciamos una sesión con mysql. Por ello es recomendable que se indique la base de
datos sobre la que vamos a trabajar al momento de invocar al monitor de MySQL. Por
ejemplo:
-p .-
.%%p ./
&/
&000000
1
p
-2 $3p
&+
pp-#
& 4+
5
%&2 $3
6
&7&7&
8+98+8: .
/-/#
& 4-)
&-/+ / 4
&-%))&
p
&
c
c
ë
á â
á
á ë
á ë ! !
"á # $
%á &
!
'á &
!
(
)á * &
+,-,,+--+
.á / !
0á
(
!
áë 1
áë
áë
á2
"á2 3
! !
%á#
'á# 4
)á# 3
.á# (
0á2 (
á2 1$
á5(
á56(
áë
"á7
8
%á7
$
'á7
(
)áë$
.á* !
0á*
á/9: ; ;
á/9: !4
áë !
á7
!
4 1!
"á5! !!
%á
"áë
4
4
%áë$
'á&
! (
)á& 6 !
.á5!!
"0á<
"á
(
(
"áë
!
"á5!!
1
" á5!!
4
""á/
4
"%á
"'á#
")á#
".á# 4
%0á7
(8(
%á7
(8
%á2 8
%áë 1($
% á2 (8
%"á2 !8
%%á2
8
%'á2 8
%)á2 8 !8
%.á8 =!(
!
'0á8
$
'á7
(
1
'á2
'áë
' áë
8
'"áâ
1 >
'%áâ !
1
''áâ !
1
8
')á5
6
1
'.á5
6
>8
)0á/ !
8
)á/ !
8
)á/ !
8
)áë:
;
) á<
á
á
c
c
á á
á
SQL, Structure Query Language (Lenguaje de Consulta Estructurado) es un lenguaje de
programacion para trabajar con base de datos relacionales como MySQL, Oracle, etc.
MySQL permite crear base de datos y tablas, insertar datos, modificarlos, eliminarlos,
ordenarlos, hacer consultas y realizar muchas operaciones, etc., resumiendo: administrar
bases de datos.
&p&
#
&!"p&
#
Aá á
á
á
Una base de datos es un conjunto de tablas.
Para que el servidor nos muestre las bases de datos existentes, se lo solicitamos
enviando la instrucción:
-
#
±os mostrará los nombres de las bases de datos, debe aparecer en este sitio
"administracion".
c
c
*á á
ááááá
á
á
á áá á
á
á á
á ááá
Una base de datos almacena sus datos en tablas.
Una tabla es una estructura de datos que organiza los datos en columnas y filas; cada
columna es un campo (o atributo) y cada fila, un registro. La intersección de una
columna con una fila, contiene un dato específico, un solo valor.
Cada campo (columna) debe tener un nombre. El nombre del campo hace referencia a la
información que almacenará.
Cada campo (columna) también debe definir el tipo de dato que almacenará.
MarioPerez Marito
MariaGarcia Mary
DiegoRodriguez z8080
Gráficamente acá tenemos la tabla usuarios, que contiene dos campos llamados:nombre
y clave. Luego tenemos tres registros almacenados en esta tabla, el primero almacena en
el campo nombre el valor "MarioPerez" y en el campo clave "Marito", y así
sucesivamente con los otros dos registros.
-
#
Deben aparecer todas las tablas que han creado los visitantes al sitio mysqlya.com.ar
Al crear una tabla debemos resolver qué campos (columnas) tendrá y que tipo de datos
almacenarán cada uno de ellos, es decir, su estructura.
La tabla debe ser definida con un nombre que la identifique y con el cual accederemos a
ella.
c
c
&%%&
*
p&7&
-&*8,(
77&
-&*,
,#
Si intentamos crear una tabla con un nombre ya existente (existe otra tabla con ese
nombre), mostrará un mensaje de error indicando que la acción no se realizó porque ya
existe una tabla con el mismo nombre.
Para ver las tablas existentes en una base de datos tipeamos nuevamente:
-
#
Cuando se crea una tabla debemos indicar su nombre y definir sus campos con su tipo
de dato. En esta tabla "usuarios" definimos 2 campos:
.
p&%
&;%
-8
&
&
%(
%p
&;
p&%%&
.
7
&
&
&
%(%%&&;
7
%%&
+
Cada usuario ocupará un registro de esta tabla, con su respectivo nombre y clave.
Para ver la estructura de una tabla usamos el comando "describe" junto al nombre de la
tabla:
Aparece lo siguiente:
Esta es la estructura de la tabla "usuarios"; nos muestra cada campo, su tipo, lo que
ocupa en bytes y otros datos como la aceptación de valores nulos etc, que veremos más
adelante en detalle.
&
/%%&
#
Si tipeamos nuevamente:
&
/%%&
#
Aparece un mensaje de error, indicando que no existe, ya que intentamos borrar una
tabla inexistente.
c
c
&
/)?%%&
#
rá
,$%&p
p
&
%&
p
+
.p@@?
&
/)?#
9.&%p@@(&
%
p/
p&7&
-&*9,
p
7&
-&*8,
)
7&
-&*,
&*
p&7&
-&*9,(
p
7&
-&*8,(
)
7&
-&*,
,#
8.A
&&%7p+/&
pB&&
&+
.C%
?*-
,+
D.C%
&%
%&@@*
&,+
E.p(?*&
/()?,+
6.Ap&
;%%)?*&
/
,+
!/&
&%pB&&
&
%
?+
á ááá
ááááá
á
á
á
á á
á
Un registro es una fila de la tabla que contiene los datos propiamente dichos. Cada
registro tiene un dato por cada columna.
&%%&
*
p&7&
-&*8,(
77&
-&*,
,#
Al ingresar los datos de cada registro debe tenerse en cuenta la cantidad y el orden de
los campos.
&
%%&
*
p&(
7,7%*2&
F& (2&
,#
c
c
Usamos "insert into". Especificamos los nombres de los campos entre paréntesis y
separados por comas y luego los valores para cada campo, también entre paréntesis y
separados por comas.
MarioPerez Marito
Es importante ingresar los valores en el mismo orden en que se nombran los campos, si
ingresamos los datos en otro orden, no aparece un mensaje de error y los datos se
guardan de modo incorrecto.
±ote que los datos ingresados, como corresponden a campos de cadenas de caracteres se
colocan entre comillas simples. Las comillas simples son OBLIGATORIAS.
p&(
7)&
p%%&
#
Aparece un registro.
El comando "select" recupera los registros de una tabla. Luego del comando select
indicamos los nombres de los campos a rescatar.
á
rá
&B
@@+
.p@@(?
&
/)?#
9.&%p@@+!&
%
p/
p&*
9,(
p
*
8, )
*
,
&*
p&7&
-&*9,(
p
7&
-&*8,(
)
7&
-&*,
,#
8.C%
?/&7&)
&
&
G
@@+
*-
,+
.C%
&%
%&@@+*
&,+
D.A&
%&&
&
*
p&(
p
()
,7%
*&
2
&(
98(98DE6,#
&
*
p&(
p
( )
,7%
*H%
&&(78D(D:6:6,#
E.
p%&
&&
p&(
p
()
)&
p#
c
c
- varchar: se usa para almacenar cadenas de caracteres. Una cadena es una secuencia de
caracteres. Se coloca entre comillas (simples): 'Hola'. El tipo "varchar" define una
cadena de longitud variable en la cual determinamos el máximo de caracteres. Puede
guardar hasta 255 caracteres. Para almacenar cadenas de hasta 30 caracteres, definimos
un campo de tipo varchar(30). Si asignamos una cadena de caracteres de mayor longitud
que la definida, la cadena se corta. Por ejemplo, si definimos un campo de tipo
varchar(10) y le asignamos la cadena 'Buenas tardes', se almacenará 'Buenas tar'
ajustándose a la longitud de 10 caracteres.
- float: se usa para almacenar valores numéricos decimales. Se utiliza como separador el
punto (.). Definimos campos de este tipo para precios, por ejemplo.
Antes de crear una tabla debemos pensar en sus campos y optar por el tipo de dato
adecuado para cada uno de ellos. Por ejemplo, si en un campo almacenaremos números
enteros, el tipo "float" sería una mala elección; si vamos a guardar precios, el tipo
"float" es correcto, no así "integer" que no tiene decimales.
rá
7
%%%/I
%7
p
)
&p
G
%/I
%%
p@/
%@#/&
/I
%
%
.
p&(
&
&9
%(
.
&(
&
&9
%(
.%&
G(7
&%pJ&
&
+
.
/7
&&
+
.p (?
&
/)?/
%#
c
c
9.&
/
%
/&
p/
&/
%*
p&7&
-&*9,(
&7&
-&*9,(
%&
&(
&
,#
8.C&%
%&
&/
%#
.A&
%&&
&
/
%*
p&(
&(%&
(
,
7%*2
p/
(
p&%(9(8,#
&
/
%*
p&(
&(%&
(
,
7%*2
p/
9(
p&%(:(9,#
&
/
%*
p&(
&(%&
(
,
7%*2%B&
(H%+((8,#
&
/
%*
p&(
&(%&
(
,
7%* <&(-K
&&((9,#
D.2%&
&&
0)&
p/
%#
á á
áá
á
á
á
Hemos aprendido cómo ver todos los registros de una tabla:
0)&
p&
#
El comando "select" recupera los registros de una tabla. Con el asterisco (*) indicamos
que seleccione todos los campos de la tabla que nombramos.
Podemos especificar el nombre de los campos que queremos ver separándolos por
comas:
& (
)&
p&
#
á
á
c
c
rá
&
/)?/
%#
2- Cree la tabla:
&/
%*
%
7&
-&*9,(
&7&
-&*9,(
%&
&(
&
,#
&
/
%*%
(
&(%&
(
,
7%*2
p/
(
p&%(9(8,#
&
/
%*%
(
&(%&
(
,
7%*2
p/
9(
p&%(:(9,#
&
/
%*%
(
&(%&
(
,
7%*2%B&
(H% +((8,#
&
/
%*%
(
&(%&
(
,
7%* <&(-K
&&((9,#
á á
áá
á
!
á
á áá
Hemos aprendido cómo ver todos los registros de una tabla:
p&(
7)&
p %%&
#
El comando "select" recupera los registros de una tabla. Detallando los nombres de los
campos separados por comas, indicamos que seleccione todos los campos de la tabla
que nombramos.
c
c
Existe una cláusula, "where" que es opcional, con ella podemos especificar condiciones
para la consulta "select". Es decir, podemos recuperar algunos registros, sólo los que
cumplan con ciertas condiciones indicadas con la cláusula "where". Por ejemplo,
queremos ver el usuario cuyo nombre es "MarioPerez", para ello utilizamos "where" y
luego de ella, la condición:
p&(
7)&
p%%&
-&
p&L2&
F& #
Para las condiciones se utilizan operadores relacionales (tema que trataremos más
adelante en detalle). El signo igual(=) es un operador relacional. Para la siguiente
selección de registros especificamos una condición que solicita los usuarios cuya clave
es igual a 'bocajunior':
p&(
7)&
p%%&
-&
7L
B%
&#
rá
&Bp
%&@@+
.pp
@@(?
&
/)?#
9.&p
(
%
p/
p&*
9,(
p
*
8, )
*
,+
8.C%
&%
%&@@+*
&,+
.A&
%&&
&
2
&(
98(98DE6(
H%
&&(78D(D:6: 6(
2&3
/ (&% 888(DDD(
<&
3
/ (&% 888(DDD+
D.
&&
+*
,+
E.
&&
%
p&H%
&&+
6.
&&
%
p
98+
:.2%&
%J)
DDD+
.p@@
á
á
á
c
c
Xá á"
á
á#á$%á$á$#á%á
%#á
Hemos aprendido a especificar condiciones de igualdad para seleccionar registros de
una tabla; por ejemplo:
%
(%
&(
&)&
p&
-&%
&L"
&#
Los operadores relacionales vinculan un campo con un valor para que MySQL compare
cada registro (el campo especificado) con el valor dado.
L %
M
p
&
M p
&
L p
&
%
ML p
&
%
Podemos seleccionar los registros cuyo autor sea diferente de 'Borges', para ello usamos
la condición:
Podemos comparar valores numéricos. Por ejemplo, queremos mostrar los libros cuyos
precios sean mayores a 20 pesos:
,#
8.C&%
%& *
&,+
.A&%
&&
&
&
%
*
(
p&(
&/
(/&
(
,
7%*(p/&
&(/
%D(+:(9,#
&
&
%
*
(
p&(
&/
(/&
(
,
7%*9(p/&
&(/
%:D(D(8,#
&
&
%
*
(
p&(
&/
(/&
(
,
7%*8(p
&(p%(:(,#
&
&
%
*
(
p&(
&/
(/&
(
,
7%*(
("( (D,#
&
&
%
*
(
p&(
&/
(/&
(
,
7%*D(
(/N
"((D,#
D.
&&
+*
,+
E.2%&
p/&
&+
6.
&I
%
%
/&
p
&
%D
0)&
p&
%
-&/&
LD#
:.
&I
%
%
p
&8
p&(
&/
(/&
(
)&
p&
%
-&
M9#
.
p&
&/
G
&I
%
%
%
O
p&(
&/
)&
p&
%
-&/&
M#
á á&áá
áááá
á
Para eliminar los registros de una tabla usamos el comando "delete":
)&
p%%&
#
La ejecución del comando indicado en la línea anterior borra TODOS los registros de la
tabla.
Si queremos eliminar uno o varios registros debemos indicar cuál o cuáles, para ello
utilizamos el comando "delete" junto con la clausula "where" con la cual establecemos
la condición que deben cumplir los registros a borrar. Por ejemplo, queremos eliminar
aquel registro cuyo nombre de usuario es 'Leonardo':
)&
p%%&
-&
p&L3
&
#
c
c
rá
&B
@@%&&)
&p
G&)&
%p
+
.p*&
/,? *)?,+
9.&
%
p/
/
*
8,(
p&*
9,(
p
*
8, )
*
,
&*
/
7&
-&*8,(
p&7&
-&*9,(
p
7&
-&*8,(
)
7&
-&*,
,#
8.C%
&%
%&@@*
&,+
.A&
%&&
*&
,
2
&(&
(
98(98DE6(
&&(H%(78D(D:6:6(
3
/ (2&(&% 888(DDD(
3
/ (H
(&% 888(DDD(
F&(%(P&+F 98(98DE+
D.p&&
%
p&H%* .-&,+
E.p
&&
%
Qp&
)G
%DDD+
'á á(
!
áá
ááá
áá
Para modificar uno o varios datos de uno o varios registros utilizamos "update"
(actualizar).
Por ejemplo, en nuestra tabla "usuarios", queremos cambiar los valores de todas las
claves, por "RealMadrid":
%/%%&
7L2&#
Utilizamos "update" junto al nombre de la tabla y "set" junto con el campo a modificar
y su nuevo valor.
%/%%&
7L"
-&
p&L 2&
F& #
Si no encuentra registros que cumplan con la condición del "where", ningún registro es
afectado.
%/%%&
p&L2&
!%&(
7L2&
-&
p&L2&
#
Para ello colocamos "update", el nombre de la tabla, "set" junto al nombre del campo y
el nuevo valor y separado por coma, el otro nombre del campo con su nuevo valor.
rá
&B
@@%p
%p
+
.p?+
9.&
&*
/
7&
-&*8,(
p&7&
-&*9,(
p
7&
-&*8,(
)
7&
-&*,
,#
8.C%
&%
%&@@*
&,+
.A&
%&&
*&
,
2
&(&
(
98(98DE6(
&&(H%(78D(D:6:6(
3
/ (2&(&% 888(DDD(
3
/ (H
(&% 888(DDD(
F&(%(P&+F 98(98DE+
D.2
)%&&
%
p&@H%@/
&@H%
H
@*%/ .-&,
%/
p&LH%H
-&
p&LH%#
E.
%
&&
%
Qp&
)G
%
DDD/
&DDEE
%/)
LDDEE
-&)
LDDD#
6.
%
&&
%
p/
@
p&@7
&
@H%@/
&@H%H
@
c
c
á áá
á
Una clave primaria es un campo (o varios) que identifica 1 solo registro (fila) en una
tabla.
Para un valor del campo clave existe solamente 1 registro. Los valores no se repiten ni
pueden ser nulos.
&%%&
*
p&7&
-&*9,(
77&
-&*,(
/&p& *
p&,
,#
Para definir un campo como clave primaria agregamos "primary key" luego de la
definición de todos los campos y entre paréntesis colocamos el nombre del campo que
queremos como clave.
&
%%&
*
p&(
7,
7%*3
&
(/
,#
&
%%&
*
p&(
7,
7%*2&
F& (2&
,#
&
%%&
*
p&(
7,
7%*2&
(7&,#
&
%%&
*
p&(
7,
7%*P%7
(7&,#
Si intentamos ingresar un valor para el campo clave que ya existe, aparece un mensaje
de error indicando que el registro no se cargó pues el dato clave existe. Esto sucede
porque los campos definidos como clave primaria no pueden repetirse.
c
c
&
%% &
*
p&(
7,
7%*P%7
("
,#
Una tabla sólo puede tener una clave primaria. Cualquier campo (de cualquier tipo)
puede ser clave primaria, debe cumplir como requisito, que sus valores no se repitan.
Al establecer una clave primaria estamos indexando la tabla, es decir, creando un índice
para dicha tabla; a este tema lo veremos más adelante.
rá
&B
@&
@%&&I+
.p?+
9.&J
%
p/
7
*&,(
%
*
9
&
&
%,(%
&*
8,(
&*
D,(
&;
7/&p&
&&
*
&(
%
7&
-&*9,(
%
&7&
-&*8,(
&7&
-&*D,(
/&p& *
,
,#
8.C%
&%
%&@&
@(
p/&%
7
/&p&+
.A&
%&&
(/-("
&(F#
9(2&<&&
(H
R& (p
#
8(/&FRF(2&
2
(p
#
(&7 %B
("
&(F
#
D(2p
-(F (F
#
D.
&&
+
E.A&%&&
G
&/
p&%
&
&/
+
6.A&%&&
G
&/
I%
&
&/
+
:.A&&%&&
%&/
p/
7*/&
pB&&
&
/
&
7&/,+
Sólo puede haber un campo "auto_increment" y debe ser clave primaria (o estar
indexado).
Para establecer que un campo autoincremente sus valores automáticamente, éste debe
ser entero (integer) y debe ser clave primaria:
&&
*
%
>
&p(
%
7&
-&*9,(
%
&7&
-&*8,(
&7&
-&*D,(
/&p& *
,
,#
Hasta ahora, al ingresar registros, colocamos el nombre de todos los campos antes de
los valores; es posible ingresar valores para algunos de los campos de la tabla, pero
recuerde que al ingresar los valores debemos tener en cuenta los campos que detallamos
y el orden en que lo hacemos.
&
&
*%
(%
&(
&,
7%*/-("
&(F,#
&
&
*
(%
(%
&(
&,
7%*E(2&<&&
(H
R& (F
,#
c
c
.7
&;&/
/&
&;%pB&&
&
&&
&&;+
.7
&
%
(
p%p
%
&
(
%&;
%
p
7
&p;
+
.7
&&
(
p %&&&
%
%
+
.7
&&
7
*
p/
;)
/&
/&G
7
&/
7
,(
& +
Para que este atributo funcione correctamente, el campo debe contener solamente
valores positivos; más adelante trataremos este tema.
rá
)&p
%&)
&p
G&)&%p
p
%
p@p
p
@+
.p(?
&
/)?p
p
#
9.&
%&%
%&
&p
p
*
&%
>
&p(
p&7&
-&*9,(
&
&
7&
-&*9,(
/&
)
(
&(
/&p& *
,
,#
8.C%
&%
%&@p
p
@*
&,+
.A&
%&&
*&
,
&
p
p
*
p&(
&
&
(/&
(
,
7%*&(
-(D+9(,#
&
p
p
*
p&(
&
&
(/&
(
,
7%*"%
/(
-(+(9,#
&
p
p
*
p&(
&
&
(/&
(
,
7%*p
?D(" &(D+E(,#
D.C&)%%
p/
@
G
@&G
7
&p
%
p;
(
p&(
&
&
(/&
(
)&
pp
p
#
E.A&&%&&
%7
&
7/&p&
&/
+
6.A&%&&
%7
&
7/&p&
&/
%
&
p
p
*
(
p&(
&
&
(/&
(
,
7%*9(F&
p
D("
(+(9,#
c
c
á
á
á
*á áá áá
Aprendimos que para borrar todos los registro de una tabla se usa "delete" sin condición
"where".
También podemos eliminar todos los registros de una tabla con "truncate table". Por
ejemplo, queremos vaciar la tabla "libros", usamos:
La sentencia "truncate table" vacía la tabla (elimina todos los registros) y vuelve a crear
la tabla con la misma estructura.
La diferencia con "drop table" es que esta sentencia borra la tabla, "truncate table" la
vacía.
La diferencia con "delete" es la velocidad, es más rápido "truncate table" que "delete"
(se nota cuando la cantidad de registros es muy grande) ya que éste borra los registros
uno a uno.
rá
c
c
)&p
%&)
&p
G&)&%p
p
%
p@p
p
@+
.p(?
&
/)?p
p
#
9.&
%&%
%&
&p
p
*
&%
>
&p(
p&7&
-&*9,(
&
&
7&
-&*9,(
/&
)
(
&(
/&p& *
,
,#
8.A&
%&&
&
p
p
*
p&(
&
&
(/&
(
,
7%*&(
-(D+9(,#
&
p
p
*
p&(
&
&
(/&
(
,
7%*"%
/(
-(+(9,#
&
p
p
*
p&(
&
&
(/&
(
,
7%*p
?D(" &(D+E(,#
.p
&&
@@
)&
pp
p
#
D.A&9&&
&
p
p
*
p&(
&
&
(/&
(
,
7%*&(
-(D+9(,#
&
p
p
*
p&(
&
&
(/&
(
,
7%*p
?D(" &(D+E(,#
E.C
&&
/&7&)
&%
%G
%
&&7
&/&@
@
0)&
pp
p
#
6.C
I
&%
p
p
#
:.A&%&&
&
p
p
*
p&(
&
&
(/&
(
,
7%*"%
/(
-(+(9,#
.C
&&
/&7&)
&%
&&
G
&
G
%
+
La segunda columna "±ull" especifica si el campo permite valores nulos; vemos que en
el campo "codigo", aparece "±O" y en las demás "üES", esto significa que el primer
campo no acepta valores nulos (porque es clave primaria) y los otros si los permiten.
La tercera columna "Key", muestra los campos que son clave primaria; en el campo
"codigo" aparece "PRI" (es clave primaria) y los otros están vacíos, porque no son clave
primaria.
La cuarta columna "Default", muestra los valores por defecto, esto es, los valores que
MySQL ingresa cuando omitimos un dato o colocamos un valor inválido; para todos los
campos, excepto para el que es clave primaria, el valor por defecto es "null".
La quinta columna "Extra", muestra algunos atributos extra de los campos; el campo
"codigo" es "auto_increment".
En contraposición, tenemos campos que no pueden estar vacíos jamás, por ejemplo, los
campos que identifican cada registro, como los códigos de identificación, que son clave
primaria.
Imaginemos que ingresamos los datos de un libro, para el cual aún no hemos definido el
precio:
&
&
*%
(%
&(
&(/&
,
7%*/-("
&(F(%,#
±ote que el valor "null" no es una cadena de caracteres, no se coloca entre comillas.
Los campos establecidos como clave primaria no aceptan valores nulos. ±uestro campo
clave primaria, está definido "auto_increment"; si intentamos ingresar el valor "null"
para este campo, no lo tomará y seguirá la secuencia de incremento.
c
c
El campo "titulo", no debería aceptar valores nulos, para establecer este atributo
debemos crear la tabla con la siguiente sentencia:
&&
*
%
>
&p(
%
7&
-&*9,
%
%
&7&
-&*8,(
&7&
-&*D,(
/&
)
(
/&p& *
,
,#
Entonces, para que un campo no permita valores nulos debemos especificarlo luego de
definir el campo, agregando "not null". Por defecto, los campos permiten valores nulos,
pero podemos especificarlo igualmente agregando "null".
Explicamos que "null" no es lo mismo que una cadena vacía o un valor 0 (cero).
Para recuperar los registros que contengan el valor "null" en el campo "precio" no
podemos utilizar los operadores relacionales vistos anteriormente: = (igual) y <>
(distinto); debemos utilizar los operadores "is null" (es igual a null) y "is not null" (no es
null):
0)&
p&
-&/&
%#
0)&
p&
-&/&
L#
Con la primera sentencia veremos los libros cuyo precio es igual a "null" (desconocido);
con la segunda, los libros cuyo precio es 0.
Igualmente para campos de tipo cadena, las siguientes sentencias "select" no retornan
los mismos registros:
0)&
p&
-&
&%#
0)&
p&
-&
&L#
Con la primera sentencia veremos los libros cuya editorial es igual a "null", con la
segunda, los libros cuya editorial guarda una cadena vacía.
rá
pp@p
p
@%p
)
&p
G
/&
%
%7%)&p
+
.p(?+
9.&
%&%
%&
&p
p
*
&%
>
&p(
p&7&
-&*9,
%(
&
&
7&
-&*9,(
c
c
/&
)
(
&
%(
/&p& *
,
,#
8.C%
&%
%&@p
p
@+
.A&
%&&
&
p
p
*
p&(
&
&
(/&
(
,
7%*&
(
-(D+9( ,#
&
p
p
*
p&(
&
&
(/&
(
,
7%*&
p/%
(
-(6+(D,#
&
p
p
*
p&(
&
&
(/&
(
,
7%*"%
/(
-(%(9,#
&
p
p
*
p&(
&
&
(/&
(
,
7%*p
?D(" &(D+E(,#
&
p
p
*
p&(
&
&
(/&
(
,
7%*p
?B&(" &(9D(9,#
&
p
p
*
p&(
&
&
(/&
(
,
7%*p
?(%(9D(9,#
&
p
p
*
p&(
&
&
(/&
(
,
7%*" /&(((D,#
D.C&)%%
p/
@
@&G
7
&p
%
p;
*
,+
E.
%/&
& &
%
7
&@%@
p/
@
&
&
@(
%
%%
7
Ipp
p/
+=
%
&%
)&
0)&
pp
p
-&
&
&
%#
0)&
pp
p
-&
&
&
L#
6.
%/&
&&
%
7
&@%@
p/
@/&
@(
%
%7
&pp
p/
+=
%
&%
)&
0)&
pp
p
-&/&
%#
0)&
pp
p
-&/&
L#
:.A&&%&&
7
&@%@/&
p/
@
p&@
&
p
p
*
p&(
&
&
(/&
(
,
7%*%(" &(+9(,#
/&
%pB &&
&+
:.A&&%&&
7
&@%@/&
p/
@
@
&
p
p
*
p&(
&
&
(/&
(
,
7%*"&
p/&p
(" &(+9(%,#
/&
%pB&&
&+
.A&%&&
7
&@%@/&
p/
&&/
G
&
p
p
*
(
p&(
&
&
(/&
(
,
7%*%("&
p/&p
(" &(+9(%,#
=
p%&%pB&&
&+&
%/&p
&&
(
7&;%p
G
%7
&
%
%
&p
+
c
c
.
%/&
&&
%
/&
(%
%
@%@
0)&
pp
p
-&/&
M#
0)&
pp
p
-&/&
%#
=
%/&p&
p%&
&&
7
& p/
%7
&%
#&%
%
p%&
&&
7
&/&
p/
/&
*
%
7
&,+
/
&%
7
&@%@
/%
p/&&
/&
&&
+
.
%/&
&&
%
&
&
%
7
I(
%
%
@%@
0)&
p p
p
-&
&
&
M#
0)&
pp
p
-&
&
&
%#
=
%/&p&
&&
%
7
I(
&(
%%&%
(
p
@%@
%
(
&
&
&&
7
&%
+
&%
%
%
p%&
7
&%
(
&(
%p%&
%%&
(
%
7
I+
Los campos de tipo entero pueden tener el atributo "auto_increment", que incrementa
automáticamente el valor del campo en 1.
Los campos de cualquier tipo aceptan el atributo "null" y "not null" con lo cual permiten
o no valores nulos.
Hemos aprendido que al crear una tabla, es importante elegir el tipo de dato adecuado,
el más preciso, según el caso. Si un campo almacenará sólo valores positivos, es útil
definir dicho campo con este atributo.
c
c
En los tipos enteros, "unsigned" duplica el rango, es decir, el tipo "integer" permite
valores de -2000000000 a 2000000000 aprox., si se define "integer unsigned" el rango
va de 0 a 4000000000 aprox.
Los tipos de coma flotante (float por ejemplo) también aceptan el atributo "unsigned",
pero el valor del límite superior del rango se mantiene.
rá
&B
%p
&/I
%+
.p@/
%@(?+
9.
%&
7
&%p
&;
p/
.
&
/&&(%
&p(
.%
&
&
%(
%
(
.
&
9(
.%&
&
/
7
(
.
7/&p&
+
8.& )
p/
Q&
7
&%
p
&;
&/
%*
&%%
>
&p(
%
7&
-&*,
%(
&7&
-&*9,(
%&
&%(
/&p& *
,
,#
.C%
&%
%&+
á á
áá
á
üa explicamos que al crear una tabla debemos elegir la estructura adecuada, esto es,
definir los campos y sus tipos más precisos, según el caso. Por ejemplo, si un campo
numérico almacenará solamente valores enteros positivos el tipo "integer" con el
atributo "unsigned" es más adecuado que, por ejemplo un "float".
Hasta ahora hemos visto 3 tipos de datos: varchar, integer (con y sin signo) y float (con
y sin signo). Hay más tipos, incluso, subtipos.
A) TEXTO: Para almacenar texto usamos cadenas de caracteres. Las cadenas se colocan
entre comillas simples. Podemos almacenar dígitos con los que no se realizan
operaciones matemáticas, por ejemplo, códigos de identificación, números de
documentos, números telefónicos. Tenemos los siguientes tipos: varchar, char y text.
C) FECHAS ü HORAS: para guardar fechas y horas dispone de varios tipos: date
(fecha), datetime (fecha y hora), time (hora), year (año) y timestamp.
E) Otro valor que podemos almacenar es el valor "null". El valor 'null' significa ³valor
desconocido´ o "dato inexistente", ya lo estudiamos. ±o es lo mismo que 0 o una
cadena vacía.
á
á á
áá
á,á
üa explicamos que al crear una tabla debemos elegir la estructura adecuada, esto es,
definir los campos y sus tipos más precisos, según el caso.
Hasta ahora hemos visto 3 tipos de datos: varchar, integer (con y sin signo) y float (con
y sin signo). Hay más tipos, incluso, subtipos.
Para almacenar TEXTO usamos cadenas de caracteres. Las cadenas se colocan entre
comillas simples. Podemos almacenar dígitos con los que no se realizan operaciones
matemáticas, por ejemplo, códigos de identificación, números de documentos, números
telefónicos. Tenemos los siguientes tipos:
Ocupa tantos bytes como se definen con el argumento "x". Si ingresa un argumento
mayor al permitido (255) aparece un mensaje indicando que no se permite y sugiriendo
que use "blob" o "text". Si omite el argumento, coloca 1 por defecto.
Para los tipos que almacenan cadenas, si asignamos una cadena de caracteres de mayor
longitud que la permitida o definida, la cadena se corta. Por ejemplo, si definimos un
campo de tipo varchar(10) y le asignamos la cadena 'Buenas tardes', se almacenará
'Buenas tar' ajustándose a la longitud de 10.
c
c
Es importante elegir el tipo de dato adecuado según el caso, el más preciso. Por
ejemplo, si vamos a almacenar un caracter, conviene usar char(1), que ocupa 1 byte y no
varchar(1), que ocupa 2 bytes.
/
" p
p
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-&*?, ?
7&
-&*?, ?S
rá
& %
7%
%
p
%
%p@%
@+
.p@%
@?+
9.&
%&%
%&
&%
*
/
-&*E,(
p&
7&
-&*9,(
p
-&*,(
/&
)
%(
/&p& */,
,#
8.A&
%&&
&
%
*/(p&
(p
(/&
,
7%*!98(<9:(6(D,#
&
%
*/(p&
(p
(/&
,
7%*P98(%((,#
&
%
*/(p&
(p
(/&
,
7%*"!888(F%
DD((:,#
&
%
*/(p&
(p
(/&
,
7%*P!98(%
((6,#
&
%
*/(p&
(p
(/&
,
7%*"888(%2(:(D,#
&
%
*/(p&
(p
(/&
,
7%*"C<D8(<9:(6D(9,#
Rp
)
p/
@/@/
@
-&@
@7&
-&@/
&%
&
&
p/&&;pp
%*E
&
&,(
)
G
%/p
E (
-%Jp
)
p
@7&
-&*E,@
%/&I6 +3
pp
%
p/
@p
@(
%p
&p
N
(
p
&
&)B
+F&
p/
@/&
@)p
%
)
/
&%
7
&%
&;7
+
.
%
N
0)&
p%
-&p
L#
D.
%
/&
%/&
&D
0)&
p%
-&/&
D#
Xá á
áá
á+
á
c
c
Hasta ahora hemos visto 2 tipos de datos para almacenar valores numéricos: integer
(con y sin signo) y float (con y sin signo). Existe variedad de tipos numéricos para
representar enteros, negativos, decimales.
Para almacenar valores enteros, por ejemplo, en campos que hacen referencia a
cantidades, precios, etc., usamos: 1) integer(x) o int(x): su rango es de -2000000000 a
2000000000 aprox. El tipo "int unsigned" va de 0 a 4000000000. El tipo "integer" tiene
subtipos:
- tinyint(x): define un valor entero pequeño, cuyo rango es de -128 a 127. El tipo sin
signo va de 0 a 255.
- bool o boolean: sinónimos de tinyint(1). Un valor cero se considera falso, los valores
distintos de cero, verdadero.
Todos los tipos enteros pueden tener el atributo "unsigned", esto permite sólo valores
positivos y duplica el rango. Los tipos de coma flotante también aceptan el atributo
"unsigned", pero el valor del límite superior del rango no se modifica.
Es importante elegir el tipo de dato adecuado según el caso, el más preciso. Por
ejemplo, si un campo numérico almacenará valores positivos menores a 10000, el tipo
"int" no es el más adecuado, porque su rango va de -2000000000 a 2000000000 aprox.,
conviene el tipo "smallint unsigned", cuyo rango va de 0 a 60000 aprox. De esta manera
usamos el menor espacio de almacenamiento posible.
/
" p
p
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
p 9
p%p 8
:
)
p*(, S9(SL S9M
c
c
á
á
rá
&
/)?&
#
&&
*
%%
>
&p(
%
7&
-&*9,
%(
%
&7&
-&*8,(
&7&
-&*D,(
/&
p*D(9,%(
p%(
/&p& *
,
,#
±ote que definimos el campo "cantidad" de tipo "smallint unsigned", esto es porque los
valores para este campo serán siempre positivos (mayores o iguales a 0), además la
cantidad disponible no superará los 60000 aprox., así que no es adecuado usar int (cuyo
rango llega hasta 4000 millones aprox.), así ocupamos menos espacio (3 bytes para
mediumint contra 4 bytes para int). Es importante elegir el tipo de dato más preciso.
á á
áá
á!
áá
á
Para guardar fechas y horas dispone de varios tipos:
Si ingresamos los valores como cadenas, un valor entre "00" y "69" es convertido a
valores "year" en el rango de 2000 a 2069; si el valor está entre "70" y "99", se
convierten a valores "year" en el rango 1970 a 1999.
c
c
Para almacenar valores de tipo fecha se permiten como separadores "/", "-" y ".".
Si ingresamos '2006-12-31 11:30:21' (valor date time) en un campo 'date', toma sólo la
parte de la fecha, la hora se corta, se guarda '2006-12-31'.
Es importante elegir el tipo de dato adecuado según el caso, el más preciso. Por
ejemplo, si sólo necesitamos registrar un año (sin día ni mes), el tipo adecuado es "year"
y no "date".
/
" p
p
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>
8
p :
p 8
&
á
rá
Una playa de estacionamiento guarda cada día los datos de los vehículos que ingresan a
la playa en una tabla llamada "vehiculos".
&
/)?7-
%
#
&7-
%
*
/
-&*E,
%(
/
-&*,(
-
&p
%(
c
c
-
&p
,#
&
7-
%
*/(/
(-
&,7%
*!98( %
(:8,#
&
7-
%
*/(/
(-
&,
7%*"P<98(p
(:8D,#
&
7-
%
*/(/
(-
&,
7%*'AE6(%
(,#
0)&
p7-
%
#
±ote que no ingresamos los segundos y colocó por defecto "00" para ellos.
%/7-
%
-
&LD
-&/L!98#
&
7-
%
7%*3A:6(%
((%,#
0)&
p7-
%
#
&
7-
%
7%*P :6(%
((%,#
&
7-
%
7%*R 98(%
(9E .9.D
9D(%,#
c
c
&
7-
%
7%*'59E(%
(9TD(%,#
almacena "00:00:15".
á
A'á á*
áá! á
Hemos visto los valores por defecto de los distintos tipos de datos. Ahora que
conocemos más tipos de datos, vamos a ampliar la información referente a ellos y a
repasar los conocidos.
Para campos de cualquier tipo no declarados "not null" el valor por defecto es "null"
(excepto para tipos "timestamp" que no trataremos aquí).
Para campos declarados "not null", el valor por defecto depende del tipo de dato. Para
cadenas de caracteres el valor por defecto es una cadena vacía. Para valores numéricos
el valor por defecto es 0; en caso de ser "auto_increment" es el valor mayor existente+1
comenzando en 1. Para campos de tipo fecha y hora, el valor por defecto es 0 (por
ejemplo, en un campo "date" es "0000-00-00").
Para todos los tipos, excepto "blob", "text" y "auto_increment" se pueden explicitar
valores por defecto con la cláusula "default"; tema que veremos más adelante.
Los campos para los cuales no se ingresaron valores tomarán los valores por defecto
según el tipo de dato del campo, en el campo "codigo" ingresará el siguiente valor de la
secuencia porque es "auto_increment"; en el campo "titulo", ingresará una cadena vacía
porque es "varchar not null"; en el campo "editorial" almacenará "null", porque no está
definido "not null"; en el campo "precio" guardará "null" porque es el valor por defecto
de los campos no definidos como "not null" y en el campo "cantidad" ingresará 0
porque es el valor por defecto de los campos numéricos que no admiten valores nulos.
/
C
&/
&)
;%%@)%@
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
&
&
%
7
I
/&p
%p&
%
/&p
c
c
)
-
% ..
/&p
-
&
%
/&p
%
>
&p %
+(p/
/&p
&
+(%p&+()
-(-
&% %
Aá á*
á
á
Hemos visto los valores por defecto de los distintos tipos de datos.
Un valor es inválido por tener un tipo de dato incorrecto para el campo o por estar fuera
de rango.
-cadenas: si en un campo numérico ingresamos una cadena, lo pasa por alto y coloca 0.
Por ejemplo, si en un campo de tipo "integer" guardamos 'abc', almacenará 0.
- Pasa por alto los valores fuera del rango, 0 en caso de no ser "unsigned" y todos los
menores a 1 en caso de ser "unsigned".
-valor "null": si un campo está definido "not null" e intentamos ingresar "null", aparece
un mensaje de error y la sentencia no se ejecuta.
Los valores inválidos para otros tipos de campos lo trataremos más adelante.
2=
/
C
&7;
%
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>
&
&%T
% 98 98
&
&%T
% p
&
%
&
&
% % &&
&
%pJ&
%T
% 98
%pJ&
%T
% )%&&
Ip
%pJ&
% % &&
&
%pJ&
p%T
% p;
p%
)
&
p;
&
%p+%
>
&+
T
%T
% %
%p+%
>
&+T
%T
%
p
& %
%p+%
>
&+
T
% % %
%p+%
>
&+
T
%T
% 7
&? &&
&
)
- )%&&
..
)
- 9.6.9E*
&
&, ..
-
& )%&&
Ipp;
)
- -
&
% % &&
&
c
c
AAá á-
á!ááá áá
áá
Si al insertar registros no se especifica un valor para un campo, se inserta su valor por
defecto implícito según el tipo de dato del campo. Por ejemplo:
&
&
*%
(%
&(
&(/&
(
,
7%*H7p%
(H%F& &(F
(9D+6(,#
Como no ingresamos valor para el campo "codigo", MySQL insertará el valor por
defecto, como "codigo" es un campo "auto_increment", el valor por defecto es el
siguiente de la secuencia.
&
&
*%
(
&(/&
(
,
7%*H7p%
(F
(9D+6(9,#
MySQL insertará "null", porque el valor por defecto de un campo (de cualquier tipo)
que acepta valores nulos, es "null".
&
&
*%
(%
&(
&(
,
7%*H7p%
(H%F& &(F
(D,#
MySQL insertará el valor "null" porque el valor por defecto de un campo (de cualquier
tipo) que acepta valores nulos, es "null".
&
&
*%
&(
&(/&
(
,
7%*"
&(F
(9D+6(9,#
MySQL guardará una cadena vacía, ya que éste es el valor por defecto de un campo de
tipo cadena definido como "not null" (no acepta valores nulos).
&
&
*%
(%
&(
&(/&
,
7%*
&7/B
(3&&
(p
(8+D,#
el valor que se almacenará será 0, porque el campo "precio" es de tipo numérico "not
null" y el valor por defecto de los tipos numéricos que no aceptan valores nulos es 0.
Podemos establecer valores por defecto para los campos cuando creamos la tabla. Para
ello utilizamos "default" al definir el campo. Por ejemplo, queremos que el valor por
defecto del campo "precio" sea 1.11 y el valor por defecto del campo "autor" sea
"Desconocido":
Si al ingresar un nuevo registro omitimos los valores para el campo "autor" y "precio",
MySQL insertará los valores por defecto definidos con la palabra clave "default":
&
&
*%
(
&(
,
7%*H7p%
(F
(9,#
-para campos de cualquier tipo que admiten valores nulos, el valor por defecto "null";
-para campos que no admiten valores nulos, es decir, definidos "not null", el valor por
defecto depende del tipo de dato:
"Field" contiene el nombre del campo; "Type", el tipo de dato; "±ULL" indica si el
campo admite valores nulos; "Key" indica si el campo está indexado (lo veremos más
adelante); "Default" muestra el valor por defecto del campo y "Extra" muestra
información adicional respecto al campo, por ejemplo, aquí indica que "codigo" está
definido "auto_increment".
También se puede utilizar "default" para dar el valor por defecto a los campos en
sentencias "insert", por ejemplo:
&
&
*%
(%
&(/&
(
,
7%*
()%()%(,#
rá
p&
%7I/ p/
p
&&
/
&p%
p@/
@
%
.%p&
/
(%
&p(&
/
7
p
p
&9/&
?+
.
p&/
p/(/
&)
@p/@(
./
/
&Bp/
(/ /
(p% &(
+(
p/&(/
(BpG
%
(
&
(
+
./&
/&
/
&%(7
&
p%
%/&
O+ &;p/&p
&
(/
&)
@@(
.
&
%
(&
/
7
)&
&
9/&
?+(/
&
)
@9@
.
p
+
.p@/
@?+
9.&
/
%
/&
p/
+
8.A&
%&&
&
/
*
p&(/
(/&
(
(
p
,
7%*/ (p % &(+(8(&p
98D,#
&
/
*/
(/&
(
(
p
,
7%*&(+(9(&% 9E,#
&
/
*
p&(/
(
p
,
7%*p/(N(
8,#
&
/
*/
(
p
,
7%*&(2&,#
&
/
*
p&(/
(/&
(
p
,
7%*/ (/
(+(78D,#
.2%&
p/
/
/&7&
Gp
%&&
&
+
c
c
A*á á-
á.!
ááá áá
áá
Cualquier campo numérico puede tener otro atributo extra "zerofill".
Por ejemplo, creamos la tabla "libros", definiendo los campos "codigo" y "cantidad" con
el atributo "zerofill":
&&
*
*E, &
)%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*8,(
&7&
-&*D,(
/&
p*D(9,%(
p &
)(
/&p& *
,
,#
±ote que especificamos el tamaño del tipo "int" entre paréntesis para que muestre por la
izquierda ceros, cuando los valores son inferiores al indicado; dicho parámetro no
restringe el rango de valores que se pueden almacenar ni el número de digitos.
Al ingresar un valor de código con menos cifras que las especificadas (6), aparecerán
ceros a la izquierda rellenando los espacios; por ejemplo, si ingresamos "33", aparecerá
"000033". Al ingresar un valor para el campo "cantidad", sucederá lo mismo.
Si queremos ver los títulos, precio y cantidad de cada libro escribimos la siguiente
sentencia:
c
c
Si queremos saber el precio de cada libro con un 10% de descuento podemos incluir en
la sentencia los siguientes cálculos:
&
/)?&
#
Creamos la tabla:
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*8,(
&7&
-&*D,(
/&
p*D(9,%(
p%(
/&p& *
,
,#
&
&
*%
(%
&(
&(/&
(
,
7%*/-("
&(F(D(,#
&
&
*%
(%
&(
&(/&
(
,
7%*2&<&&
(H
R& (p
(99+9(9,#
&
&
*%
(%
&(
&(/&
(
,
7%*
/
("
&(F((D,#
&
&
*%
(%
&(
&(/&
(
,
7%*/&FRF(2&
2
(p
(:+9(9,#
&
&
*%
(%
&(
&(/&
(
,
7%*&7 %B
("
&(F
(8E+(,#
&
&
*%
(%
&(
&(/&
(
,
7%*2%FRF(H++F (F
(8+:(,#
&
&
*%
(%
&(
&(/&
(
,
7%*R&& F
& /&)
)(H+'+
(F
(D+(D,#
&
&
*%
(%
&(
&(/&
(
,
7%*R&& F
&
p&
&(H+'+
(F
(E+(8,#
&
&
*%
(%
&(
&(/&
(
,
7%*
/p&7(3
&&
(F
(%(D,#
Para obtener el monto total en dinero de un título podemos multiplicar el precio por la
cantidad, por cada título, MySQL realiza el cálculo y lo incluye en una columna extra
en la salida:
)&
p&
#
Para saber el precio de cada libro con un 10% de descuento podemos incluir en la
sentencia los siguientes cálculos:
á
Aùá á/
ááá0áá
á
RECUERDE que ±O debe haber espacios entre un nombre de función y los paréntesis
porque MySQL puede confundir una llamada a una función con una referencia a una
tabla o campo que tenga el mismo nombre de una función.
MySQL tiene algunas funciones para trabajar con cadenas de caracteres. Estas son
algunas:
&*,#
retorna 65.
-char(x,..): retorna una cadena con los caracteres en código ASCII de los enteros
enviados como argumentos. Ejemplo:
-&*ED(EE(E6,#
retorna "ABC".
*R
(((
p
U,#
>* .(H%(F&
(3%,#
c
c
retorna "Juan-Pedro-Luis".
devuelve 4.
*
(
p
7,#
retorna 2.
/
*
p
7,#
retorna 2.
*&(2&& (,#
retorna 1.
*&(2&&(8,#
retorna 5.
&*
p
7(
p,#
c
c
devuelve 2.
/*-
((,#
retorna "000000hola".
)*%
(:,#
retorna "enas".
retorna "enas".
retorna "garita".
retorna "garita".
retorna
@R
@
.
retorna
@R
@
.
retorna 'Hola'.
retorna "hola00".
retorna "00hola".
retorna "hola".
retorna "hola".
retorna "hola".
retorna "www.mysql.com'.
&/*-
(8,#
retorna "holaholahola".
&7&*R
,#
retorna "aloH".
&*%&(9(E(??,#
retorna ""bxxtardes".
&*R3 !A,#
c
c
retorna 1
rá
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*8,(
&7&
-&*9,(
/&
p*D(9,%(
/&p& *
,
,#
&
&
*%
(%
&(
&(/&
,
7%*-/("
&(F
(88+,#
&
&
*%
(%
&(
&(/&
,
7%*
/p&7(3+
&&
(F(E,#
>* .(%
(%
&,
)&
p&
#
c
c
la salida muestra una sola columna en la cual se concatenan, con el separador "-", los
distintos campos especificados.
&*%
,(%//&*
&,
)&
p&
#
Aá á/
á
á
Los operadores aritméticos son "+","-","*" y "/". Todas las operaciones matemáticas
retornan "null" en caso de error. Ejemplo:
DT#
MySQL tiene algunas funciones para trabajar con números. Aquí presentamos algunas.
RECUERDE que ±O debe haber espacios entre un nombre de función y los paréntesis
porque MySQL puede confundir una llamada a una función con una referencia a una
tabla o campo que tenga el mismo nombre de una función.
retorna 20.
*9+8,(
retorna 13.
)
&*9+8,#
c
c
retorna 12.
p
*(8,#
retorna 1.
p
*(9,#
retorna 0.
V8#
retorna 1.
V9#
retorna 0.
/
&*9(8,#
retorna 8.
-rand(): retorna un valor de coma flotante aleatorio dentro del rango 0 a 1.0.
&
%*9+8,#
retorna 12.
&
%*9+E,#
retorna 13.
retorna 123.45;
retorna 123.
á
rá
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*8,(
&7&
-&*9,(
/&
p*D(9,%(
/&p& *
,
,#
&
&
*%
(%
&(
&(/&
,
7%*-/("
&(F
(88+,#
&
&
*%
(%
&(
&(/&
,
7%*
/p&7(3+
&&
(F(E+8,#
&
&
*%
(%
&(
&(/&
,
7%*
&7 /B
(3+&&
(F(:+:,#
&*/&
,
)&
p&
#
%
(&%
*/&
(,
)&
p&
c
c
Aá á/
ááá
áá! áá
á
MySQL tiene algunas funciones para trabajar con fechas y horas. Estas son algunas:
-dayofmonth(fecha): retorna el día del mes para la fecha dada, dentro del rango 1 a 31.
Ejemplo: dayofmonth('2006-08-10') retorna 10.
-dayofweek(fecha): retorna el índice del día de semana para la fecha pasada como
argumento. Los valores de los índices son: 1=domingo, 2=lunes,... 7=sábado). Ejemplo:
dayofweek('2006-08-10') retorna 5, o sea jueves.
-dayofyear(fecha): retorna el día del año para la fecha dada, dentro del rango 1 a 366.
Ejemplo: dayofmonth('2006-08-10') retorna 222.
Ejemplos:
?&
* &)&
p9 E..,(&
&@9E@+
?&
* &>p
-)&
p9E ..D9D,&
&@9E@+
?&
* >p%)&
p9E ..D9D,&
&@D@#
Los valores para tipo pueden ser: second, minute, hour, day, month, year,
minute_second, hour_minute, day_hour, year_month, hour_second (horas, minutos y
segundos), day_minute (días, horas y minutos), day_second (días a segundos).
-to_days(fecha): retorna el número de día (el número de día desde el año 0).
-weekday(fecha): retorna el índice del día de la semana para la fecha pasada como
argumento. Los índices son: 0=lunes, 1=martes,... 6=domingo). Ejemplo:
weekday('2006-08-10') retorna 3, o sea jueves.
á
rá
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:
.I%
&
(
.
%p
%/& &
(
.)
-/&Jp
(
.)
-7
%
G&
(
.7%
&
-
7%
+
&
/)?/&p
#
Creamos la tabla:
&/&p
*
%
7&
-&*,
%(
%p
-&*:,
%(
)
-/&p
%(
)
-7
%
(
7%
-&*,)%
,#
Ingresamos un registro con los 3 primeros datos y calculamos con una función la fecha
de devolución:
&
/&p
*%
(
%p
()
-F&p
()
-!7
%
,7%
*2%&
(98DE6:(9E .:.(>*9E .:.(
&7D ,,#
Con un "select" vemos cómo quedó almacenado el registro ingresado anteriormente:
0)&
p/&p
#
&
/&p
*%
(
%p
()
-F&p
()
-!7
%
,
7%*
/p&7(98DE6:(
9E.:.9(>*9E .:.9(&7D ,,#
&
/&p
*%
(
%p
()
-F&p
()
-!7
%
,7%
*/-(99D8:6(9E .:.D(>*9E .:.D(&7
D ,,#
&
/&p
*%
(
%p
()
-F&p
()
-!7
%
,
7%*2%
&)D&
(9DDDDEEE(9E .:.8(
>*9E .:.8(&7D ,,#
c
c
&
/&p
*%
(
%p
()
-F&p
()
-!7
%
,7%
*%7&(9(
%&&>(>*
%&&>(
&7D ,,#
Por ejemplo, recuperamos los registros de la tabla "libros" ordenados por el título:
(%
(%
&(
&(/&
)&
p&
&&
%
#
También podemos colocar el número de orden del campo por el que queremos que se
ordene en lugar de su nombre. Por ejemplo, queremos el resultado del "select" ordenado
por "precio":
(%
(%
&(
&(/&
)&
p&
&& D#
Por defecto, si no aclaramos en la sentencia, los ordena de manera ascendente (de menor
a mayor). Podemos ordenarlos de mayor a menor, para ello agregamos la palabra clave
"desc":
(%
(%
&(
&(/&
)&
p&
&&
&
#
También podemos ordenar por varios campos, por ejemplo, por "titulo" y "editorial":
(%
(%
&(
&(/&
)&
p&
&&
%
(
&#
Incluso, podemos ordenar en distintos sentidos, por ejemplo, por "titulo" en sentido
ascendente y "editorial" en sentido descendente:
(%
(%
&(
&(/&
)&
p&
&& %
(
&
#
c
c
Debe aclararse al lado de cada campo, pues estas palabras claves afectan al campo
inmediatamente anterior
rá
&
/)?&
#
&&
*
%%
>
&p(
%
7&
-&*,(
%
&7&
-&*8,(
&7&
-&*D,(
/&
p*D(9,%(
/&p& *
,
,#
Visualizamos su estructura:
&
&
*%
(%
&(
&(/&
,
7%*/-("
&(F(D+D,#
&
&
*%
(%
&(
&(/&
,
7%*2&<&&
(H
R& (p
(99+,#
&
&
*%
(%
&(
&(/&
,
7%*2&<&&
(H
R& (F(8,#
&
&
*%
(%
&(
&(/&
,
7%*/&FRF(2&
2
(p
(+D,#
&
&
*%
(%
&(
&(/&
,
7%*&7 %B
("
&(F
(8D+,#
&
&
*%
(%
&(
&(/&
,
7%*2p
-(F (F
(,#
(%
(%
&(
&(/&
)&
p&
&& %
#
(%
(%
&(
&(/&
)&
p&
&& D#
c
c
(%
(%
&(
&(/&
)&
p&
&& %
(
&#
(%
(%
&(
&(/&
)&
p&
&& %
(
&
#
Aá á"
á1
áá áá áá
Hasta el momento, hemos aprendido a establer una condición con "where" utilizando
operadores relacionales. Podemos establecer más de una condición con la cláusula
"where", para ello aprenderemos los operadores lógicos.
.()
@ @(
.
&()
@ T
@(
.?
&()
@
@(
.
()
@
@(7&&%
.*,(/&J
Queremos recuperar todos los registros cuyo autor sea igual a "Borges" y cuyo precio
no supere los 20 pesos, para ello necesitamos 2 condiciones:
0)&
p&
-&*%
&L"
&,
*/&
ML9,#
Los registros recuperados en una sentencia que une 2 condiciones con el operador
"and", cumplen con las 2 condiciones.
Queremos ver los libros cuyo autor sea "Borges" y/o cuya editorial sea "Planeta":
0)&
p&
-&%
&L"
&
&
&LF#
En la sentencia anterior usamos el operador "or", indicamos que recupere los libros en
los cuales el valor del campo "autor" sea "Borges" y/o el valor del campo "editorial" sea
"Planeta", es decir, seleccionará los registros que cumplan con la primera condición,
con la segunda condición o con ambas condiciones.
c
c
Los registros recuperados con una sentencia que une 2 condiciones con el operador "or",
cumplen 1 de las condiciones o ambas.
Queremos ver los libros cuyo autor sea "Borges" o cuya editorial sea "Planeta":
0)&
p&
-&*%
&L"
&,?
&
*
&LF,#
En la sentencia anterior usamos el operador "xor", indicamos que recupere los libros en
los cuales el valor del campo "autor" sea "Borges" o el valor del campo "editorial" sea
"Planeta", es decir, seleccionará los registros que cumplan con la primera condición o
con la segunda condición pero no los que cumplan con ambas condiciones. Los
registros recuperados con una sentencia que une 2 condiciones con el operador "xor",
cumplen 1 de las condiciones, no ambas.
Queremos recuperar los libros que no cumplan la condición dada, por ejemplo, aquellos
cuya editorial ±O sea "Planeta":
0)&
p&
-&
*
&LF,#
Los paréntesis se usan para encerrar condiciones, para que se evalúen como una sola
expresión.
0)&
p&
-&*%
&L"
&,
&
*
&LF
/&
M9,#
0)&
p&
-&*%
&L"
&
&
&LF
,
*/&
M9,#
Si bien los paréntesis no son obligatorios en todos los casos, se recomienda utilizarlos
para evitar confusiones.
El orden de prioridad de los operadores lógicos es el siguiente: "not" se aplica antes que
"and" y "and" antes que "or", si no se especifica un orden de evaluación mediante el uso
de paréntesis.
c
c
= (igual), <> (distinto), > (mayor), < (menor), >= (mayor o igual), <= (menor o igual),
is null/is not null (si un valor es ±ULL o no).
Para recuperar de nuestra tabla "libros" los registros que tienen precio mayor o igual a
20 y menor o igual a 40, usamos 2 condiciones unidas por el operador lógico "and":
0)&
p&
-&/&
L9/&
ML#
0)&
p&
-&/&
9#
Para recuperar los libros cuyo autor sea 'Paenza' o 'Borges' usamos 2 condiciones:
0)&
p&
-&%
&L"
&
&%
&LF #
0)&
p&
-&%
&*"
&(F ,#
Con "in" averiguamos si el valor de un campo dado (autor) está incluido en la lista de
valores especificada (en este caso, 2 cadenas).
Para recuperar los libros cuyo autor no sea 'Paenza' ni 'Borges' usamos:
0)&
p&
-&%
&M"
&%
&MF #
0)&
p&
-&%
&
*"
&(F ,#
c
c
Con "in" averiguamos si el valor del campo está incluido en la lista, con "not"
antecediendo la condición, invertimos el resultado.
0)&
p&
-&%
&L"
&#
/-"
&#
/
H+3+"
&#
Si queremos recuperar todos los libros cuyo autor sea "Borges", y especificamos la
siguiente condición:
0)&
p&
-&%
&L"
&#
sólo aparecerá el primer registro, ya que la cadena "Borges" no es igual a la cadena "J.L.
Borges".
Esto sucede porque el operador "=" (igual), también el operador "<>" (distinto)
comparan cadenas de caracteres completas. Para comparar porciones de cadenas
utilizamos los operadores "like" y "not like".
0)&
p&
-&%
&@V"
&V@#
0)&
p&
c
c
-&%
V#
±ote que el símbolo "%" ya no está al comienzo, con esto indicamos que el título debe
tener como primera letra la "A" y luego, cualquier cantidad de caracteres.
0)&
p&
-&%
V#
Así como "%" reemplaza cualquier cantidad de caracteres, el guión bajo "_" reemplaza
un caracter, es el otro caracter comodín. Por ejemplo, queremos ver los libros de "Lewis
Carroll" pero no recordamos si se escribe "Carroll" o "Carrolt", entonces tipeamos esta
condición:
0)&
p&
-&%
&@V&&
>@#
rá
&&
*
%%
>
&p(
%
7&
-&*,(
%
&7&
-&*8,(
&7&
-&*D,(
/&
p*D(9,%(
/&p& *
,
,#
&
&
*%
(%
&(
&(/&
,
7%*/-("
&(F(D+D,#
&
&
*%
(%
&(
&(/&
,
7%*2&<&&
(H
R& (p
(99+,#
&
&
*%
(%
&(
&(/&
,
c
c
7%*
/
(H+3+"
&(F(8,#
&
&
*%
(%
&(
&(/&
,
7%*/&FRF(2&
2
(p
(+D,#
&
&
*%
(%
&(
&(/&
,
7%*&7 %B
("
& .H+3+
"
&(F
(8D+,#
&
&
*%
(%
&(
&(/&
,
7%*2%FRF(H++F (F
(,#
&
&
*%
(%
&(
&(/&
,
7%*R&& F
& /&)
)(H+'+
(F
(D+,#
&
&
*%
(%
&(
&(/&
,
7%*R&& F
&
p&
&(H+'+
(F
(E+,#
&
&
*%
(%
&(
&(/&
,
7%*
/p&7(3
&&
(F
(8E+,#
0)&
p&
-&%
&L"
&#
0)&
p&
-&%
&V"
&V#
0)&
p&
-&%
V#
0)&
p&
-&%
V#
0)&
p&
-&%
&V&&
>#
0)&
p&
-&%
VR&& F
&V#
0)&
p&
-&%
VFRFV#
Para buscar los autores que tienen al menos una "h" o una "k" o una "w" tipeamos:
%
&)&
p&
-&%
&&?/W-X#
Para buscar los autores que no tienen ni "h" o una "k" o una "w" tipeamos:
%
&)&
p&
-&%
&
&?/W-X#
Para buscar los autores que tienen por lo menos una de las letras de la "a" hasta la "d",
es decir, "a,b,c,d", usamos:
%
&)&
p&
-&%
&&?/W .X#
Para buscar títulos que contengan una "a" luego un caracter cualquiera y luego una "e"
utilizamos la siguiente sentencia:
Podemos mostrar los títulos que contienen una "a" seguida de 2 caracteres y luego una
"e":
-&%
&?/++#
%
&)&
p&
-&%
&&?/Y++++++O#
%
&)&
p&
-&%
&&?/++++++#
**á áá
á á
Existen en MySQL funciones que nos permiten contar registros, calcular sumas,
promedios, obtener valores máximos y mínimos. Veamos algunas de ellas.
Imaginemos que nuestra tabla "libros" contiene muchos registros. Para averiguar la
cantidad sin necesidad de contarlos manualmente usamos la función "count()":
%*0,)&
p&
#
La función "count()" cuenta la cantidad de registros de una tabla, incluyendo los que
tienen valor nulo.
%*0,)&
p&
-&
&LF#
También podemos utilizar esta función junto con la clausula "where" para una consulta
más específica. Por ejemplo, solicitamos la cantidad de libros que contienen la cadena
"Borges":
%*0,)&
p&
-&%
&V"
&V#
Para contar los registros que tienen precio (sin tener en cuenta los que tienen valor
nulo), usamos la función "count()" y en los paréntesis colocamos el nombre del campo
que necesitamos contar:
%*/&
,)&
p&
#
c
c
±ote que "count(*)" retorna la cantidad de registros de una tabla (incluyendo los que
tienen valor "null") mientras que "count(precio)" retorna la cantidad de registros en los
cuales el campo "precio" no es nulo. ±o es lo mismo. "count(*)" cuenta registros, si en
lugar de un asterisco colocamos como argumento el nombre de un campo, se
contabilizan los registros cuyo valor en ese campo no es nulo.
%*0,)&
p&
#
%*0,)&
p&
#
*)á á/
áá
á á á
,á á
á á
á áá
Existen en MySQL funciones que nos permiten contar registros, calcular sumas,
promedios, obtener valores máximos y mínimos. üa hemos aprendido "count()",
veamos otras.
La función "sum()" retorna la suma de los valores que contiene el campo especificado.
Por ejemplo, queremos saber la cantidad de libros que tenemos disponibles para la
venta:
También podemos combinarla con "where". Por ejemplo, queremos saber cuántos libros
tenemos de la editorial "Planeta":
Para averiguar el valor máximo o mínimo de un campo usamos las funciones "max()" y
"min()" respectivamente. Ejemplo, queremos saber cuál es el mayor precio de todos los
libros:
p?*/&
,)&
p&
#
La función avg() retorna el valor promedio de los valores del campo especificado. Por
ejemplo, queremos saber el promedio del precio de los libros referentes a "PHP":
%*0,)&
p &
#
%*0,)&
p&
#
rá
Trabajamos con la tabla "libros" que registra la información de los libros que vende una
librería.
&
/)?&
#
Creamos la tabla:
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*8,(
&7&
-&*D,(
/&
p*D(9,%(
p%p%(
/&p& *
,
,#
&
&
*%
(%
&(
&(/&
(
,
7%*/-("
&(F(D(,#
&
&
*%
(%
&(
&(/&
(
,
7%*2&<&&
(H
R& (p
(99+9(9,#
&
&
*%
(%
&(
&(/&
(
,
7%*
/
(H+3+"
&(F((D,#
&
&
*%
(%
&(
&(/&
(
,
7%*/&FRF(2&
2
(p
(:+9(9,#
&
&
*%
(%
&(
&(/&
(
,
7%*&7 %B
("
& .H+3+
"
&(F
(8E+(,#
&
&
*%
(%
&(
&(/&
(
,
7%*2%FRF(H++F (F
(8+:(9,#
&
&
*%
(%
&(
&(/&
(
,
7%*R&& F
& /&)
)(H+'+
(F
(D+(D,#
&
&
*%
(%
&(
&(/&
(
,
7%*R&& F
&
p&
&(H+'+
(F
(E+(,#
c
c
&
&
*%
(%
&(
&(/&
(
,
7%*
/p&7(3
&&
(F
(%(9,#
Para conocer la suma de las cantidades de libros que tenemos disponibles tipeamos:
Retorna 1220; verifique la suma, sumando los valores de todos los registros del campo
"cantidad".
Retorna 250; verifique el total sumando las cantidades de los libros cuya editorial sea
"Planeta".
p?*/&
,)&
p&
#
Devuelve 46.
0)&
p&
&& /&
#
Retorna 45.
0)&
p&
-&%
&V
V
&& D#
Solicitamos el promedio del precio de los libros que tratan sobre "PHP":
Retorna 24.50...
c
c
0)&
p&
-&%
VFRFV#
%*0,)&
p&
#
%*0,)&
p&
#
*ùá á-á
ááá
Hemos aprendido que las funciones de agrupamiento permiten contar registros, calcular
sumas y promedios, obtener valores máximos y mínimos. También dijimos que dichas
funciones operan sobre conjuntos de registros, no con datos individuales.
Generalmente esta funciones se combinan con la sentencia "group by", que agrupa
registros para consultas detalladas.
%*0,)&
p7
-&
%L
&
#
%*0,)&
p7
-&
%LP&
#
%*0,)&
p7
-&
%LC!
&#
+++
%(
%*0,
)&
p7
&
%/
%#
Entonces, para saber la cantidad de visitantes que tenemos en cada ciudad utilizamos la
función "count()", agregamos "group by" y el campo por el que deseamos que se realice
el agrupamiento, también colocamos el nombre del campo a recuperar.
Para obtener la cantidad visitantes con teléfono no nulo, de cada ciudad utilizamos la
función "count()" enviándole como argumento el campo "telefono", agregamos "group
by" y el campo por el que deseamos que se realice el agrupamiento (ciudad):
%(
%*)
,
)&
p7
&
%/
%#
Como resultado aparecen los nombres de las ciudades y la cantidad de registros de cada
una, sin contar los que tienen teléfono nulo. Recuerde la diferencia de los valores que
retorna la función "count()" cuando enviamos como argumento un asterisco o el nombre
de un campo: en el primer caso cuenta todos los registros incluyendo los que tienen
valor nulo, en el segundo, los registros en los cuales el campo especificado es no nulo.
?
(%p*p
p/&,
)&
p7
&
%/ ?
#
?
(p?*p
p/&,)&
p7
&
%/ ?
#
?
(p*p
p/&,)&
p7
&
%/ ?
#
Se pueden simplificar las 2 sentencias anteriores en una sola sentencia, ya que usan el
mismo "group by":
?
(p?*p
p/&,(
p*p
p/&,
)&
p7
&
%/ ?
#
%(7*p
p/&,)&
p7
&
%/
%#
Podemos agrupar por más de un campo, por ejemplo, vamos a hacerlo por "ciudad" y
"sexo":
%(?
(
%*0, )&
p7
&
%/
%(?
#
%(
%*0,)&
p7
-&
%M
&
&
%/
%#
c
c
Podemos usar las palabras claves "asc" y "desc" para una salida ordenada:
%(
%*0,)&
p7
&
%/
%
#
rá
Un comercio que tiene un stand en una feria registra en una tabla llamada "visitantes"
algunos datos de las personas que visitan o compran en su stand para luego enviarle
publicidad de sus productos.
&
/)?7#
Creamos la tabla:
&7*
p&7&
-&*8,(
%(
?
-&*,(
p
7&
-&*8,(
%7&
-&*9,(
)
7&
-&*,(
p
p/&
p*E(9,%
,#
&
7*
p&((
?
(
p
(
%()
(p
p/&,
7%*%2
(9:()(
98(
&
(%(D+D,#
&
7*
p&((
?
(
p
(
%()
(p
p/&,
7%*2&
2&
(8E()(7
8D(
&
(DDD(,#
&
7*
p &((
?
(
p
(
%()
(p
p/&,
7%*&
P&
(8D(p(P&+F 98(
P&
(8D698DE(9D,#
&
7*
p&((
?
(
p
(
%()
(p
p/&,
7%* &P&
(88()(P& +F 98(
P&
(8D698DE(,#
&
7*
p&((
?
(
p
(
%()
(p
p/&,
7%*
&
F& (D(p(&%
88D(
&
(98DE(88+9,#
&
7*
p&((
?
(
p
(
%()
(p
p/&,
7%*2&
&&(99()(
999(C
!
&(8D9988(9D,#
&
7*
p&((
?
(
p
(
%()
(p
p/&,
7%*H %P
p (9()(2&888(
P&
(8D6999(D8+D,#
c
c
&
7*
p&((
?
(
p
(
%()
(p
p/&,
7%*
?3
/ (9()( &%7&
8D(
P&
(%(,#
&
7*
p&((
?
(
p
(
%()
(p
p/&,
7%*3P&
(D()(F
(
&
(D::66:(:,#
&
7*
p&((
?
(
p
(
%()
(p
p/&,
7%*H%
&&(8(p(&p
:6E(
&
(::66:(D+8,#
%(
%*0,
)&
p7
&
%/
%#
%(
%*)
,
)&
p7
&
%/
%#
?
(%p*p
p/&,)&
p7
&
%/ ?
#
?
(p?*p
p/&,)&
p7
&
%/ ?
#
?
(p*p
p/&,)&
p7
&
%/ ?
#
Se pueden simplificar las 2 sentencias anteriores en una sola sentencia, ya que usan el
mismo "group by":
?
(p?*p
p/&,(
p*p
p/&,
)&
p7
&
%/ ?
#
%(7*p
p/&,)&
p7
&
%/
%#
%(?
(
%*0,)&
p7
&
%/
%(?
#
c
c
%(
%*0,)&
p7
-&
%M
&
&
%/
%#
%(
%*0,)&
p7
&
%/
%
#
*á á5
ááááá
á
á
Así como la cláusula "where" permite seleccionar (o rechazar) registros individuales; la
cláusula "having" permite seleccionar (o rechazar) un grupo de registros.
&(
%*0,)&
p&
&
%/
&#
Si queremos saber la cantidad de libros agrupados por editorial pero considerando sólo
algunos grupos, por ejemplo, los que devuelvan un valor mayor a 2, usamos la siguiente
instrucción:
&(
%*0,)&
p&
&
%/
&
-7
%*0,9#
Veamos otros ejemplos. Queremos el promedio de los precios de los libros agrupados
por editorial:
&(7*/&
,)&
p&
&
%/
&#
&(7*/&
,)&
p&
&
%/
&
-77*/&
,9D#
&(
%*0,)&
p&
-&
&MF
&
%/
&#
&(
%*0,)&
p&
&
%/
&
-7
&MF#
La primera, selecciona todos los registros rechazando los de editorial "Planeta" y luego
los agrupa para contarlos. La segunda, selecciona todos los registros, los agrupa para
contarlos y finalmente rechaza la cuenta correspondiente a la editorial "Planeta".
Queremos la cantidad de libros, sin considerar los que tienen precio nulo, agrupados por
editorial, sin considerar la editorial "Planeta":
&(
%*0,)&
p&
-&/&
%
&
%/
&
-7
&MF#
Aquí, selecciona los registros rechazando los que no cumplan con la condición dada en
"where", luego los agrupa por "editorial" y finalmente rechaza los grupos que no
cumplan con la condición dada en el "having".
&(7*/&
,)&
p&
&
%/
&
-7
%*0,9#
Podemos encontrar el mayor valor de los libros agrupados por editorial y luego
seleccionar las filas que tengan un valor mayor o igual a 30:
&(p?*/&
,)&
p&
&
%/
&
-7p?*/&
,L8#
Esta misma sentencia puede usarse empleando un "alias", para hacer referencia a la
columna de la expresión:
& (p?*/&
,p
&)&
p&
&
%/
&
c
c
-7p
&L8#
rá
Trabajamos con la tabla "libros" que registra los datos de una librería.
&
/)?&
#
Creamos la tabla:
&&
*
%%
>
&p(
%
7&
-&*9,
%(
%
&7&
-&*8,(
&7&
-&*D,(
/&
p*D(9,%(
/&p& *
,
,#
&
&
*%
(%
&(
&(/&
,
7%*/-("
&(F(D,#
&
&
*%
(%
&(
&(/&
,
7%*2&<&&
(H
R& (p
(99+9,#
&
&
*%
(%
&(
&(/&
,
7%*
/
( "
&(F(,#
&
&
*%
(%
&(
&(/&
,
7%*/&FRF(2&
2
(p
(:+9,#
&
&
*%
(%
&(
&(/&
,
7%*&7 %B
("
&(F
(8E+,#
&
&
*%
(%
&(
&(/&
,
7%*2%FRF(H++F (F
(8+:,#
&
&
*%
(%
&(
&(/&
,
7%*R&& F
& /&)
)(H+'+
(F
(D+,#
&
&
*%
(%
&(
&(/&
,
7%*R&& F
&
p&
&(H+'+
(F
(E+,#
&
&
*%
(%
&(
&(/&
,
7%*
/p&7(3
&&
(F
(% ,#
&(
%*0,)&
p&
&
%/
&#
Queremos conocer la cantidad de libros agrupados por editorial pero considerando sólo
los que devuelvan un valor mayor a 2, tipeamos:
&(
%*0,)&
p&
&
%/
&
-7
%*0,9#
c
c
&(7*/&
,
)&
p&
&
%/
&#
&(7*/&
,
)&
p&
&
%/
&
-77*/&
,9D#
Queremos contar los registros agrupados por editorial sin tener en cuenta a la editorial
"Planeta". Tipeamos y analicemos las siguientes sentencias:
&(
%*0,)&
p&
-&
&MF
&
%/
&#
&(
%*0,)&
p&
&
%/
&
-7
&MF#
±ote que ambas retornan la misma salida. La primera, selecciona los registros sin
considerar los de la editorial "Planeta" y luego los agrupa para contarlos. La segunda,
selecciona todos los registros, los agrupa para contarlos y finalmente rechaza la cuenta
correspondiente a la editorial "Planeta". Recuerde no confundir las cláusulas "where" y
"having"; la primera establece condiciones para la selección de registros individuales, la
segunda establece condiciones para la selección de filas de una salida "group by".
&(
%*0,)&
p&
-&/&
%
&
%/
&
-7
&MF#
Para obtener el promedio de los precios agrupados por editorial, de aquellas editoriales
que tienen más de 2 libros tipeamos:
&(7*/&
,)&
p&
&
%/
&
-7
%*0,9#
Para encontrar el mayor valor de los libros agrupados por editorial y luego seleccionar
las filas que tengan un valor mayor o igual a 30 usamos:
&(p?*/&
,
)&
p&
&
%/
&
-7p?*/&
,L8#
c
c
Para esta misma sentencia podemos utilizar un "alias" para hacer referencia a la
columna de la expresión:
&(p?*/&
,p
&
)&
p&
&
%/
&
-7p
&L8#
*á á
á
á
á
Con la cláusula "distinct" se especifica que los registros con ciertos datos duplicados
sean obviadas en el resultado. Por ejemplo, queremos conocer todos los autores de los
cuales tenemos libros, si utilizamos esta sentencia:
%
&)&
p&
#
%
&)&
p&
&
%/ %
&#
±ote que en los tres casos anteriores aparece "null" como un valor para "autor"· Si sólo
queremos la lista de autores conocidos, es decir, no queremos incluir "null" en la lista,
podemos utilizar la sentencia siguiente:
Para contar los distintos autores, sin considerar el valor "null" usamos:
%*
%
&,
)&
p&
#
±ote que si contamos los autores sin "distinct", no incluirá los valores "null" pero si los
repetidos:
%*%
&,
)&
p&
#
&)&
p&
#
%*
&,)&
p &
#
Podemos combinarla con "where". Por ejemplo, queremos conocer los distintos autores
de la editorial "Planeta":
&(
%*
%
&,
)&
p&
&
%/
&#
Para mostrar los títulos de los libros sin repetir títulos, usamos:
La cláusula "distinct" afecta a todos los campos presentados. Para mostrar los títulos y
editoriales de los libros sin repetir títulos ni editoriales, usamos:
±ote que los registros no están duplicados, aparecen títulos iguales pero con editorial
diferente, cada registro es diferente.
rá
Creamos la tabla:
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*8,(
&7&
-&*D,(
/&
p*D(9,%(
/&p& *
,
,#
&
&
*%
(%
&(
&(/&
,
7%*/-("
&(F(D,#
c
c
&
&
*%
(%
&(
&(/&
,
7%*2&< &&
(H
R& (p
(99+9,#
&
&
*%
(%
&(
&(/&
,
7%*2&<&&
(H
R& (F(9+9,#
&
&
*%
(%
&(
&(/&
,
7%*
/
("
&(F(,#
&
&
*%
(%
&(
&(/&
,
7%*/&FRF(2&
2
(p
(:+9,#
&
&
*%
(%
&(
&(/&
,
7%*&7 %B
("
& .
"
&(F
(8E+,#
&
&
* %
(%
&(
&(/&
,
7%*2%FRF(%(F
(8+:,#
&
&
*%
(%
&(
&(/&
,
7%*R&& F
& /&)
)(H+'+
(F(D+,#
&
&
*%
(%
&(
&(/&
,
7%*R&& F
&
p&
&(H+'+
(F(E+,#
&
&
*%
(%
&(
&(/&
,
7%*
/p&7(3
&&
(F
(% ,#
&
&
*%
(%
&(
&(/&
,
7%*
/p&7(3
&&
(p
(9+,#
Para contar los distintos autores, sin considerar el valor "null" usamos:
%*
%
&,
)&
p&
#
±ote que si contamos los autores sin "distinct", no incluirá los valores "null" pero si los
repetidos:
%*%
&,
)&
p&
#
&
)&
p&
#
%*
&,
)&
p&
#
Para contar la cantidad de autores distintos de cada editorial podemos usar "distinct" y
"group by":
&(
%*
%
&,
)&
p&
&
%/
&#
Para mostrar los títulos y editoriales de los libros sin repetir títulos ni editoriales,
usamos:
La consulta nos devuelve registros con títulos iguales pero con editorial diferente, cada
registro es distinto.
*Xá á-
á
Un "alias" se usa como nombre de un campo o de una expresión o para referenciar una
tabla cuando se utilizan más de una tabla (tema que veremos más adelante).
%*0,
)&
p&
-&%
&V"
&V#
la columna en la salida tiene como encabezado "count(*)", para que el resultado sea más
claro podemos utilizar un alias:
%*0,&
&
)&
p&
-&%
&V"
&V#
La columna de la salida ahora tiene como encabezado el alias, lo que hace más
comprensible el resultado.
c
c
Un alias puede tener hasta 255 caracteres, acepta todos los caracteres. La palabra clave
"as" es opcional en algunos casos, pero es conveniente usarla. Si el alias consta de una
sola cadena las comillas no son necesarias, pero si contiene más de una palabra, es
necesario colocarla entre comillas.
Se pueden utilizar alias en las clásulas "group by", "order by", "having". Por ejemplo:
&=
p&
&
)&
p&
&
%/ =
p&
&#
&(
%*0,
)&
p&
&
%/
&
&&
#
& (
%*0,
)&
p&
&
%/
&
-7
9#
Los alias serán de suma importancia cuando rescate datos desde el lenguaje PHP
*á áá
á
á
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:
./
-&*E,
%(
./
-&*,(
.-
&p
%(
.-
&p(
±ecesitamos definir una clave primaria para una tabla con los datos descriptos arriba.
±o 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.
c
c
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:
&7-
%
*
/
-&*E,
%(
/
-&*,(
-
&p
%
-
&p(
/&p& */(-
&,
,#
±ombramos los campos que formarán parte de la clave separados por comas.
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":
&7-
%
&
/-
&#
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".
rá
Una playa de estacionamiento guarda cada día los datos de los vehículos que ingresan a
la playa en una tabla llamada "vehiculos".
&
/)?7-
%
#
Para crear una tabla con clave primaria compuesta usamos la siguiente sintaxis:
&7-
%
*
/
-&*E,
%(
/
-&*,(
-
&p
%(
-
&p(
/&p& */(-
&,
,#
Vemos que en la columna "key", en ambos campos aparece "PRI", porque ambos son
clave primaria.
&
7-
%
*/(/
(-
&(-
&,
7%*!98(%
(:8(,#
&
7-
%
*/(/
(-
&(-
&,
7%*'3:(%
(:D(,#
&
7-
%
*/(/
(-
&(-
&,
7%*RP<98(%
(8(,#
&
7-
%
*/(/
(-
&(-
&,
7%*! 98(%
(D8(%,#
&
7-
%
*/(/
(-
&(-
&,
7%*< D D(p
(D(%,#
&
7-
%
*/(/
(-
&(-
&,
7%*P 5D(%
(98(9,#
&
7-
%
*/(/
(-
&(-
&,
7%*!98(%
(E(%,#
&
7-
%
*/(/
(-
&(-
&,
7%*!98(%
(E(%,#
&
7-
%
*/(/
(-
&(-
&,
7%*!<98(p
(:8(,#
&7-
%
&
/-
&#
)&
p7-
%
-&/L!98#
&7-
%
&
/-
&#
c
c
Ahora si lo permite.
10- Vea la estructura de la tabla para ver cómo quedó la clave primaria:
)'á á
áááá
Para facilitar la obtención de información de una tabla se utilizan índices.
El indice de una tabla desempeña la misma función que el índice de un libro: permite
encontrar datos rápidamente; en el caso de las tablas, localiza registros.
El índice es un tipo de archivo con 2 entradas: un dato (un valor de algún campo de la
tabla) y un puntero.
Un índice posibilita el acceso directo y rápido haciendo más eficiente las búsquedas. Sin
índice, se debe recorrer secuencialmente toda la tabla para encontrar un registro.
La indexación es una técnica que optimiza el acceso a los datos, mejora el rendimiento
acelerando las consultas y otras operaciones. Es útil cuando la tabla contiene miles de
registros.
Es importante identificar el o los campos por los que sería útil crear un indice, aquellos
campos por los cuales se realizan operaciones de búsqueda con frecuencia.
1) "primary key": es el que definimos como clave primaria. Los valores indexados
deben ser únicos y además no pueden ser nulos. MySQL le da el nombre "PRIMARü".
Una tabla solamente puede tener una clave primaria.
2) "index": crea un indice común, los valores no necesariamente son unicos y aceptan
valores "null". Podemos darle un nombre, si no se lo damos, se coloca uno por defecto.
"key" es sinónimo de "index". Puede haber varios por tabla.
c
c
3) "unique": crea un indice para los cuales los valores deben ser únicos y diferentes,
aparece un mensaje de error si intentamos agregar un registro con un valor ya existente.
Permite valores nulos y pueden definirse varios por tabla. Podemos darle un nombre, si
no se lo damos, se coloca uno por defecto.
Todos los índices pueden ser multicolumna, es decir, pueden estar formados por más de
1 campo.
Una tabla puede tener hasta 64 índices. Los nombres de índices aceptan todos los
caracteres y pueden tener una longitud máxima de 64 caracteres. Pueden comenzar con
un dígito, pero no pueden tener sólo dígitos.
Una tabla puede ser indexada por campos de tipo numérico o de tipo caracter. También
se puede indexar por un campo que contenga valores ±ULL, excepto los PRIMARü.
"show index" muestra información sobre los índices de una tabla. Por ejemplo:
-
?)&
p&
#
)á á
áá
á
á
El índice llamado primary se crea automáticamente cuando establecemos un campo
como clave primaria, no podemos crearlo directamente. El campo por el cual se indexa
puede ser de tipo numérico o de tipo caracter.
Los valores indexados deben ser únicos y además no pueden ser nulos. Una tabla
solamente puede tener una clave primaria por lo tanto, solamente tiene un índice
PRIMARü.
Puede ser multicolumna, es decir, pueden estar formados por más de 1 campo.
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*8,(
&7&
-&*D,(
/&p& *
,
,#
Podemos ver la estructura de los índices de una tabla con "show index". Por ejemplo:
-
?)&
p&
#
)Aá á
á 2á
,á
Dijimos que hay 3 tipos de índices. Hasta ahora solamente conocemos la clave primaria
que definimos al momento de crear una tabla.
Vamos a ver el otro tipo de índice, común. Un índice común se crea con "index", los
valores no necesariamente son únicos y aceptan valores "null". Puede haber varios por
tabla.
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*8,(
&7&
-&*D,(
/&p& *
,(
?>
&*
&,
,#
Luego de la definición de los campos colocamos "index" seguido del nombre que le
damos y entre paréntesis el o los campos por los cuales se indexará dicho índice.
-
?)&
p&
#
Ciertas tablas (MyISAM, InnoDB y BDB) soportan índices en campos que permiten
valores nulos, otras no, debiendo definirse el campo como "not null".
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*8,(
c
c
&7 &
-&*D,(
?>%
&*%
(
&,
,#
Para crear índices por múltiple campos se listan los campos dentro de los paréntesis
separados con comas. Los valores de los índices se crean concatenando los valores de
los campos mencionados.
)*á á
á2
á
3á
Veamos el otro tipo de índice, único. Un índice único se crea con "unique", los valores
deben ser únicos y diferentes, aparece un mensaje de error si intentamos agregar un
registro con un valor ya existente. Permite valores nulos y pueden definirse varios por
tabla. Podemos darle un nombre, si no se lo damos, se coloca uno por defecto.
Crearemos dos índices únicos, uno por un solo campo y otro multicolumna:
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*8,(
&7&
-&*D,(
%%>
*
,(
%%>%
&*%
(
&,
,#
Luego de la definición de los campos colocamos "unique" seguido del nombre que le
damos y entre paréntesis el o los campos por los cuales se indexará dicho índice.
-
?)&
p&
#
/
=
p& F&
7 C
&Q
/% /
&
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
7/&p& FA25
=
pQ &
/
&)
@?@
@ @ =
7&
Q
&
/
&)
@%%@ 7&
rá
Crearemos dos índices únicos, uno por un solo campo y otro multicolumna:
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*8,(
&7&
-&*D,(
%%>
*
,(
%%>%
&*%
(
&,
,#
-
?)&
p&
#
=
>%% ' >p >>?
%p>p
=%
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>
&
>
&
>%
& %
&
>%
& 9
&
5
Aparecen 3 filas.
Ambos índices son únicos, o sea, no permiten valores repetidos, esto se indica en la
columna "±on_unique". La columna "Key_name" indica el nombre de los índices. La
columna "Seq_in_index" y "Column_name" muestran la secuencia de la indexación
para cada campo del índice "i_tituloeditorial". En el índice "i_tituloeditorial" y el campo
"titulo" muestra 1 y para el campo "editorial" muestra 2, esto significa que está
indexado en ese orden.
La columna "±ull" indica si el campo permite valores nulos; el índice "i_codigo" no los
permite; el campo "titulo" del índice "i_tituloeditorial" no los permite (recuerde que lo
definimos "not null"), el campo "editorial" si los permite (üES).
))á á&á
áá
,á
Para eliminar un índice usamos "drop index". Ejemplo:
&
/?>
&
&
#
&
/?>%
&
&
#
c
c
Se elimina el índice con "drop index" seguido de su nombre y "on" seguido del nombre
de la tabla a la cual pertenece.
Podemos eliminar los índices creados con "index" y con "unique" pero no el que se crea
al definir una clave primaria. Un índice PRIMARü se elimina automáticamente al
eliminar la clave primaria (tema que veremos más adelante).
)ùá á
áá
áá
á
,
á á
,á
Podemos agregar un índice a una tabla existente.
Entonces, para agregar un índice común a una tabla existente usamos "create index",
indicamos el nombre, sobre qué tabla y el o los campos por los cuales se indexará, entre
paréntesis.
Para agregar un índice único a una tabla existente usamos "create unique index",
indicamos el nombre, sobre qué tabla y entre paréntesis, el o los campos por los cuales
se indexará.
Ejemplo:
0)&
p&
p(#
Si tipeamos:
0)&
p&
pD(#
0)&
p&
p:#
Para recuperar los registros desde cierto número hasta el final, se puede colocar un
número grande para el segundo argumento:
0)&
p&
pE(#
)&
p&
p9#
)&
p&
&& /&
p9#
esta sentencia borrará los 2 primeros registros, es decir, los de precio más bajo.
Podemos emplear la cláusula "limit" para eliminar registros duplicados. Por ejemplo,
continuamos con la tabla "libros" de una librería, ya hemos almacenado el libro "El
aleph" de "Borges" de la editorial "Planeta", pero nos equivocamos y volvemos a
ingresar el mismo libro, del mismo autor y editorial 2 veces más, es un error que no
controla MySQL. Para eliminar el libro duplicado y que sólo quede un registro de él
vemos cuántos tenemos:
0)&
p&
-&%
L/-
%
&L"
&
&LF#
Luego eliminamos con "limit" la cantidad sobrante (tenemos 3 y queremos solo 1):
)&
p&
-&%
L/-@
%
&L"
&
&LF
p9#
c
c
0)&
p&
-&%
L/-@
%
&L"
&
&LF#
Sólo queda 1.
)á á
áá
áá!á
á
Una librería que tiene almacenados los datos de sus libros en una tabla llamada "libros"
quiere donar a una institución 5 libros tomados al azar.
Para recuperar de una tabla registros aleatorios se puede utilizar la función "rand()"
combinada con "order by" y "limit":
0)&
p&
&& &*,
pD#
Podemos ejecutar la sentencia anterior varias veces seguidas y veremos que los registros
recuperados son diferentes en cada ocasión.
)Xá á .á
á á
"replace" reemplaza un registro por otro. Solo en caso de que sea un reemplazo de un
valor de clave primaria o único; de resto funciona igual que el insert into.
Si se usa replace para agregar código=2,libro igual hola2. Se agrega un nuevo registro
(osea como si hubiera usado insert into).
Cuando intentamos ingresar con "insert" un registro que repite el valor de un campo
clave o indexado con índice único, aparece un mensaje de error indicando que el valor
está duplicado. Si empleamos "replace" en lugar de "insert", el registro existente se
borra y se ingresa el nuevo, de esta manera no se duplica el valor único.
Si tenemos la tabla "libros" con el campo "codigo" establecido como clave primaria e
intentamos ingresar ("insert") un valor de código existente, aparece un mensaje de error
porque no está permitido repetir los valores del campo clave. Si empleamos "replace" en
lugar de "insert", la sentencia se ejecuta reemplazando el registro con el valor de código
existente por el nuevo registro.
%
%
&
& /&
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
++ 3&&
p
D+
D /&FRF 2&
2
F D+:
98 /- "
& F 98+
&
&
7%*98(H7p%
(2&
2
(p
(9D+D,#
Si empleamos "replace":
&/
&
7%*98(H7p%
(2&
2
(p
(9D+D,#
"replace" funciona como "insert" en los siguientes casos: - si los datos ingresados no
afectan al campo único, es decir no se ingresa valor para el campo indexado:
&/
&
*%
(%
&(
&(/&
,
7%*&7 %B
("
&(F
(9:,#
aparece un mensaje indicando que se afectó un solo registro, el ingresado, que se guarda
con valor de código 0.
&/
&
7%*8(2p
-(F (F
(9+:,#
aparece un mensaje indicando que se afectó solo una fila, no hubo reemplazo porque el
código no existía antes de la nueva inserción.
c
c
&/
&
7%*(R&& F
& /&
)
)(R(p
(:,#
rá
&
/)?&
#
Creamos la tabla:
&&
*
%(
%
7&
-&*,(
%
&7&
-&*8,(
&7&
-&*9,(
/&
p*D(9,%(
/&p& *
,
,#
&
&
7%*(
/p&7(3
&&
(p
(D+,#
&
&
7%*D(/& FRF(2&
2
(F(D+:,#
&
&
7%*98(/-("
&(F(98+,#
&
&
7%*98(H7p%
(2&
2
(p
(9D+D,#
&/
&
7%*98(H7p%
(2&
2
(p
(9D+D,#
&/
&
*%
(%
&(
&(/&
,
7%*&7 %B
("
&(F
(9:,#
aparece un mensaje indicando que se afectó un solo registro, el ingresado, que se guarda
con valor de código 0.
&/
&
7 %*8(2p
-(F (F
(9+:,#
aparece un mensaje indicando que se afectó solo una fila, no hubo reemplazo porque el
código no existía antes de la nueva inserción.
&&
&
//&p& #
&/
&
7%*(R&& F
& /&
)
)(R(p
(:,#
"alter table" hace una copia temporal de la tabla original, realiza los cambios en la
copia, luego borra la tabla original y renombra la copia.
Para ello utilizamos nuestra tabla "libros", definida con la siguiente estructura:
.
G
(%%
>
&p(
7/&p&(
.%
(7&
-&*,
%(
.%
&(7&
-&*8,(
.
&(7&
-&*9,(
./&
(
p*D(9,%+
±ecesitamos agregar el campo "cantidad", de tipo smallint unsigned not null, tipeamos:
&&
p%
%#
Usamos "alter table" seguido del nombre de la tabla y "add" seguido del nombre del
nuevo campo con su tipo y los modificadores.
&&
#
&&
%)&%
&#
rá
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*8,(
&7&
-&*9,(
/&
p*D(9,%(
c
c
Para agregar el campo "cantidad" de tipo smallint unsigned not null, tipeamos:
&&
p%
%#
Si mostramos todos los registros, vemos que los valores para el nuevo campo se
cargaron con su valor por defecto, "0" en el ejemplo porque el campo agregado es de
tipo numérico y declarado "not null".
&&
#
Si mostramos todos los registros, vemos que los valores para el nuevo campo se
cargaron con su valor por defecto, "null" en este caso.
&&
/&
#
ù'á á6
á
ááááá
á áá
"alter table" nos permite alterar la estructura de la tabla, podemos usarla para eliminar
un campo.
&&
&
/
#
c
c
Entonces, para borrar un campo de una tabla usamos "alter table" junto con "drop" y el
nombre del campo a eliminar.
&&
&
/
&(&
/
#
Si se borra un campo de una tabla que es parte de un índice, también se borra el índice.
Hay que tener cuidado al eliminar un campo, éste puede ser clave primaria. Es posible
eliminar un campo que es clave primaria, no aparece ningún mensaje:
&&
&
/
#
ùá á(
!
á
ááááá
á á
!á
Con "alter table" podemos modificar el tipo de algún campo incluidos sus atributos.
.
G
(%(
.%
(7&
-&*8,
%(
.%
&(7&
-&*8,(
.
&(7&
-&*9,(
./&
(
p*D(9,%(
.
%+
Queremos modificar el tipo del campo "cantidad", como guardaremos valores que no
superarán los 50000 usaremos smallint unsigned, tipeamos:
&&
p
)
p%#
Usamos "alter table" seguido del nombre de la tabla y "modify" seguido del nombre del
nuevo campo con su tipo y los modificadores.
Queremos modificar el tipo del campo "titulo" para poder almacenar una longitud de 40
caracteres y que no permita valores nulos, tipeamos:
&&
p
) %
7&
-&*,
%#
c
c
Hay que tener cuidado al alterar los tipos de los campos de una tabla que ya tiene
registros cargados. Si tenemos un campo de texto de longitud 50 y lo cambiamos a 30
de longitud, los registros cargados en ese campo que superen los 30 caracteres, se
cortarán.
&&
p
)
% %
>
&p#
"alter table" combinado con "modify" permite agregar y quitar campos y atributos de
campos. Para modificar el valor por defecto ("default") de un campo podemos usar
también "modify" pero debemos colocar el tipo y sus modificadores, entonces resulta
muy extenso, podemos setear sólo el valor por defecto con la siguienmte sintaxis:
&&
&%
&)%C&
#
&&
&%
&&
/)%#
rá
&&
*
%(
%
7&
-&*8,
%(
%
&7&
-&*8,(
&7&
-&*9,(
/&
p*D(9,%(
%
,#
Para modificar el tipo del campo "cantidad" por "smallint unsigned", tipeamos:
c
c
&&
p
)
p%#
Para modificar el tipo del campo "titulo" para poder almacenar una longitud de 40
caracteres y que no permita valores nulos, tipeamos:
&&
p
) %
7&
-&* ,
%#
&
&
*%
(%
&(
&(/&
(
,
7%*/-("
&(F(98+D(,#
&
&
*%
(%
&(
&(/&
(
,
7%*
/p&7(3
&&
(p
(9D(9,#
&
&
*%
(%
&(
&(/&
(
,
7%*
(%(p
((D,#
&
&
*%
(%
&(
&(/&
(
,
7%*2&<&&
(H
R& (F(D(9,#
& &
p
) %
&7&
-&*,#
0)&
p&
#
±ote que los nombres de los autores que tenían más de 10 caracteres se cortaron.
0)&
p&
#
c
c
±ote que en el campo "autor" del libro "El gato con botas", ahora tiene una cadena
vacía, lo habíamos cargado con "null", pero al redefinir el campo como no nulo, "null"
se convirtió en un valor inválido.
&&
p
) /&
p*(9,#
0)&
p&
(
±ote que el valor "150" se convierte en un valor inválido para el tipo, entonces guarda
en su lugar, el valor límite más cercano, "99.99".
&&
p
)
%%
>
&p#
La sentencia no se ejecuta.
ùAá á
ááááá áá
áááá á á
Con "alter table" podemos cambiar el nombre de los campos de una tabla.
- nombre, varchar(40),
- autor, varchar(30),
&&
c
c
-
/&
p*D(9,#
Usamos "alter table" seguido del nombre de la tabla y "change" seguido del nombre
actual y el nombre nuevo con su tipo y los modificadores.
&&
-
p&%
7&
-&*,
%#
ù*á á-áá
áá á
á
áá
Hasta ahora hemos aprendido a definir una clave primaria al momento de crear una
tabla. Con "alter table" podemos agregar una clave primaria a una tabla existente.(valga
decir que eliminar la clave primaria es quitarle esa propiedad al campo y no eliminar el
campo en si).
.
G
(%%
>
&p(
.%
(7&
-&*,(
.%
&(7&
-&*8,(
.
&(7&
-&*9,(
./&
(
p*D(9,%(
.
p%+
&&
/&p& *
,#
Usamos "alter table" con "add primary key" y entre paréntesis el nombre del campo que
será clave.
Para que un campo agregado como clave primaria sea autoincrementable, es necesario
agregarlo como clave y luego redefinirlo con "modify" como "auto_increment". ±o se
puede agregar una clave y al mismo tiempo definir el campo autoincrementable.
Tampoco es posible definir un campo como autoincrementable y luego agregarlo como
clave porque para definir un campo "auto_increment" éste debe ser clave primaria.
&&
&
//&p& #
Con "alter table" y "drop primary key" eliminamos una clave primaria definida al crear
la tabla o agregada luego.
Si intentamos establecer como clave primaria un campo que tiene valores repetidos,
aparece un mensaje de error y la operación no se realiza.
'
(
"(!
"
c')*
"
!
"
c'+*!
c',*!
'-!,*"(!
"(
*.
.
/'
(
*.
.
/.
.
ù)á á-á
áá áá
,á
Aprendimos a crear índices al momento de crear una tabla. También a crearlos luego de
haber creado la tabla, con "create index". También podemos agregarlos a una tabla
usando "alter table".
&&
*
%(
%
7&
-&*,(
%
&7&
-&*8,(
&7&
-&*9,(
/&
p*D(9,%(
p%
,#
c
c
Para agregar un índice común por el campo "editorial" usamos la siguiente sentencia:
& &
?>
&*
&,#
Usamos "alter table" junto con "add index" seguido del nombre que le daremos al índice
y entre paréntesis el nombre de el o los campos por los cuales se indexará.
Para agregar un índice único multicampo, por los campos "titulo" y "editorial", usamos
la siguiente sentencia:
&&
%%?>%
&*%
(
&,#
Usamos "alter table" junto con "add unique index" seguido del nombre que le daremos
al índice y entre paréntesis el nombre de el o los campos por los cuales se indexará.
ùùá á&áá
ááá áá
,áá
Los índices común y únicos se eliminan con "alter table".
Trabajamos con la tabla "libros" de una librería, que tiene los siguientes campos e
índices:
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
- &*8,(
&7&
-&*D,(
/&p& *
,(
?>
&*
&,(
%%>%
&*%
(
&,
,#
&&
&
/?>
&#
Usamos "alter table" y "drop index" seguido del nombre del índice a borrar.
&&
&
/?>%
&#
c
c
ùá á
áááá
Además de los tipos de datos ya conocidos, existen otros que analizaremos ahora, los
tipos "enum" y "set".
El tipo de dato "enum" representa una enumeración. Puede tener un máximo de 65535
valores distintos. Es una cadena cuyo valor se elige de una lista enumerada de valores
permitidos que se especifica al definir el campo. Puede ser una cadena vacía, incluso
"null".
Los valores presentados como permitidos tienen un valor de índice que comienza en 1.
Una empresa necesita personal, varias personas se han presentado para cubrir distintos
cargos. La empresa almacena los datos de los postulantes a los puestos en una tabla
llamada "postulantes". Le interesa, entre otras cosas, conocer los estudios que tiene cada
persona, si tiene estudios primario, secundario, terciario, universitario o ninguno. Para
ello, crea un campo de tipo "enum" con esos valores.
Para definir un campo de tipo "enum" usamos la siguiente sintaxis al crear la tabla:
&/
%*
%p&
%%
>
&p(
%p
-&*:,(
p&7&
-&*8,(
%
%p*%
(/&p&
(
%&
(
&
&
(%7&&
,(
/&p& *%p&
,
,#
Si un "enum" permite valores nulos, el valor por defecto el "null"; si no permite valores
nulos, el valor por defecto es el primer valor de la lista de permitidos.
&
/
%*
%p
(
p&(%
,
7%*999DD9ED(H%F& &(D,#
&
/
%*
%p
(
p&(%
,
7%*999DD9ED(H%F& &(,#
&
/
%*
%p
(
p&(%
,
7%*999DD9ED(H%F& &(E,#
&
/
%*
%p
(
p& (%
,
7%*999DD9ED(H%F& &(F
P&
,#
En los 3 casos guarda una cadena vacía, en los 2 primeros porque los índices ingresados
están fuera de rango y en el tercero porque el valor no está incluido en la lista de
permitidos.
Esta cadena vacía de error, se diferencia de una cadena vacía permitida porque la
primera tiene el valor de índice 0; entonces, podemos seleccionar los registros con
valores inválidos en el campo de tipo "enum" así:
0)&
p/
%
-&%
L#
0)&
p/
%
-&%
L%7&&
#
Si el campo está definido como "not null" e intenta almacenar el valor "null" aparece un
mensaje de error y la sentencia no se ejecuta.
Los bytes de almacenamiento del tipo "enum" depende del número de valores
enumerados.
rá
Una empresa necesita personal, varias personas se han presentado para cubrir distintos
cargos.
La empresa almacena los datos de los postulantes a los puestos en una tabla llamada
"postulantes". Le interesa, entre otras cosas, conocer los estudios que tiene cada
persona, si tiene estudios primario, secundario, terciario, universitario o ninguno. Para
ello, crea un campo de tipo "enum" con esos valores.
&/
%*
%p&
%%
>
&p(
%p
-&*:,(
p&7&
-&*8,(
?
-&*,(
c
c
%
%p*%
(/&p&
(
%&
(
&
&
(%7&&
,
%(
/&p& *%p&
,
,#
&
/
%*
%p
(
p&(?
(%
,
7%*99888(
()(/&p&
,#
&
/
%*
%p
(
p&(?
(%
,
7%*9988(2&2&
(p(%7&&
,#
Ingresamos un registro sin especificar valor para "estudios", guardará el valor por
defecto:
&
/
%*
%p
(
p&(?
,
7%*9888(3%3
/ (p,#
0)&
p /
%#
&
/
%*
%p
(
p&(?
(%
,
7%*9DDDEE(H%F& &()(D,#
Si ingresamos un valor no presente en la lista, coloca una cadena vacía. Por ejemplo:
&
/
%*
%p
(
p&(?
(%
,
7%*9E6:6(F&
F& (p(F
P&
,#
&
/
%*
%p
(
p&(?
(%
,
7%*99999888(%F& &()(E,#
&
/
%*
%p
(
p&(?
(%
,
7%*9DE6EDE6(2&2
()(,#
La cadena vacía ingresada como resultado de ingresar un valor incorrecto tiene el valor
de índice 0; entonces, podemos seleccionar los registros con valores inválidos en el
campo de tipo "enum" así:
0)&
p/
%
-&%
L#
0)&
p/
%
-&%
L%7&&
#
Como el campo está definido como "not null", si intentamos almacenar el valor "null"
aparece un mensaje de error y la sentencia no se ejecuta.
&
/
%*
%p
(
p&(?
(%
,
7%*9DE6EDE6( 2&2
()(%,#
ùXá á
ááá
á
El tipo de dato "set" representa un conjunto de cadenas.
Puede tener 1 ó más valores que se eligen de una lista de valores permitidos que se
especifican al definir el campo y se separan con comas. Puede tener un máximo de 64
miembros. Ejemplo: un campo definido como set ('a', 'b') not null, permite los valores
'a', 'b' y 'a,b'. Si carga un valor no incluido en el conjunto "set", se ignora y almacena
cadena vacía.
Es similar al tipo "enum" excepto que puede almacenar más de un valor en el campo.
Una empresa necesita personal, varias personas se han presentado para cubrir distintos
cargos. La empresa almacena los datos de los postulantes a los puestos en una tabla
llamada "postulantes". Le interesa, entre otras cosas, saber los distintos idiomas que
conoce cada persona; para ello, crea un campo de tipo "set" en el cual guardará los
distintos idiomas que conoce cada postulante.
&/
%*
%p&
%%
>
&p(
%p
-&*:,(
p&7&
-&*8,(
p*(
(/
&%,(
/&p& *%p&
,
,#
Ingresamos un registro:
&
/
%*
%p
(
p&(
p,
7%*99DDD(
(,#
Para ingresar un valor que contenga más de un elemento del conjunto, se separan por
comas, por ejemplo:
&
/
%*
%p
(
p&(
p,
7%*98DDD(H%F& &((
,#
&
/
%*
%p
(
p&(
p,
c
c
Tampoco importa si se repite algún valor, cada elemento repetido, se ignora y se guarda
una vez y en el orden que ha sido definido, por ejemplo, si ingresamos:
&
/
%*
%p
(
p&(
p,
7%*98DDD(H%F& &(
( (
,#
p/
@
p@%&&;(
+
Si ingresamos un valor que no está en la lista "set", se ignora y se almacena una cadena
vacía, por ejemplo:
&
/
%*
%p
(
p&(
p,
7%*999DD9ED(H%F& &()&
,#
Si un "set" permite valores nulos, el valor por defecto es "null"; si no permite valores
nulos, el valor por defecto es una cadena vacía.
Si se ingresa un valor de índice fuera de rango, coloca una cadena vacía. Por ejemplo:
&
/
%*
%p
(
p&(
p,
7%*999DD9ED(H%F& &(,#
&
/
%*
%p
(
p&(
p,
7%*999DD9ED(H%F& &(:,#
L(
9L
(
8L(
(
L/
&%%(
DL(/
&%%(
EL
(/
&%% (
6L(
(/
&%%+
&
/
%*
%p
(
p&(
p,
7%*999DD9ED(H%F& &(9,#
&
/
%*
%p
(
p&(
p,
7%*99DDD:::(H% F& &(8,#
Para recuperar todos los valores que contengan la cadena "ingles" podemos usar
cualquiera de las siguientes sentencias:
c
c
0)&
p/
%
-&
pVV#
0)&
p/
%
-&)>>*(
p,#
0)&
p/
%
-&
pV(
V#
Para buscar registros que contengan sólo el primer miembro del conjunto "set" usamos:
0)&
p/
%
-&
pL#
0)&
p/
%
-&
pL#
Para buscar los registros que contengan el valor "ingles,italiano" podemos utilizar
cualquiera de las siguientes sentencias:
0)&
p/
%
-&
pL (
#
0)&
p/
%
-&
pL8#
También podemos usar el operador "not". Para recuperar todos los valores que no
contengan la cadena "ingles" podemos usar cualquiera de las siguientes sentencias:
0)&
p/
%
-&
p
VV#
0)&
p/
%
-&
)>>*(
p,#
Los bytes de almacenamiento del tipo "set" depende del número de miembros, se
calcula así: (cantidad de miembros+7)/8 bytes; entonces puede ser 1,2,3,4 u 8 bytes.
rá
Una empresa necesita personal, varias personas se han presentado para cubrir distintos
cargos. La empresa almacena los datos de los postulantes a los puestos en una tabla
c
c
llamada "postulantes". Le interesa, entre otras cosas, saber los distintos idiomas que
conoce cada persona; para ello, crea un campo de tipo "set" en el cual guardará los
distintos idiomas que conoce cada postulante.
&/
%*
%p&
%%
>
&p(
%p
-&*:,(
p&7&
-&*8,(
p*(
(/
&%,(
/&p& *%p&
,
,#
Ingresamos un registro:
&
/
%*
%p
(
p&(
p,
7%*99DDD(
(,#
&
/
%*
%p
(
p&(
p,
7%*98DDD(H%F& &( (
,#
&
/
%*
%p
(
p&(
p,
7%*9DDDD(&P&
(
(,#
Tampoco importa si se repite algún valor, cada elemento repetido, se ignora y se guarda
una vez y en el orden que ha sido definido:
&
/
%*
%p
(
p&(
p,
7%*96DDD(!
2
&(
((
,#
Si ingresamos un valor que no está en la lista "set", se ignora y se almacena una cadena
vacía:
&
/
%*
%p
(
p&(
p,
7%*96DDDE(!R&&&
()&
,#
También coloca una cadena vacía si ingresamos valore de índice fuera de rango:
&
/
%*
%p
(
p&(
p,
7%*9:9DD9ED(F&
F& (,#
&
/
%*
%p
(
p&(
p,
7%*999DD9E(=
!%&(:,#
&
/
%*
%p
(
p&,
c
c
7%*9:DDDE(A<%&
,#
&
/
%*
%p
(
p&(
p,
7%*99DD9ED (H%& (6,#
0)&
p/
%
-&
pVV#
0)&
p/
%
-&
pV(
V#
Recuerde que para las búsquedas, es importante respetar el orden en que se presentaron
los valores en la definición del campo; intentemos buscar el valor "italiano,ingles" en
lugar de "ingles,italiano", no retornará registros:
0)&
p/
%
-&
pV
(V#
0)&
p/
%
-&)>>*(
p,#
Para localizar los registros que sólo contienen el primer miembro del conjunto "set"
usamos:
0)&
p/
%
-&
pL#
0)&
p/
%
-&
pL#
0)&
p/
%
-&
pL6#
Para recuperar todos los valores que ±O contengan la cadena "ingles" podemos usar
cualquiera de las siguientes sentencias:
0)&
p/
%
c
c
-&
p
VV#
0)&
p/
%
-&
)>>*(
p,#
ùá á
áá
ááá,á
Los tipos "blob" o "text" son bloques de datos. Tienen una longitud de 65535 caracteres.
Existen subtipos:
Se utiliza este tipo de datos cuando se necesita almacenar imágenes, sonidos o textos
muy largos.
.
% %
>
&p(
7/&p&(
.
p&7&
-&*,(
.
&7&
-&*8,(
.%&
%(
.
/?(
Se ingresan los datos en un campo "text" o "blob" como si fuera de tipo cadena de
caracteres, es decir, entre comillas:
&
/
%7%*(2%&(H
<
&(9(
p%
p%
J#%N
%/&
+3
%
/
%p/
&%7
/&
pN
+%
p&-&;
% J
%
/& %&
+!&p,#
0)&
p/
%
-&
/V!&pV#
±o se pueden establecer valores por defecto a los campos de tipo "blob" o "text", es
decir, no aceptan la cláusula "default" en la definición del campo.
rá
&
/)?/
%#
&/
%*
%%
>
&p(
p&7&
-&*,(
&7&
-&*8,(
%&
%(
/?(
/&p& *
,
,#
&
/
%7%*(2%&(H
<
&(9(
p%
p%
J( %N
%/&
+
3
%/
%p/
&%7
/&
p
N
+
%p&-&;
%J%
/& %&
+!&p,#
&
/
%7%*9(-& );&
-
(H+!/(9 (
N
p
-&%G
&&%
D
%&
/&&&)%
);&
-
?
J&
1 1
%&&p&
%
+7%&,#
insert into peliculas values(3,'La terminal','Tom Hanks',180, 'Sin papeles y esperando
que el gobierno resuelva su situación migratoria, Victor convierte el aeropuerto de
±ueva üork en su nuevo hogar trasformando la vida de los empleados del lugar.
Drama');
Para buscar todas las películas que en su campo "sinopsis" contengan el texto "Drama"
usamos "like":
0)&
p/
%
-&
/V!&pV#
c
c
0)&
p/
%
-&
/V
-
V#
'á á/
áá áá!0á
!á
Trabajamos con las tablas "libros" de una librería.
±o nos interesa el precio exacto de cada libro, sino si el precio es menor o mayor a $50.
Podemos utilizar estas sentencias:
En la primera sentencia mostramos los libros con precio menor a 50 y en la segunda los
demás.
Veamos el ejemplo:
Si el precio del libro es mayor a 50 (primer argumento del "if"), coloca "caro" (segundo
argumento del "if"), en caso contrario coloca "economico" (tercer argumento del "if").
Queremos mostrar los nombres de los autores y la cantidad de libros de cada uno de
ellos; para ello especificamos el nombre del campo a mostrar ("autor"), contamos los
libros con "autor" conocido con la función "count()" y agrupamos por nombre de autor:
%
&(
%*0,
)&
p&
&
%/ %
&#
El resultado nos muestra cada autor y la cantidad de libros de cada uno de ellos. Si
solamente queremos mostrar los autores que tienen más de 1 libro, es decir, la cantidad
mayor a 1, podemos usar esta sentencia:
%
&(
%*0,
c
c
)&
p&
&
%/ %
&
-7
%*0,#
Pero si no queremos la cantidad exacta sino solamente saber si cada autor tiene más de 1
libro, podemos usar "if":
%
&(
)*
%*0,(2;(,
)&
p&
&
%/ %
&#
Si la cantidad de libros de cada autor es mayor a 1 (primer argumento del "if"), coloca
"Más de 1" (segundo argumento del "if"), en caso contrario coloca "1" (tercer
argumento del "if").
&(
)*
%*0,(D
p;(p
D,
)&
p&
&
%/
&
&&
#
rá
Creamos la tabla:
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*8,(
&7&
-&*8,(
/&
p*D(9,%(
/&p& *
,
,#
&
&
*%
(%
&(
&(/&
,
7%*
/p&7(3
&&
(F
(D+D,#
&
&
*%
(%
&(
&(/&
,
7%*
&7/B
(3&&
(p
(9D,#
&
&
*%
(%
&(
&(/&
,
7%*/-("
&(F
(D,#
&
&
*%
(%
&(
&(/&
,
c
c
±o nos interesa el precio exacto de cada libro, sino si el precio es menor o mayor a $50.
Podemos utilizar estas sentencias:
En la primera sentencia mostramos los libros con precio menor a 50 y en la segunda los
demás.
Si el precio del libro es mayor a 50 (primer argumento del "if"), coloca "caro" (segundo
argumento del "if"), en caso contrario coloca "economico" (tercer argumento del "if").
Queremos mostrar los nombres de los autores y la cantidad de libros de cada uno de
ellos; para ello especificamos el nombre del campo a mostrar ("autor"), contamos los
libros con "autor" conocido con la función "count()" y agrupamos por nombre de autor:
%
&(
%*0,
)&
p&
&
%/ %
&#
El resultado nos muestra cada autor y la cantidad de libros de cada uno de ellos. Si
solamente queremos mostrar los autores que tienen más de 1 libro, es decir, la cantidad
mayor a 1, podemos usar esta sentencia:
%
&(
%*0,
)&
p&
&
%/ %
&
-7
%*0,#
Pero si no queremos la cantidad exacta sino solamente saber si cada autor tiene más de 1
libro, podemos usar "if":
%
&(
)*
%*0,(2;(,
)&
p&
&
%/ %
&#
c
c
Si la cantidad de libros de cada autor es mayor a 1 (primer argumento del "if"), coloca
"Más de 1" (segundo argumento del "if"), en caso contrario coloca "1" (tercer
argumento del "if").
%
&(
)*
%*0,(2;(,
)&
p&
&
%/ %
&
&&
#
&(
)*
%*0 ,(D
p;(p
D,
)&
p&
&
%/
&
&&
#
á á/
áá áá!0á
á
La función "case" es similar a la función "if", sólo que se pueden establecer varias
condiciones a cumplir.
&(
)*
%*0,(29(,
)&
p&
&
%/
&#
vemos los nombres de las editoriales y una columna "cantidad" que especifica si hay
más o menos de uno. Podemos obtener la misma salida usando un "case":
&(
%*0,
--
p
)&
p&
&
%/
&#
Por cada valor hay un "when" y un "then"; si encuentra un valor coincidente en algún
"where" ejecuta el "then" correspondiente a ese "where", si no encuentra ninguna
c
c
--
+++
&(
%*0,
--
)&
p&
&
%/
&#
Con el "if" solamente podemos obtener dos salidas, cuando la condición resulta
verdadera y cuando es falsa, si queremos más opciones podemos usar "case". Vamos a
extender el "case" anterior para mostrar distintos mensajes:
&(
%*0,
--
-9-9
-8-8
2;8
)&
p&
&
%/
&#
Incluso podemos agregar una cláusula "order by" y ordenar la salida por la columna
"cantidad":
&(
%*0,
--
-9-9
-8-8
2;8
)&
p&
&
%/
&
&&
#
&(
%*0,
--
--p
)&
p&
&
%/
&#
c
c
--
+++
Veamos un ejemplo:
&(
-
%*0,L-
p%
)&
p&
&
%/
&#
rá
&
/)?&
#
Creamos la tabla:
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*8,(
&7&
-&*9,(
/&
p*D(9,%(
p%(
/&p& *
,
,#
&
&
*%
(%
&(
&(/&
(
,
7%*/-("
&(F(8+D(,#
&
&
*%
(%
&(
&(/&
(
,
7%*
/ p&7(&&
3+(F
(9+6(D,#
&
&
*%
(%
&(
&(/&
(
,
7%*-&& F
&
p&
&(%(p
(8D(D,#
&
&
*%
(%
&(
&(/&
(
,
7%*/& FRF(2
2&
(F(D(,#
&
&
*%
(%
&(
&(/&
(
,
7%*R&& F
& /&)
)(%(p
(8:(D,#
&
&
*%
(%
&(
&(/&
(
,
7%*/&H7(2
2&
(F(DD(,#
&
&
*%
(%
&(
&(/&
(
,
7%*/&H7
&/(2
2&
(F(D:(D,#
&(
%*0,
--
p
)&
p&
&
%/
&#
Por cada valor hay un "when" y un "then"; si encuentra un valor coincidente en algún
"where" ejecuta el "then" correspondiente a ese "where", si no encuentra ninguna
coincidencia, se ejecuta el "else", si no hay parte "else" retorna "null". Finalmente se
coloca "end" para indicar que el "case" ha finalizado. Veamos un ejemplo sin parte
"else":
& (
%*0,
--
)&
p&
&
%/
&#
&(
%*0,
--
-9-9
-8-8
2;8
)&
p&
&
%/
&#
Agregamos la cláusula "order by" para ordenar la salida por la columna "cantidad":
&(
%*0,
--
-9-9
-8-8
2;8
)&
p&
&
%/
&
&&
#
&(
%*0,
--
--p
)&
p&
&
%/
&#
&(
-
%*0,L-
c
c
p
)&
p&
&
%/
&#
Aá á*
á
á0
á
Hasta ahora hemos trabajado con una sola tabla, pero en general, se trabaja con varias
tablas.
Por ejemplo, los datos de nuestra tabla "libros" podrían separarse en 2 tablas, una
"libros" y otra "editoriales" que guardará la información de las editoriales. En nuestra
tabla "libros" haremos referencia a la editorial colocando un código que la identifique.
Veamos:
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*8,
%)%!
(
& %
%(
/&
p*D(9,%(
p%)%(
/&p& *
,
,#
&
&*
%%
>
&p(
p&7&
-&*9,
%(
/&p& *
,
,#
De este modo, evitamos almacenar tantas veces los nombres de las editoriales en la
tabla "libros" y guardamos el nombre en la tabla "editoriales"; para indicar la editorial
de cada libro agregamos un campo referente al código de la editorial en la tabla "libros"
y en "editoriales".
0)&
p&
#
Cuando obtenemos información de más de una tabla decimos que hacemos un "join"
(unión). Veamos un ejemplo:
0)&
p&
B
&
&
+
&L
&+
#
c
c
Indicamos el nombre de la tabla luego del "from" ("libros"), unimos esa tabla con "join"
y el nombre de la otra tabla ("editoriales"), luego especificamos la condición para
enlazarlas con "on", es decir, el campo por el cual se combinarán. "on" hace coincidir
registros de las dos tablas basándose en el valor de algún campo, en este ejemplo, los
códigos de las editoriales de ambas tablas, el campo "codigoeditorial" de "libros" y el
campo "codigo" de "editoriales" son los que enlazarán ambas tablas.
Cuando se combina (join, unión) información de varias tablas, es necesario indicar qué
registro de una tabla se combinará con qué registro de la otra tabla.
0)&
p&
B
&#
0)&
p&
B
&
&
+
&L
&+
#
0)&
p&
B
&
&L
#
Entonces, si en las tablas, los campos tienen el mismo nombre, debemos especificar a
cuál tabla pertenece el campo al hacer referencia a él, para ello se antepone el nombre
de la tabla al nombre del campo, separado por un punto (.).
0)&
p&
B
&
+
&L+
#
Cada tabla tiene un alias y se referencian los campos usando el alias correspondiente.
En este ejemplo, el uso de alias es para fines de simplificación, pero en algunas
consultas es absolutamente necesario.
Al presentar los campos, en este caso, no es necesario aclarar a qué tabla pertenecen
porque los campos solicitados no se repiten en ambas tablas, pero si solicitáramos el
código del libro, debemos especificar de qué tabla porque el campo "codigo" se repite
en ambas tablas ("libros" y "editoriales"):
+
(%
(%
&(
p&)&
p&
B
&
+
&L+
#
rá
&
/)?&
(
&#
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*8,
%)%!
(
& %
%(
/&
p*D(9,%(
p%)%(
/&p& *
,
,#
&
&*
%%
>
&p(
p&7&
-&*9,
%(
/&p& *
,
,#
c
c
&
&*
p&,7%*F
,#
&
&*
p&,7%*p
,#
&
&*
p&,7%*F,#
&
& *
p&,7%*%p&
,#
&
&
*%
(%
&(
&(/&
(
,
7%*/-("
&(8(8+D(9,#
&
&
*%
(%
&(
&(/&
(
,
7%*
/p&7(3
&&
(9(88+D(,#
&
&
*%
(%
&(
&(/&
(
,
7%*/&FRF(2&
F& ((DD+:( D,#
&
&
*%
(%
&(
&(/&
(
,
7%*H7p%
(H%3
/ ((::(D,#
&
&
*%
(%
&(
&(/&
(
,
7%*
&7/B
(3&&
((D+D( :,#
&
&
*%
(%
&(
&(/&
(
,
7%*&7 %B
("
& ."
&(8(9D+D(8,#
0)&
p&
#
0)&
p&
B
&
&
+
&L
&+
#
0)&
p&
B
&#
el resultado es el producto cartesiano de ambas tablas. Un "join" sin condición "on" para
la unión genera un resultado en el que aparecen todas las combinaciones de los registros
de ambas tablas.
0)&
p&
B
&
&L
#
c
c
Por ello, si hacemos referencia a un campo de una tabla que tiene el mismo nombre que
el campo de la otra tabla consultada, debemos especificar a cuál tabla pertenece dicho
campo.
0)&
p&
B
&
+
&L+
#
+
(%
(%
&(
p&)&
p&
B
&
+
&L+
#
(%
(%
&(
p&)&
p&
B
&
+
&L+
#
*á áá!á
Un campo que se usa para establecer un "join" (unión) con otra tabla en la cual es clave
primaria, se denomina "clave ajena o foránea".
En el ejemplo de la librería en que utilizamos las tablas "libros" y "editoriales" con los
campos:
&
*
7/&p&,(%
(%
&(
&(
/&
(
&
*
7/&p&,(
p&+
Cuando alteramos una tabla, debemos tener cuidado con las claves foráneas. Si
modificamos el tipo, longitud o atributos de una clave foránea, ésta puede quedar
inhabilitada para hacer los enlaces.
Las claves foráneas y las claves primarias deben ser del mismo tipo para poder
enlazarse. Si modificamos una, debemos modificar la otra para que los valores se
correspondan.
rá
&
/&
(
&#
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*8,
%)%!
(
& %
%(
/&
p*D(9,%(
p%)%(
/&p& *
,
,#
&
&*
%%
>
&p(
p&7&
-&*9,
%(
/&p& *
,
,#
&
&7%*9(p
,#
&
& 7%*D(F,#
&
&7%*98(F
,#
&
&
7%*(/-("
&(98(+DD(,#
&
&
7%*9(
/
p&7(3&&
(9(+DD(9,#
&
&
7%*8(2&<&&
(H
R& (D(6+9(,#
Si modificamos el tipo, longitud o atributos de una clave foránea, ésta puede quedar
inhabilitada para hacer los enlaces.
Veamos un ejemplo:
c
c
&&
p
)
&
-&*,#
0)&
p&
#
El libro con código de editorial "23" ("Paidos") ahora tiene "2" ("Emece") en
"codigoeditorial" y el libro con código de editorial "15" ("Planeta") ahora almacena "1"
(valor inexistente en "editoriales").
El resultado es erróneo.
Las claves foráneas y las claves primarias deben ser del mismo tipo para poder
enlazarse. Si modificamos una, debemos modificar la otra para que los valores se
correspondan.
&
&
p
)
-&*,#
±o lo permite porque si la modifica los valores para el campo clave quedan repetidos.
)á á*
á
á!á0
á
Hemos visto cómo usar registros de una tabla para encontrar registros de otra tabla,
uniendo ambas tablas con "join" y enlazándolas con una condición "on" en la cual
colocamos el campo en común. O sea, hacemos un "join" y asociamos registros de 2
tablas usando el "on", buscando coincidencia en los valores del campo que tienen en
comun ambas tablas.
.&
*
7/&p&,(%
(%
&(
&(
/&
(
.
&
*
7/&p&,(
p&+
Para averiguar qué registros de una tabla no se encuentran en otra tabla necesitamos
usar un "join" diferente.
c
c
Para obtener la lista de editoriales y sus libros, incluso de aquellas editoriales de las
cuales no tenemos libros usamos:
0)&
p
&
)B
&
&+
L&
+
&#
Un "left join" se usa para hacer coincidir registros en una tabla (izquierda) con otra tabla
(derecha), pero, si un valor de la tabla de la izquierda no encuentra coincidencia en la
tabla de la derecha, se genera una fila extra (una por cada valor no encontrado) con
todos los campos seteados a "null".
0)&
p
&
)B
&
&+
L&
+
&#
0)&
p&
)B
&
&+
L&
+
&#
La primera sentencia opera así: por cada valor de codigo de "editoriales" busca
coincidencia en la tabla "libros", si no encuentra coincidencia para algún valor, genera
una fila seteada a "null".
Luego del "on" se especifican los campos que se asociarán; no se deben colocar
condiciones en la parte "on" para restringir registros que deberían estar en el resultado,
para ello hay que usar la cláusula "where".
Un "left join" puede tener clausula "where" que restringa el resultado de la consulta
considerando solamente los registros que encuentran coincidencia en la tabla de la
derecha:
+
p&(+%
)&
p
&
)B
&
+
L+
&
-&+
&
%#
c
c
El anterior "left join" muestra los valores de la tabla "editoriales" que están presentes en
la tabla de la derecha ("libros").
+
p&(+%
)&
p
&
)B
&
+
L+
&
-&+
&%#
El anterior "left join" muestra los valores de la tabla "editoriales" que no encuentran
correspondencia en la tabla de la derecha, "libros"
rá
&
/)?&
(
&#
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*8,
%)%!
(
& %
%(
/&
p*D(9,%(
%)%(
/&p& *
,
,#
&
&*
%%
>
&p(
p&7&
-&*9,
%(
/&p& *
,
,#
&
&*
p&,7%*F
,#
&
&*
p&,7%*p
,#
&
&*
p&,7%*F,#
&
&*
p&,7%*%p&
,#
&
&
*%
(%
&(
&(/&
(
,
7%*/-("
&(8(8+D(9,#
&
&
*%
(%
&(
&(/&
(
,
7%*
/p&7(3
&&
(9(88+D(,#
&
&
*%
(%
&(
&(/&
(
,
7%*/&FRF(2&
F& ((DD+:(D,#
&
&
*%
(%
&(
&(/&
(
,
c
c
7%*H7p%
(H%3
/ ((::(D,#
&
&
*%
(%
&(
&(/&
(
,
7%*
&7/B
(3&&
((D+D(:,#
&
&
*%
(%
&(
&(/&
(
,
7%*&7 %B
("
& ."
&(8(9D+D(8,#
&
&
*%
(%
&(
&(/&
(
,
7%*/&H7p%
(3
/ H%(D(9:(,#
Para obtener la lista de todas las editoriales y los libros de las mismas, incluso de las
cuales no tenemos libros usamos:
0)&
p
&
)B
&
&+
L&
+
&#
Un "left join" se usa para hacer coincidir registros en una tabla (izquierda) con otra tabla
(derecha), pero, si un valor de la tabla de la izquierda no encuentra coincidencia en la
tabla de la derecha, se genera una fila extra (una por cada valor no encontrado) con
todos los campos seteados a "null".
Recuerde que es importante la posición en que se colocan las tablas en un "left join", la
tabla de la izquierda es la que localiza registros en la tabla de la derecha. Por lo tanto,
estos "join" no son iguales:
0)&
p
&
)B
&
&+
L&
+
&#
0)&
p&
)B
&
&+
L&
+
&#
La primera sentencia busca coincidencia en la tabla "libros" por cada valor de codigo de
"editoriales", si no encuentra coincidencia para algún valor, genera una fila seteada a
"null". ±o hay libros de la editorial "Sudamericana", entonces esa fila contiene "null" en
todos los campos correspondientes a "libros".
Para encontrar los valores de código de la tabla "editoriales" que están presentes en la
tabla "libros" usamos un "where":
p&(%
)&
p
&
)B
&
+
L+
&
-&+
&
%#
+
p&(+%
)&
p
&
)B
&
+
L+
&
-&+
&%#
ùá á*
á
á
á0
á
"right join" opera del mismo modo que "left join" sólo que la búsqueda de coincidencias
la realiza de modo inverso, es decir, los roles de las tablas se invierten, busca
coincidencia de valores desde la tabla de la derecha en la tabla de la izquierda y si un
valor de la tabla de la derecha no encuentra coincidencia en la tabla de la izquierda, se
genera una fila extra (una por cada valor no encontrado) con todos los campos seteados
a "null".
.&
*
7/&p&,(%
( %
&(
&(
/&
(
.
&
*
7/&p&,(
p&+
p&(%
)&
p
&
)B
&
+
L+
&#
p&( %
)&
p&
&-B
&
+
L+
&#
á á*
á
á
á0
á
"cross join" retorna todos los registros de todas las tablas implicadas en la unión,
devuelve el producto cartesiano. ±o es muy utilizado.
Un pequeño restaurante tiene almacenados los nombres y precios de sus comidas en una
tabla llamada "comidas" y en una tabla denominada "postres" los mismos datos de sus
postres.
El restaurante quiere combinar los registros de ambas tablas para mostrar los distintos
menúes que ofrece. Podemos usar "cross join":
+0(/+0
)&
p
p
c
c
&
B
/
&/#
+0(/+0
)&
p
p
B
/
& /#
Podemos organizar la salida del "cross join" para obtener el nombre del plato principal,
del postre y el precio total de cada combinación (menú):
+
p&(/+
p&(
+/&
S/+/&
)&
p
p
&
B
/
&/#
Para realizar un "join" no es necesario utilizar 2 tablas, podemos combinar los registros
de una misma tabla. Para ello debemos utilizar 2 alias para la tabla.
Si los datos de las tablas anteriores ("comidas" y "postres") estuvieran en una sola tabla
con la siguiente estructura:
&
p*
%%
>
&p(
p&7&
-&*8,(
&%&
7&
-&*9,(T0/
/&
/ /
&0T
/&
p*D(9,%(
/&p& *
,
,#
+
p&(
+/&
(
9+
p&(
9+/&
)&
p
p
&
B
p
9
-&
+&%&
L/
/&
/
9+&%&
L/
&#
+
p&(
9+
p&(
+/&
S
9+/&
)&
p
p
&
B
p
9
-&
+&%&
L/
/&
/
9+&%&
L/
&#
á á*
á
áá0
á
"natural join" se usa cuando los campos por los cuales se enlazan las tablas tienen el
mismo nombre.
c
c
.&
*
7/&p&,(%
(%
&(
&(
/&
+
.
&
&*
7/&p&,(
p&+
p&(%
)&
p
&
%&)B
&
#
p&(%
)&
p
&
)B
&
+
&L+
&#
Es decir, con "natural join" no se coloca la parte "on" que especifica los campos por los
cuales se enlazan las tablas, porque MySQL busca los campos con igual nombre y
enlaza las tablas por ese campo.
Hay que tener cuidado con este tipo de "join" porque si ambas tablas tiene más de un
campo con igual nombre, MySQL no sabrá por cual debe realizar la unión. Por ejemplo,
si el campo "titulo" de la tabla "libros" se llamara "nombre", las tablas tendrían 2
campos con igual nombre ("codigoeditorial" y "nombre").
Otro problema que puede surgir es el siguiente. Tenemos la tabla "libros" con los
siguientes campos: codigo (del libro), titulo, autor y codigoeditorial, y la tabla
"editoriales" con estos campos: codigo (de la editorial) y nombre. Si usamos "natural
join", unirá las tablas por el campo "codigo", que es el campo que tienen igual nombre,
pero el campo "codigo" de "libros" no hace referencia al código de la editorial sino al
del libro, así que la salida será errónea
c
c
á
Xá á*
á
á
á0
á á
á
0
á
Existen otros tipos de "join" además del simple "join", "left join", "right join", "cross
join" y "natural join". Veámoslos.
"inner join" es igual que "join". Con "inner join", todos los registros no coincidentes son
descartados, sólo los coincidentes se muestran en el resultado:
p&(%
)&
p
&
&B
&
+
L+
& #
p&(%
)&
p
&
B
&
+
L+
&#
"straight join" es igual a "join", sólo que la tabla de la izquierda es leída siempre antes
que la de la derecha.
á á0
7áááá!
áá
á
Podemos usar "group by" y las funciones de agrupamiento con "join".
Para ver todas las editoriales, agrupadas por nombre, con una columna llamada
"Cantidad de libros" en la que aparece la cantidad calculada con "count()" de todos los
libros de cada editorial tipeamos:
+
p&(
%*+
&,&
)&
p
&
)B
&
+
&L+
&
%/ +
p&#
Si usamos "left join" la consulta mostrará todas las editoriales, y para cualquier editorial
que no encontrara coincidencia en la tabla "libros" colocará "0" en "Cantidad de libros".
Si usamos "join" en lugar de "left join":
+
p&(
%*+
&, &
)&
p
&
B
&
c
c
+
&L+
&
%/ +
p&#
solamente mostrará las editoriales para las cuales encuentra valores coincidentes para el
código de la editorial en la tabla "libros".
Para conocer el mayor precio de los libros de cada editorial usamos la función "max()",
hacemos una unión y agrupamos por nombre de la editorial:
+
p&(
p?*+/&
,2
&/&
)&
p
&
)B
&
+
& L+
&
%/ +
p&#
+
p&(
p?*+/&
,2
&/&
)&
p
&
B
&
+
&L+
&
%/ +
p&#
sólo mostrará las editoriales para las cuales encuentra correspondencia en la tabla de la
derecha.
rá
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*8,
%)%(
& %
%(
/&
p*D(9,% (
/&p& *
,
,#
&
&*
%%
>
&p(
p&7&
-&*9,(
/&p& *
,
,#
&
&*
p&,7%*F,#
c
c
&
&*
p&,7%*p
,#
&
&*
p&,7%*F
,#
&
&
*%
(%
&(
&(/&
,
7%*
/p&7(3
&&
((98+D,#
&
&
*%
(%
&(
&(/&
,
7%*
&7/B
(3&&
(9(9D,#
&
&
*%
(%
&(
&(/&
,
7%*/-("
&(9(D,#
&
&
*%
(%
&(
&(/&
,
7%*2p;
-(F ((,#
Para ver todas las editoriales, agrupadas por nombre, con una columna llamada
"cantidad de libros" en la que aparece la cantidad calculada con "count()" de todos los
libros de cada editorial tipeamos:
+
p&(
%*+
&,
&
)&
p
&
)B
&
+
&L+
&
%/ +
p&#
±ote que como usamos "left join" la consulta muestra todas las editoriales, y para la
editorial que no encuentra coincidencia en "libros" coloca "0" en "cantidad de libros". Si
usáramos "join" en lugar de "left join":
+
p&(
%*+
&,
&
)&
p
&
B
&
+
&L+
&
%/ +
p&#
solamente muestra las editoriales para las cuales encuentra valores coincidentes para el
código de la editorial en "libros".
Para conocer el mayor precio de los libros de cada editorial usamos la función "max()",
hacemos un "join" y agrupamos por nombre de la editorial:
+
p&(
p?*+/&
,p
&/&
)&
p
&
)B
&
+
&L+
&
%/ +
p&#
+
p&(
p?*+/&
,p
&/&
)&
p
&
B
&
+
&L+
c
c
&
%/ +
p&#
sólo mostrará las editoriales para las cuales encuentra correspondencia en "libros".
'á á0
á á
áá
á
á
Podemos hacer un "join" con más de dos tablas.
Una biblioteca registra la información de sus libros en una tabla llamada "libros", los
datos de sus socios en "socios" y los préstamos en una tabla "prestamos".
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*9,)%!
(
/&p& *
,
,#
&
*
%p
-&*:,
%(
p&7&
-&*8,(
p
7&
-&*8,(
/&p& *%p&
,
,#
&/&p
*
%p
-&*:,
%(
&
%(
)
-/&p
%(
)
-7
%
(
/&p& *
&
()
-/&p
,
,#
0)&
p/&p
#
aparece el código del libro pero no sabemos el nombre y tampoco el nombre del socio
sino su documento. Para obtener los datos completos de cada préstamo, incluyendo esos
datos, necesitamos consultar las tres tablas.
p&(%
()
-/&p
)&
p/&p
/
B
+
%p
L/+
%p
B
&
&
L
#
c
c
±ote que especificamos a qué tabla pertenece el campos "documento" porque a ese
nombre de campo lo tienen las tablas "prestamos" y "socios", esto es necesario para
evitar confusiones y ambiguedades al momento de referenciar un campo. En este
ejemplo, si omitimos la referencia a las tablas al nombrar el campo "documento"
aparece un mensaje de error indicando que "documento" es ambiguo.
Para ver todos los prestamos, incluso los que no encuentran coincidencia en las otras
tablas, usamos:
p&(%
()
-/&p
)&
p/&p
/
)B
/+
%p
L+
%p
)B
&
+
L/+
&
#
Podemos ver aquellos prestamos con valor coincidente para "libros" pero para "socio"
con y sin coincidencia:
p&(%
()
-/&p
)&
p/&p
/
)B
/+
%p
L+
%p
B
&
/+
&
L+
#
á
rá
Una biblioteca registra la información de sus libros en una tabla llamada "libros", los
datos de sus socios en "socios" y los préstamos en una tabla "prestamos".
&&
*
%%
>
&p(
%
7&
-&*,
%(
%
&7&
-&*9,)%!
(
/&p& *
,
,#
&
*
%p
-&*:,
%(
c
c
p&7&
-&*8,(
p
7&
-&*8,(
/&p& *
%p
,
,#
&/&p
*
%p
-&*:,
%(
&
%(
)
-/&p
%(
)
-7
%
(
/&p& *
&
()
-/&p
,
,#
&
7%*99888(H%F& (
8D,#
&
7%*98888(3%3
/ (&
,#
&
7%*9D888(R&&&
(%
&9,#
&
&
7%*(2%9Z&
(2
2%,#
&
&
7%*9D(/&FRF(
&2 ,#
&
&
7%*9(2&<&&
(H
R& ,#
&
/&p
7%*99888((9E .:.(9E .:.9,#
&
/&p
7%*99888((9E .:.D(%,#
&
/&p
7%*9D888(9D(9E .:.(9E.:.
8,#
&
/&p
7%*9D888(9(9E .:.(%,#
&
/&p
7%*9D888(9D(9E .:.D(%,#
&
/&p
7%*8888(9(9E .:.9(9E.:.
D,#
&
/&p
7%*9D888(9(9E .:.9(9E .:.D,#
0)&
p/&p
#
aparece el código del libro pero no sabemos el nombre y tampoco el nombre del socio
sino su documento. Para obtener los datos completos de cada préstamo, incluyendo esos
datos, necesitamos consultar las tres tablas.
p&(%
()
-/&p
)&
p/&p
/
B
+
%p
L/+
%p
B
&
&
L
#
Muestra todos los prestamos para los cuales encuentra coincidencia en "socios" y
"libros".
Para ver todos los prestamos, incluso los que no encuentran coincidencia en las otras
tablas, usamos:
p&(%
()
-/&p
c
c
)&
p/&p
/
)B
/+
%p
L+
%p
)B
&
+
L/+
&
#
±ote que también se muestran aquellos prestamos para los cuales no se encontró
coincidencia en "libros" y "socios", es decir, hay un código de libro ingresado en
"prestamos" que no existe en la tabla "libros", esa fila está seteada a "null" en "titulo";
también hay un préstamo con un documento que no está en la tabla "socios", esa fila
contiene "null" en "nombre".
Podemos ver aquellos prestamos con valor coincidente para "libros" pero para "socio"
con y sin coincidencia:
p&(%
()
-/&p
)&
p/&p
/
)B
/+
%p
L+
%p
B
&
/+
&
L+
#
±ote que el préstamo con código de libro inexistente en la tabla "libros" ya no aparece.