Mostrando entradas con la etiqueta php. Mostrar todas las entradas
Mostrando entradas con la etiqueta php. Mostrar todas las entradas

domingo, 22 de octubre de 2017

Formulario con arrays en PHP

Explicación de cómo pasar un array entre un formulario y nuestra página php. En este caso implementamos una lista de la compra en la que:
- al añadir un producto sin cantidad se elimina ese producto de la lista de la compra si ya estaba.
- si ponemos una cantidad sin un producto nos avisa de que falta la descripción.
- si añadimos una cantidad de un producto ya existente se suma a la cantidad previa.
- en todo momento se va mostrando la lista de la compra actualizada.

Para el paso de array se usan tres métodos: en primer lugar como un campo oculto en el que se van concatenando el contenido del array, en segundo lugar empleando el método serialize y unserialize, y finalmente empleando json_encode y json_decode.


sábado, 14 de octubre de 2017

Instalación de xampp en Windows y resolución de la primera práctica de desenvolvemento web en entorno servidor.

miércoles, 27 de mayo de 2009

Manual de PHP 81.MySQL: Proteger PHPMyAdmin

Borrado de usuarios MySQL
Hasta el momento no hemos modificado ni los usuarios de MySQL ni la configuración de PHPMyAdmin.

Aún tenemos los usuarios por defecto (root sin contraseña) y PHPMyAdmin sigue dándonos el mensaje de advertencia relativo al fallo de seguridad de la configuración.

El primer paso para corregir esa vulnerabilidad será borrar los usuarios dejando sólo el usuario pepe que es el que hemos creado al instalar MySQL.

Para ello, con el servidor MySQL activo, abriremos PhpMyAdmin editaremos la tabla user correspondiente a la base de datos mysql y borraremos los usuarios, dejando únicamente al usuario pepe.





Una vez realizados estos cambios, deberíamos cerrar el servidor MySQL y reiniciarlo con la nueva configuración. A partir de aquí, cuando tratamos de acceder de nuevo a PHPMyAdmin nos aparecerá un mensaje de error tal como el que vemos en la imagen.




PHPMyAdmin nos dará este mensaje de error porque su configuración por defecto utiliza el usuario root que ya no existe. ¡Acabamos de borrarlo!

Modificación de la configuración de PHPMyAdmin

Hemos de modificar el fichero config.inc.php que está en el sudirectorio libraires de MyAdmin. Un simple cambio, tal como el que ves en las imágenes será suficiente.



Bastará cambiar (en la línea 71 del fichero) la palabra config por http, guardar los cambios y, como siempre, reiniciar el servidor MySQL para que se active la protección de PHPMyAdmin.


Acceso a PHPmyAdmin

A partir del momento que hayamos hecho los cambios anteriores, cada vez que tratemos de acceder a http://localhost/MyAdmin/ nos aparecerá una ventana como la que vemos en la imagen. Será necesario introducir un nombre de usuario válido (pepe en nuestro caso).



Nos desaparecerá el mensaje de advertencia y ya podremos gestionar nuestras bases de datos de forma un poco más segura.




Manual de PHP 80.MySQL: Otras consultas

Definición de tablas

En este ejemplo de tablas vinculadas con integridad relacional vamos a proponer la situación siguiente.

Crearemos una primera tabla (alumnos) que va a contener datos personales de un grupo de personas.

Para evitar duplicar un mismo alumno y alumnos sin DNI, vamos a utilizar como índice primario (PRIMARY KEY) el campo DNI (que es único para cada persona).

La condición de que el campo DNI sea PRIMARY KEY nos obliga a definirlo con el flag NOT NULL, dado que esta es una condición necesaria para la definición de índices primarios.

Crearemos una segunda tabla (domicilios) con los domicilios de cada uno de los alumnos, identificándolos también por su DNI. Para evitar que un mismo alumno pueda tener dos domicilios asignamos a al campo DNI de esta tabla la condición de índice único (UNIQUE).

El índice UNIQUE podríamos haberlo creado también como PRIMARY KEY ya que la única diferencia de comportamiento entre ambos es el hecho que aquel admitiría valores NULOS pero, dado que debemos evitar domicilios sin alumnos, insertaremos el flag NOT NULL en este campo.

El hecho de utilizar dos tablas no tiene otro sentido que la ejemplificación ya que lo habitual sería que todos los datos estuvieran en una misma tabla.

Vincularemos ambas tablas de modo que no puedan crearse direcciones de alumnos inexistentes y les pondremos la opción de actualización y borrado en cascada. De esta forma las acciones en la tabla de alumno se reflejarían automáticamente en la tabla de domicilios.

La tercera de las tablas (evaluaciones) tiene como finalidad definir las distintas evaluaciones que puede realizarse a cada alumno. Tendrá dos campos. Uno descriptivo (el nombre de la evaluación) y otro identificativo (no nulo y único) que será tratado como PRIMARY KEY para evitar duplicidades y porque, además, va a ser utilizado como clave foránea en la tabla notas.

La tabla notas va a tener tres campos: DNI, nº de evaluación y calificación.

Estableceremos restricciones para evitar que:

* Podamos calificar a un alumno inexistente.
* Podamos calificar una evaluación no incluida entre las previstas.
* Podamos poner más a cada alumnos más de una calificación por evaluación.

Creando una índice primario formado por los campos DNI y evaluación evitaremos la última de las situaciones y añadiendo una vinculación con las tablas alumnos y evaluaciones estaremos en condiciones de evitar las dos primeras.

En este gráfico puedes ver un esquema de la definición de estas tablas.


Importación y exportación de datos
Es esta una opción interesante por la posibilidad que ofrece de intercambiar datos entre diferentes fuentes y aplicaciones.

Importación de ficheros
MySQL permite insertar en sus tablas los contenidos de ficheros de texto. Para ello utiliza la sentencia que tienes al final y que detallaremos a continuación.

LOAD DATA INFILE
Es un contenido obligatorio que defina la opción de insertar datos desde un fichero externo.

nombre del fichero
Se incluye inmediatamente después de la anterior, es obligatorio y debe contener (entre comillas) la ruta, el nombre y la extensión del fichero que contiene los datos a insertar.

[REPLACE|IGNORE]
Es opcional. Si se omite se producirá un mensaje de error si el fichero contiene valores iguales a los contenidos en los campos de la tabla que no admiten duplicados. Con la opción REPLACE sustituiría los valores existentes en la tabla y con la opción IGNORE

INTO TABLE nombre
Tiene carácter obligatorio y debe incluir como nombre el de la tabla a la que se pretende agregar los registros.

FIELDS
Tiene carácter OPCIONAL y permite incluir especificaciones sobre cuales son los caracteres delimitadores de campos y los que indican el final del campo. Si se omite FIELDS no podrán incluirse los ENCLOSED BY ni TERMINATED BY de campo.

ENCLOSED BY
Permite espeficar (encerrados entre comillas) los caracteres delimitadores de los campos. Estos caracteres deberán encontrarse en el fichero original al principio y al final de los contenidos de cada uno de los campos (por ejemplo, si el carácter fueran comillas los campos deberían aparecer así en el fichero a importar algo como esto: "32.45"). Si se omite esta especificación (o se omite FIELDS) se entenderá que los campos no tienen caracteres delimitadores.

Cuando se incluyen como delimitadores de campo las comillas (dobles o sencillas) es necesario utilizar una sintaxis como esta: '\"' ó '\'' de forma que no quepa la ambigüedad de si se trata de un carácter o de las comillas de cierre de una cadena previamente abierta.

TERMINATED BY
Se comporta de forma similar al anterior.
Permite qué caracteres son usados en el fichero original como separadores de campos (indicador de final de campo). Si se omite, se interpretará con tal el carácter tabulador (\t).

El uso de esta opción no requiere que se especifique previamente ENCLOSED BY pero si necesita que se haya incluido FIELDS. LINES
Si el fichero de datos contiene caracteres (distintos de los valores por defecto) para señalar el comienzo de un registro, el final del mismo o ambos, debe incluirse este parámetro y, después de él, las especificaciones de esos valores correspondientes a:

STARTING BY
Permite especificar una carácter como indicador de comienzo de un registro. Si se omite o se especifica como '' se interpretará que no hay ningún carácter que señale en comienzo de línea.

TERMINATED BY
Es el indicador del final de un registro. Si se omite será considerado como un salto de línea (\n).

Exportación de ficheros
Se comporta de forma similar al supuesto anterior. Utiliza la sintaxis siguiente:

SELECT * INTO OUTFILE
Inicia la consulta de los campos especificados después de SELECT (si se indica * realiza la consulta sobre todos los campos y por el orden en el que fue creada la tabla) y redirige la salida a un fichero.

nombre del fichero
Es la ruta, nombre y extensión del fichero en el que serán almacenados los resultados de la consulta.

FIELDS
ENCLOSED BY
TERMINATED BY
LINES
STARTING BY
TERMINATED BY
Igual que ocurría en el caso de importación de datos, estos parámetros son opcionales. Si no se especifican se incluirán los valores por defecto.

FROM nombre
Su inclusión tiene carácter obligatorio. El valor de nombre ha de ser el de la tabla sobre la que se realiza la consulta.

¡Cuidado!

Al importar ficheros habrá de utilizarse el mismo formato con el que fueron creados tanto FIELDS como LINES.

Consultas usando JOIN
La claúsula JOIN es opción aplicable a consultas en tablas que tiene diversas opciones de uso. Iremos viéndolas de una en una. Todas ellas han de ir incluidas como parámetros de una consulta. Por tanto han de ir precedidas de:

SELECT *
o de
SELECT nom_tab.nom_cam,..
donde nom_tab es un nombre de tabla y nom_camp es el nombre del campo de esa tabla que pretendemos visualizar para esa consulta. Esta sintaxis es idéntica a la ya comentada en páginas anteriores cuando tratábamos de consultas en varias tablas.

Ahora veremos las diferentes posibilidades de uso de JOIN

FROM tbl1 JOIN tbl2
Suele definirse como el producto cartesiano de los elementos de la primera tabla (tbl1) por lo de la segunda (tbl2).

Dicho de una forma más vulgar, esta consulta devuelve con resultado una lista de cada uno de los registros de los registros de la primera tabla asociados sucesivamente con todos los correspondientes a la segunda. Es decir, aparecerá una línea conteniendo el primer registro de la primera tabla seguido del primero de la segunda. A continuación ese mismo registro de la primera tabla acompañado del segundo de la segunda tabla, y así, sucesivamente hasta acabar los registros de esa segunda tabla. En ese momento, repite el proceso con el segundo registro de la primera tabla y, nuevamente, todos los de la segunda. Así, sucesivamente, hasta llegar al último registro de la primera tabla asociado con el último de la segunda.

En total, devolverá un número de líneas igual al resultado de multiplicar el número de registros de la primera tabla por los de la segunda.

FROM tbl2 JOIN tbl1
Si permutamos la posición de las tablas, tal como indicamos aquí, obtendremos el mismo resultado que en el caso anterior pero, como es lógico pensar, con una ordenación diferente de los resultados.

FROM tbl2 JOIN tbl1 ON cond
El parámetro ON permite añadir una condición (cond)a la consulta de unión. Su comportamiento es idéntico al de WHERE en las consultas ya estudiadas y permite el uso de las mismas procedimientos de establecimiento de condiciones que aquel operador.

FROM tbl1 LEFT JOIN tbl2 ON cond
Cuando se incluye la cláusula LEFT delante de JOIN el resultado de la consulta es el siguiente:
– Devolvería cada uno los registros de la tabla especificada a la izquierda de LEFT JOIN -sin considerar las restricciones que puedan haberse establecido en las claúsulas ON para los valores de esa tabla– asociándolos con aquellos de la otra tabla que cumplan las condiciones establecidas en la claúsula ON. Si ningún registro de la segunda tabla cumpliera la condición devolvería valores nulos.

FROM tbl1 RIGHT JOIN tbl2 ON cond
Se comporta de forma similar al anterior. Ahora los posibles valores nulos serán asignados a la tabla indicada a la izquierde de RIGHT JOIN y se visualizarían todos los registros de la tabla indicada a la derecha.

JOIN múltiples
Tal como puedes observar en el ejemplo, es perfectamente factible utilizar conjuntamente varios JOIN, LEFT JOIN y RIGHT JOIN. Las diferentes uniones irán ejecutándose de izquierda a derecha (según el orden en el que estén incluidos en la sentencia) y el resultado del primero será utilizado para la segunda unión y así sucesivamente.

En cualquier caso, es posible alterar ese orden de ejecución estableciendo otras prioridades mediante paréntesis.

UNION de consultas
MySQL permite juntar en una sola salida los resultados de varias consultas. La sintaxis es la siguiente:

(SELECT ...)
UNION ALL
(SELECT ...)
UNION ALL
(SELECT ...)

Cada uno de los SELECT ha de ir encerrado entre paréntesis.

Estructura de tablas y relaciones


Para desarrollar los ejemplos de este capítulo vamos a crear las tablas, cuyas estructuras e interrelaciones que puedes ver en el código fuente siguiente:

<?
$base="ejemplos";
$c=mysql_connect ("localhost","pepe","pepa");
mysql_select_db ($base, $c);
###############################################
# Creación de la tabla nombres con indice primario DNI
# tabla de nombres con índice primario en DNI
###############################################
$crear="CREATE TABLE IF NOT EXISTS alumnos (";
$crear.="DNI CHAR(8) NOT NULL, ";
$crear.="Nombre VARCHAR (20) NOT NULL, ";
$crear.="Apellido1 VARCHAR (15) not null, ";
$crear.="Apellido2 VARCHAR (15) not null, ";
$crear.=" PRIMARY KEY(DNI) ";
$crear.=")";
$crear.=" Type=InnoDB";
if(mysql_query ($crear ,$c)){
print "tabla <b>nombres</b> creada<BR>";
}else{
print "ha habido un error al crear la tabla <b>alumnos</b><BR>";
}
###############################################
# Creación de la tabla direcciones
# tabla de nombres con índice único en DNI
# para evitar dos direcciones al mismo alumno
# y clave foránea nombres(DNI)
# para evitar direcciones no asociadas a un alumno
# concreto. Se activa la opción de actualizar
# en cascada y de borrar en cascada
###############################################
$crear="CREATE TABLE IF NOT EXISTS domicilios (";
$crear.="DNI CHAR(8) NOT NULL, ";
$crear.="calle VARCHAR (20), ";
$crear.="poblacion VARCHAR (20), ";
$crear.="distrito VARCHAR(5), ";
$crear.=" UNIQUE identidad (DNI), ";
$crear.="FOREIGN KEY (DNI) REFERENCES alumnos(DNI) ";
$crear.="ON DELETE CASCADE ";
$crear.="ON UPDATE CASCADE ";
$crear.=") TYPE = INNODB";
if(mysql_query ($crear ,$c)){
print "tabla <b>domicilios</b> creada<br>";
}else{
print "ha habido un error al crear la tabla <b>domicilios</b><BR>";
}
###############################################
# Creación de la tabla nombres con indice primario EVALUACIONES
# tabla de nombres con índice primario en NUMERO
###############################################
$crear="CREATE TABLE IF NOT EXISTS evaluaciones (";
$crear.="NUMERO CHAR(1) NOT NULL, ";
$crear.="nombre_evaluacion VARCHAR (20) NOT NULL, ";
$crear.=" PRIMARY KEY(NUMERO)";
$crear.=")";
$crear.=" Type=InnoDB";
if(mysql_query ($crear ,$c)){
print "tabla <b>evaluaciones</b> creada<BR>";
}else{
print "ha habido un error al crear la tabla <b>evaluaciones</b><BR>";
}
###############################################
# Creación de la tabla notas
# indice UNICO para los campos DNI y evaluacion
# con ello se impide calificar dos veces al mismo
# alumno en la misma evaluacion
# claves foráneas (DOS)
# el DNI de nombres para evitar calificar a alumnos inexistentes
# el NUMERO de la tabla evaluaciones para evitar calificar
# DOS VECES en una evaluación a un alumno
###############################################
$crear="CREATE TABLE IF NOT EXISTS notas (";
$crear.="DNI CHAR(8) NOT NULL, ";
$crear.="evaluacion CHAR (1) NOT NULL, ";
$crear.="calificacion TINYINT (2), ";
/* observa que este indice primario está formado
por dos campos (DNI y evalucion) y que, como siempre
en el caso de PRIMARY KEY ambos son de tipo NOT NULL */
$crear.=" PRIMARY KEY vemaos(DNI,evaluacion), ";
/* Fijate en la secuencia siguiente:
1º.- Creamos el índice
2º.- Establecemos la clave foránea
3º.- Establecemo las condiciones ON DELETE
4º.- Establecemos las condiciones ON UPDTE
Es muy importe mantener esta secuencia para evitar
errores MySQL */
$crear.=" INDEX identico (DNI), ";
$crear.="FOREIGN KEY (DNI) REFERENCES alumnos(DNI) ";
$crear.="ON DELETE CASCADE ";
$crear.="ON UPDATE CASCADE,";
/* Esta tabla tiene dos claves foráneas asociadas a dos tablas
la anterior definida sobre alumnos como tabla principal
y esta que incluimos a continuación asociada con evaluaciones
Como ves repetimos la secuencia descrita anteriormente
Es importante establecer estas definiciones de una en una
(tal como ves en este ejemplo) y seguir la secuencia
comentada anteriormente */
$crear.=" INDEX evalua (evaluacion),";
$crear.="FOREIGN KEY (evaluacion) REFERENCES evaluaciones(NUMERO) ";
$crear.="ON DELETE CASCADE ";
$crear.="ON UPDATE CASCADE";
$crear.=") TYPE = INNODB";
if(mysql_query ($crear ,$c)){
print "tabla <b>notas</b> creada <BR>";
}else{
print "ha habido un error al crear la tabla <b>notas</b><BR>";
echo mysql_error ($c)."<br>";
echo mysql_errno ($c);
}

mysql_close();
?>

Crear tablas ejemplo



Como puedes observar en la imagen del inicio, al definir la estructura de las tablas es muy importante prestar atención a que los campos vinculados sean del mismo tipo y dimensión.


Observa también que los campos de referencia de los vínculos que se establecen (en las tablas primarias) tienen que ser definidos como PRIMARY KEY y que, por tanto, han de establecerse como no nulos (NOT NULL).


Inserción de datos en tablas


MySQL permite importar ficheros externos utilizando la siguiente sintaxis:


LOAD DATA INFILE "nombre del fichero'
[REPLACE | IGNORE]

INTO TABLE nombre de la tabla

FIELDS
TERMINATED BY 'indicador de final de campo'

ENCLOSED BY 'caracteres delimitadores de campos'

LINES
STARTING BY 'caracteres indicadores de comienzo de registro'

TERMINATED BY 'caracteres indicadores del final de registro'



En este ejemplo pueder un caso práctico de inserción de datos en las tablas creadas anteriormente.


<?
$base="ejemplos";
$c=mysql_connect ("localhost","pepe","pepa");
mysql_select_db ($base, $c);
# hemos creado un fichero de texto (datos_alumnos.txt)
# que contiene datos de algunos alumnos. Los diferentes
# campos están entre comillas y separados unos de otros
# mediante un punto y coma.
# Cada uno de los registros comienza por un asterios
# y los registros están separados por un salto de línes (\r\n)
# Incluimos estás especificaciones en la sentencia de inserción
if(mysql_query("LOAD DATA INFILE
'c:/Apache/htdocs/cursoPHP/datos_alumnos.txt' REPLACE
INTO TABLE alumnos
FIELDS ENCLOSED BY '\"' TERMINATED BY ';'
LINES STARTING BY '*' TERMINATED BY '\r\n' ",$c)){
print "Datos de alumnos cargados<br>";
}else{
echo mysql_error ($c)."<br>";
echo mysql_errno ($c);
}
# Para esta tabla usaremos el fichero datos_evaluaciones.txt
# Los diferentes
# campos están entre comillas y separados unos de otros
# mediante una coma.
# Cada uno de los registros comienza por un espacio
# y los registros están separados por un salto de línes (\r\n)
# Incluimos estás especificaciones en la sentencia de inserción
if(mysql_query("LOAD DATA INFILE
'c:/Apache/htdocs/cursoPHP/datos_evaluaciones.txt' REPLACE
INTO TABLE evaluaciones
FIELDS ENCLOSED BY '\'' TERMINATED BY ','
LINES STARTING BY ' ' TERMINATED BY '\r\n' ",$c)){
print "Datos de evaluaciones cargados<br>";
}else{
echo mysql_error ($c)."<br>";
echo mysql_errno ($c);
}
/* En este caso no incluimos especificación alguna.
Bajo este suspuesto MySQL interpreta los valores por defecto
que son: los campos no van encerrados, las líneas no tienen
ningún carácter indicador de comienzo, los campos están separados
mediante tabulaciones (carácter de escape \t) y el final de línea
está señalado por un caracter de nueva línea (\n) */
if(mysql_query("LOAD DATA INFILE
'c:/Apache/htdocs/cursoPHP/datos_notas.txt' IGNORE
INTO TABLE notas",$c)){
print "Datos de notas cargados<br>";
}else{
echo mysql_error ($c)."<br>";
echo mysql_errno ($c);
}
/* Se comporta como los casos anteriores con distincos caracteres
para los diferentes eventos, tal como puedes ver en el código */
if(mysql_query("LOAD DATA INFILE
'c:/Apache/htdocs/cursoPHP/datos_domicilios.txt' IGNORE
INTO TABLE domicilios
FIELDS ENCLOSED BY '|' TERMINATED BY '*'
LINES STARTING BY '#' TERMINATED BY '}' ",$c)){
print "Datos de domicilios cargados<br>";
}else{
echo mysql_error ($c)."<br>";
echo mysql_errno ($c);
}mysql_close();
?>





Guardar datos en ficheros


MySQL permite los contenidos de sus tablas a ficheros de texto. Para ello utiliza la siguiente sintaxis:


SELECT * INTO OUTFILE "nombre del fichero'


FIELDS
TERMINATED BY 'indicador de final de campo'

ENCLOSED BY 'caracteres delimitadores de campos'

LINES
STARTING BY 'caracteres indicadores de comienzo de registro'

TERMINATED BY 'caracteres indicadores del final de registro'

FROM nombre de la tabla

<?
$base="ejemplos";
$c=mysql_connect ("localhost","pepe","pepa");
mysql_select_db ($base, $c);
if(mysql_query ("SELECT * INTO OUTFILE
'c:/Apache/htdocs/cursoPHP/alumnos.txt'
FIELDS ENCLOSED BY '\"' TERMINATED BY ';'
LINES STARTING BY '*' TERMINATED BY '\r\n'
FROM alumnos",$c)){
print "fichero alumnos.txt creado<br>";
}else{
echo mysql_error ($c)."<br>";
echo mysql_errno ($c);
}
if(mysql_query ("SELECT * INTO OUTFILE
'c:/Apache/htdocs/cursoPHP/domicilios.txt'
FIELDS ENCLOSED BY '|' TERMINATED BY '*'
LINES STARTING BY '#' TERMINATED BY '}'
FROM domicilios",$c)){
print "fichero domicilios.txt creado<br>";
}else{
echo mysql_error ($c)."<br>";
echo mysql_errno ($c);
}
if(mysql_query ("SELECT * INTO OUTFILE
'c:/Apache/htdocs/cursoPHP/notas.txt'
FROM notas",$c)){
print "fichero notas.txt creado<br>";
}else{
echo mysql_error ($c)."<br>";
echo mysql_errno ($c);
}
if(mysql_query ("SELECT * INTO OUTFILE
'c:/Apache/htdocs/cursoPHP/evaluaciones.txt'
FIELDS ENCLOSED BY '\'' TERMINATED BY ','
LINES STARTING BY ' ' TERMINATED BY '\r\n'
FROM evaluaciones",$c)){
print "fichero evaluaciones.txt creado<br>";
}else{
echo mysql_error ($c)."<br>";
echo mysql_errno ($c);
}
mysql_close();
?>






Al exportar ficheros en entornos Windows, si se pretende que en el fichero de texto aparezca un salto de línea no basta con utilizar la opción por defecto de LINES TERMINATED BY '\n' sino LINES TERMINATED BY '\r\n' (salto de línea y retorno) que son los caracteres que necesita Windows para producir ese efecto.

Habrá de seguirse este mismo criterio cuando se trata de importar datos desde un fichero de texto.

Consultas de unión (JOIN)

<?
$base="ejemplos";
$c=mysql_connect ("localhost","pepe","pepa");
mysql_select_db ($base, $c);
# vamos a crear un array con las diferente consultas
# posteriormente lo leeremos y la ejecutaremos secuencialmente
/* Devuelve todos los campos de ambas tablas.
Cada registro de alumnos es asociado con todos los de domicilios*/
$query[]="SELECT * FROM alumnos JOIN domicilios";
/* Devuelve todos los campos de ambas tablas. Cada registro de domicilios
es asociado con todos los de alumnos */
$query[]="SELECT * FROM domicilios JOIN alumnos";
/* Devuelve todos los campos de los registros de ambas tablas
en los que coinciden los numeros del DNI*/
$query[]="SELECT * FROM alumnos JOIN domicilios
ON domicilios.DNI=alumnos.DNI";
/* Idéntica a la anterior. Solo se diferencia en que ahora
se visualizan antes los campos domicilios*/
$query[]="SELECT * FROM domicilios JOIN alumnos
ON domicilios.DNI=alumnos.DNI";
/* devuelve cada uno de los registro de la tabla alumnos. Si existe
un domicilio con igual DNI lo insertará. Si no existiera
insertará valores nulos en esos campos
$query[]="SELECT * FROM alumnos LEFT JOIN domicilios
ON domicilios.DNI=alumnos.DNI";
/* Se comporta de forma idéntica al anterior.
Ahora insertará todos los registros de domicilios
y los alumnos coincidentes o en su defecto campos nulos.*/
$query[]="SELECT * FROM domicilios LEFT JOIN alumnos
ON domicilios.DNI=alumnos.DNI";
/* Al utilizar RIGHT será todos los registros de la tabla de la derecha
(domicilios) los que aparezcan junto con las coincidencias o
junto a campos nulos. Aparecerán primero los campos de alumnos
y detrá los de domicilios*/
$query[]="SELECT * FROM alumnos RIGHT JOIN domicilios
ON (domicilios.DNI=alumnos.DNI AND alumnos.Nombre LIKE 'A%')";
/* Consulta de nombre, apellido y localidad de todos los alumnos
cuyo nombre empieza por A */
$query[]="SELECT alumnos.Nombre, alumnos.Apellido1,alumnos.Apellido2,
domicilios.poblacion FROM alumnos JOIN domicilios
ON (domicilios.DNI=alumnos.DNI
AND alumnos.Nombre LIKE 'A%')";
# una consulta resumen de nos permitirá visualizar una lista con nombre
# y apellidos de alumnos su dirección y localidad del domicilio
# el nombre de la evaluación y su calificación.
# Si no hay datos de población insertará ---- en vez del valor nulo
# y si no hay calificación en una evaluación aparecerá N.P.
# La consulta aparecerá agrupada por evaluaciones
/* iniciamos el select especificando los campos de las diferentes
tablas que prentendemos visualizar
$q="(SELECT alumnos.Nombre,alumnos.Apellido1,";
$q.=" alumnos.Apellido2,domicilios.calle,";
# al incluir IFNULL visualizaremos ---- en los campos cuyo resultado
# sea nulo
$q.=" IFNULL(domicilios.poblacion,'––––'),";
$q.=" evaluaciones.nombre_evaluacion,";
# con este IFNULL aparecerá N.P. en las evaluaciones no calificadas.
$q.=" IFNULL(notas.calificacion,'N.P.')";
# especificamos el primer JOIN con el que tendremos como resultado una lista
# de todos los alumnos con sus direcciones correspondientes
# por efecto de la clausula ON.
# Al poner LEFT se incluirían los alumnos que no tuvieran
# su dirección registrada en la tabla de direccione
$q.=" FROM (alumnos LEFT JOIN domicilios";
$q.=" ON alumnos.DNI=domicilios.DNI)";
# al unir por la izquierda con notas tendríamos todos los resultados
# del JOIN anterior asociados con con todas sus calificaciones
# por efecto de la claúsula ON
$q.=" LEFT JOIN notas ON notas.DNI=alumnos.DNI";
# al añadir esta nueva unión por la DERECHA con la tabla evaluaciones
# se asociaría cada uno de los resultados de las uniones anteriores
# con todos los campos de la tabla evaluaciones con lo que resultaría
# una lista de todos los alumnos con todas las calificaciones
# incluyendo un campo en blanco (sería sustituido por N.P:)
# en aquellas que no tuvieran calificación registrada
$q.=" RIGHT JOIN evaluaciones";
$q.=" ON evaluaciones.NUMERO=notas.evaluacion";
/* la clausula WHERE nos permite restringir los resultados a los valores
correspondientes únicamente a la evaluación número 1*/
$q.=" WHERE evaluaciones.NUMERO=1)";
# cerramos la consulta anterior con el paréntesis. Observa que lo
# hemos abierto delante del SELECT e insertamos UNION ALL
# para que el resultado de la consulta anterior aparezca
# seguido del correspondiente a la incluida después de UNION ALL
$q.=" UNION ALL";
#iniciamos (también con paréntesis) la segunda consulta
# que será identica a la anterior salvo el WHERE
# será modificado para extraer datos de la evaluación nº2
$q.="(SELECT alumnos.Nombre,alumnos.Apellido1,";
$q.=" alumnos.Apellido2,domicilios.calle,";
$q.=" IFNULL(domicilios.poblacion,'––––'),";
$q.=" evaluaciones.nombre_evaluacion,";
$q.=" IFNULL(notas.calificacion,'N.P.')";
$q.=" FROM (alumnos LEFT JOIN domicilios";
$q.=" ON alumnos.DNI=domicilios.DNI)";
$q.=" LEFT JOIN notas ON notas.DNI=alumnos.DNI";
$q.=" RIGHT JOIN evaluaciones";
$q.=" ON evaluaciones.NUMERO=notas.evaluacion";
$q.=" WHERE evaluaciones.NUMERO=2)";
# hemos cerrado el parentesis de la consulta anterior
# e incluimos un nuevo UNION ALL para consultar los datos
# correspondientes a la tercera evaluación
$q.=" UNION ALL";
$q.="(SELECT alumnos.Nombre,alumnos.Apellido1,";
$q.=" alumnos.Apellido2,domicilios.calle,";
$q.=" IFNULL(domicilios.poblacion,'––––'),";
$q.=" evaluaciones.nombre_evaluacion,";
$q.=" IFNULL(notas.calificacion,'N.P.')";
$q.=" FROM (alumnos LEFT JOIN domicilios";
$q.=" ON alumnos.DNI=domicilios.DNI)";
$q.=" LEFT JOIN notas ON notas.DNI=alumnos.DNI";
$q.=" RIGHT JOIN evaluaciones";
$q.=" ON evaluaciones.NUMERO=notas.evaluacion";
$q.=" WHERE evaluaciones.NUMERO=3)";
# incluimos la variable $q en el array de consultas
$query[]=$q;
# leemos el array y visualizamos el resultado
# cada consulta a traves de la llamada a la funcion visualiza
# a la que pasamos el resultado de la consulta
# y la cadena que contiene las sentencias de dicha consulta
foreach($query as $v){
visualiza(mysql_query($v,$c),$v);
}
function visualiza($resultado,$query){
PRINT "<BR><BR><i>Resultado de la sentencia:</i><br>";
print "<b><font color=#ff0000>";
print $query."</font></b><br><br>";
PRINT "<table align=center border=2>";
while ($registro = mysql_fetch_row($resultado)){
echo "<tr>";
foreach($registro as $valor){
echo "<td>",$valor,"</td>";
}
}
echo "</table><br>";
}




Fuente:

Página del ifstic: http://www.isftic.mepsyd.es/formacion/enred/

miércoles, 29 de abril de 2009

Manual de PHP 79. MySQL: Tablas InnoDB

Tipos de tablas

Aunque en los temas anteriores no hemos hecho alusión a ello, MySQL permite usar diferentes tipos de tablas tales como:
  • ISAM
  • MyISAM
  • InnoDB
Las tablas ISAM son las de formato más antiguo. Están limitadas a tamaños que no superen los 4 gigas y no permite copiar tablas entre máquinas con distinto sistema operativo.

Las tablas MySAM son el resultado de la evolución de las anteriores, ya que resuelven el problema que planteaban las anteriores y son el formato por defecto de MySQL a partir de su versión 3.23.

Las tablas del tipo InnoDB tienen una estructura distinta que MyISAM, ya que utilizan un sólo archivo por tabla en ver de los tres habituales en los tipos anteriores.

Incorporan un par de ventajas importantes, ya que permiten realizar transacciones y definir reglas de integridad referencial.


Creación y uso de tablas InnoDB


La creación de tablas de este tipo no presenta ninguna dificultad añadida. El proceso es idéntico a las tablas habituales sin más que añadir Type=InnoDB después de cerrar el paréntesis de la sentencia de creación de la tabla.

Una vez creadas, las tablas InnoDB se comportan –a efectos de uso– exactamente igual que las que hemos venido utilizando en las páginas anteriores. No es preciso hacer ningún tipo de modificación en la sintaxis. Por tanto, es totalmente válido todo lo ya comentado respecto a: altas, modificaciones, consultas y bajas.

Las transacciones


Uno de los riesgos que se plantean en la gestión de bases de datos es que pueda producirse una interrupción del proceso mientras se está actualizando una o varias tablas. Pongamos como ejemplo el cobro de nuestra nómina. Son necesarias dos anotaciones simultáneas: ll cargo en la cuenta del Organismo pagador y el abono en nuestra cuenta bancaria. Si se interrumpiera fortuitamente el proceso en el intermedio de las dos operaciones podría darse la circunstancia de que apareciera registrado el pago sin que se llegaran a anotar los haberes en nuestra cuenta.

Las transacciones evitan este tipo de situaciones ya que los registros de los datos se registran de manera provisional y no toman carácter definitivo hasta que una instrucción confirme que esas anotaciones tienen carácter definitivo. Para ello, MySQL dispone de tres sentencias: BEGIN, COMMIT y ROLLBACK.

Sintaxis de las transacciones

Existen tres sentencias para gestionar las transacciones. Son las siguientes:

mysql_query("BEGIN",$c)

Su ejecución requiere que este activa la conexión $c con el servidor de base de datos e indica a MySQL que comienza una transacción.

Todas las sentencias que se ejecuten a partir de ella tendrán carácter provisional y no se ejecutarán de forma efectiva hasta que encuentre una sentencia de finalización.

mysql_query("ROLLBACK",$c)

Mediante esta sentencia advertimos a MySQL que finaliza la transacción pero que no debe hacerse efectiva ninguna de las modificaciones incluidas en ella.

mysql_query("COMMIT",$c)

Esta sentencia advierte a MySQL que ha finalizado la transacción y que debe hacer efectivos todos los cambios incluidos en ella.


Precauciones a tener en cuenta

Cuando se utilizan campos autoincrementales en tablas InnoDB los contadores se van incrementando al añadir registros (incluso de forma provisional) con lo cual si se aborta la inclusión con un ROLLBACK ese contador mantiene el incremento y en inserciones posteriores partirá de ese valor acumulado.

Por ejemplo. Si partimos de una tabla vacía y hacemos una transacción de dos registros (número 1 y número 2 en el campo autoincremental) y la finalizamos con ROLLBACK, no se insertarán pero en una inserción posterior el contador autoincremental comenzará a partir del valor 2.

MySQL anuncia que a partir de la versión 5.0.3 se incluirá una nueva sentencia para permitir que se puedan renumerar los campos autoincrementales.

Elementos necesarios para la integridad referencial

La integridad referencial ha de establecerse siempre entre dos tablas. Una de ellas ha de comportarse como tabla principal (suele llamarse tabla padre y la otra sería la tabla vinculada ó tabla hijo.

Es imprescindible:
  • Que la tabla principal tenga un índice primario (PRIMARY KEY)
  • Que la tabla vinculada tenga un índice (no es necesario que sea ni único ni primario) asociado a campos de tipo idéntico a los que se usen para índice de la tabla principal. -es decir, puede ser simplemente INDEX.
  • Si observas el código fuente del ejemplo que tienes a la derecha podrás observar que utilizamos el número del DNI (único para alumno) como elemento de vinculación de la tabla de datos personales con la que incluye las direcciones.
Borrado de tablas vinculadas

Si pretendemos eliminar una tabla principal recibiremos un mensaje de error tal como puedes ver si ejecutas este ejemplo cuyo código fuente tienes aquí. cómo es lógico, antes de ejecutarlo habrás de tener creada la tabla cuyo código fuente tienes a la derecha.

Las tablas vinculadas si permiten el borrado y una vez que éstas ya han sido eliminadas (o quitada la vinculación) ya podrán borrarse sin problemas las tablas principales. Si ejecutas este ejemplo podrás observar que borramos ambas tablas siguiendo el orden que permite hacerlo. Primero se borra la vinculada y luego la principal. Este es el código fuente del script:


<?

$base="ejemplos";

$tabla="principal";

$tabla1="vinculada";

$c=mysql_connect ("localhost","pepe","pepa");

mysql_select_db ($base, $c);

# borramos primero la tabla vinculada

if(mysql_query("DROP TABLE $tabla1",$c)){

echo "<h2> Tabla $tabla1 borrada con EXITO </h2><br>";

}else{

echo "<h2> La tabla $tabla1 NO HA PODIDO BORRARSE<br>";

echo "Se ha producido un error nº: ".mysql_errno ($c)."<br>";

echo "que es el siguiente: ".mysql_error ($c)."<br>";

};

# ahora ya podremos hacer lo mismo con la principal

if(mysql_query("DROP TABLE $tabla",$c)){

echo "<h2> Tabla $tabla borrada con EXITO </h2><br>";

}else{

echo "<h2> La tabla $tabla NO HA PODIDO BORRARSE<br>";

echo "Se ha producido un error nº: ".mysql_errno ($c)."<br>";

echo "que es el siguiente: ".mysql_error ($c)."<br>";

};

mysql_close();

?>



¡Cuidado!

Si has borrado las tablas con los ejemplos anteriores no olvides crearlas de nuevo para poder visualizar los ejemplos siguientes.


Modificación o borrado de campos vinculados

Las sentencias MySQL que deban modificar o eliminar campos utilizados para establecer vínculos entre tablas requieren de un parámetro especial (CONSTRAINT) -puede ser distinto en cada una de las tablas- que es necesario conocer previamente.

La forma de visualizarlo es ejecutar la sentencia: SHOW CREATE TABLE nombre tabla que devuelve como resultado un array asociativo con dos índices. Uno de ellos -llamado Table- que contiene el nombre de la tabla y el otro -Create Table- que contiene la estructura con la que ha sido creada la tabla pero incluyendo el parámetro CONSTRAINT seguido de su valor. Ese valor es precisamente el que necesitamos para hacer modificaciones en los campos asociados de las tablas vinculadas.

Pulsando en este enlace cuyo código fuente tienes aquí:

<?

$base="ejemplos";

$tabla="principal";

$tabla1="vinculada";

$c=mysql_connect ("localhost","pepe","pepa");

mysql_select_db ($base, $c);



$resultado=mysql_query( "SHOW CREATE TABLE $tabla1",$c);

while($registro=mysql_fetch_array($resultado)){

foreach ($registro as $c=>$v){

Print "<i>Indice</i><b>: ".$c." </b><i>Valor</i>: ".$v."<br>";

}



}

mysql_close();

?>



podrás visualizar el resultado de la ejecución de esa sentencia.

Conocido el valor de parámetro anterior el proceso de borrado del vínculo actual requiere la siguiente sintaxis:

ALTER TABLE nombre de la tabla DROP FOREIGN KEY parametro

Cuando se trata de añadir un nuevo vínculo con una tabla principal habremos de utilizar la siguiente sentencia:

ALTER TABLE nombre de la tabla ADD [CONSTRAINT parametro] FOREIGN KEY parametro REFERENCES tabla principal(clave primaria)

El parámetro CONSTRAIT (encerrado en corchetes en el párrafo anterior) es OPCIONAL y solo habría de utilzarse en el caso de que existiera ya una vinculación previa de esa tabla.


La función preg_match

En el ejemplo de la derecha utilizamos esta función cuya sintaxis es la siguiente:
preg_match( pat, cad, coin )

donde pat es un patrón de búsqueda, cad es la cadena que la han de realizarse las búsquedas y coin es un arroay que recoge todas las coincidencias encontradas en la cadena.

El patrón de búsqueda que hemos utilizado en el ejemplo
/CONSTRAINT.*FOREIGN KEY/ debe interpretarse de la siguiente forma. Los caracteres / indican el comienzo y el final del patrón, el . indica que entre CONSTRAIT y FOREING se permite cualquer carácter para admitir la coincidencia y, además, * indica que ese caracter cualquier puede repetirse cero o más veces.

¡Cuidado!

Es posible que el script del final te de un error como consecuencia de que hemos podido modificar campos en los ejemplos anteriores. Si eso ocurre, borra aquí las tablas y genéralas de nuevo pulsando aquí.


¡Cuidado!

Los resultados que obtengas el ejecutar los ejemplos de borrado y modificación de datos pueden arrojar resultados distintos según los contenidos de las tablas que, a su vez, serán consecuencia de los ejemplos que hayas ejecutado anteriormente y de la secuencia de los mismos. Siempre puedes volver a las condiciones iniciales de los enlaces de la advertencia anterior.


Opciones adicionaes de FOREIGN KEY


La claúsula FOREIGN KEY permite añadirte -detrás de la definición ya comentada y sin poner coma separándola de ella- los parámetros ON DELETE y ON UPDATE en las que se permite especificar una de las siguientes opciones:

ON DELETE RESTRICT
Esta condición (es la condición por defecto de MySQL y no es preciso escribirla) indica a MySQL que interrumpa el proeceso de borrado y de un mensaje de error cuando se intente borrar un registro de la tabla principal cuando en la tabla vinculada existan registros asociados al valor que se pretende borrar.

ON DELETE NO ACTION
Es un sinónimo de la anterior.

ON DELETE CASCADE
Cuando se especifica esta opción, al borrar un registro de la tabla principal se borrarán de forma automática todos los de la tabla vinculada que estuvieran asociados al valor de la clave foránea que se trata de borrar. Con ello se conseguiría una actualización automática de la segunda tabla y se mantendría la identidad referencial.

ON DELETE SET NULL
Con esta opción, al borrar el registro de la tabla principal no se borrarían los que tuviera asociados la tabla secundaria pero tomarían valor NULL todos los índices de ella coincidentes con la clave primaria de la tabla principal.

Para el caso de ON UPDATE las opciones son estas:

ON UPDATE RESTRICT
ON UPDATE CASCADE
ON UPDATE SET NULL

Su comportamiento es idéntico a sus homónimas del caso anterior.

¡Cuidado!

El uso de la opción SET NULL requiere que el campo indicado en FOREIGN KEY esté permita valores nulos. Si está definido con flag NOT NULL (como ocurre en los ejemplos que tienes al margen) daría un mensaje de error.


¡Cuidado!

Al incluir ON DELETE y ON UPTADE (si se incluyen ambas) han de hacerse por este mismo orden.
Si se cambiara este orden daría un mensaje de error y no se ejecutarían.


Creación de una tabla InnoDB


La creación de tablas tipo InnoDB requiere una de estas dos sentencias:


CREATE TABLE IF NOT EXISTS tabla (campo1, campo2,... ) Type=InnoDB


CREATE TABLE tabla (campo1, campo2,... ) Type=InnoDB


Este script crear una tabla InnoDB con idénticos campos a los utilizados en el caso de la tabla demo4 con la que hemos venido trabajando hasta ahora. La sintaxis, muy similar a la utilizada allí es esta:


$base="ejemplos";
$tabla="demoINNO";
$c=mysql_connect ("localhost","pepe","pepa");
mysql_select_db ($base, $c);

$crear="CREATE TABLE $tabla (";
$crear.="Contador TINYINT(8) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT,";
$crear.="DNI CHAR(8) NOT NULL, ";
$crear.="Nombre VARCHAR (20) NOT NULL, ";
$crear.="Apellido1 VARCHAR (15) not null, ";
$crear.="Apellido2 VARCHAR (15) not null, ";
$crear.="Nacimiento DATE DEFAULT '1970-12-21', ";
$crear.="Hora TIME DEFAULT '00:00:00', ";
$crear.="Sexo Enum('M','F') DEFAULT 'M' not null, ";
$crear.="Fumador CHAR(0) , ";
$crear.="Idiomas SET(' Castellano',' Francés','Inglés',
' Alemán',' Búlgaro',' Chino'), ";
$crear.=" PRIMARY KEY(DNI), ";
$crear.=" UNIQUE auto (Contador)";
$crear.=")";
# esta es la única diferencia con el proceso de
# creación de tablas MyISAM
$crear.=" Type=InnoDB";

if(mysql_query ($crear ,$c)) {
echo "<h2> Tabla $tabla creada con EXITO </h2><br>";
}else{
echo "<h2> La tabla $tabla NO HA PODIDO CREARSE ";
# echo mysql_error ($c)."<br>";
$numerror=mysql_errno ($c);
if ($numerror==1050){echo "porque YA EXISTE</h2>";}
};
mysql_close($c);
?>

Crear tabla InnoDB




Bajo Windows, al crear una base de datos o tabla InnoDB el nombre de la misma aparecerá en minúsculas independientemente de la sintaxis que hayamos utilizado en su creación.

Si observas el ejemplo anterior, hemos puesto demoINNO como nombre de la tabla. Sin embargo, si miras el directorio c:\mysql verás que aparece el fichero demoinno.frm con minúsculas.



Las primeras transacciones

<?
$base="ejemplos";
# escribimos el nombre de la tabla en MINUSCULAS
# para asegurar la compatibilidad entre plataformas
$tabla="demoinno";
$conexion=mysql_connect("localhost","pepe","pepa");
mysql_select_db ($base, $conexion);
# insertamos la sentencia BEGIN para indicar el comienzo
# de una transacción
mysql_query("BEGIN",$conexion);
/* hasta que no aparezca una sentencia que finalice la transacción
(ROLLBACK ó COMMIT) las modificaciones en la tabla serán registradas
de forma "provisional") */
mysql_query("INSERT $tabla (DNI,Nombre,Apellido1,Apellido2,
Nacimiento,Sexo,Hora,Fumador,Idiomas)
VALUES
('111111','Alvaro','Alonso','Azcárate','1954-11-23',
'M','16:24:52',NULL,3)",$conexion);
if (mysql_errno($conexion)==0){
echo "Registro AÑADIDO<br>";
}else{
if (mysql_errno($conexion)==1062){
echo "No ha podido añadirse el registro <br>";
echo "Ya existe un registro con este DNI<br>";
}else{
$numerror=mysql_errno($conexion);
$descrerror=mysql_error($conexion);
echo "Se ha producido un error nº $numerror<br>";
echo "<br>que corresponde a: $descrerror<br>";
}
}
# indicamos el final de la transacción, en este caso con ROLLBACK
# por lo tanto el registro con DNI 111111 no será insertado en la tabla
mysql_query("ROLLBACK",$conexion);
# incluyamos una nueva transacción
mysql_query("BEGIN",$conexion);
mysql_query("INSERT $tabla (DNI,Nombre,Apellido1,Apellido2,
Nacimiento,Sexo,Hora,Fumador,Idiomas)
VALUES
('222222','Genoveva','Zarabozo','Zitrón','1964-01-14',
'F','16:18:20',NULL,2)",$conexion);
if (mysql_errno($conexion)==0){
echo "Registro AÑADIDO";
}else{
if (mysql_errno($conexion)==1062){
echo "No ha podido añadirse el registro <br>";
echo "Ya existe un registro con este DNI";
}else{
$numerror=mysql_errno($conexion);
$descrerror=mysql_error($conexion);
echo "Se ha producido un error nº $numerror";
echo "<br>que corresponde a: $descrerror";
}
}
# indicamos el final de la transacción, en este caso con COMMIT
# por lo tanto el registro con DNI 222222 si será insertado en la tabla
mysql_query("COMMIT",$conexion);
# leamos el contenido de la tabla para ver el resultado
$resultado= mysql_query("SELECT * FROM $tabla" ,$conexion);
print "<br>Lectura de la tabla depués del commit<br>";
while ($registro = mysql_fetch_row($resultado)){
foreach($registro as $clave){
echo $clave,"<br>";
}
}
mysql_close();
?>


ejemplo236.php

Ejecutar el ejemplo


Integridad referencial en tablas InnoDB


Cuando se trabaja con varias tablas que tienen algún tipo de vínculo resulta interesante disponer de mecanismos que protejan o impidan acciones no deseadas. Supongamos, como veremos en los ejemplos posteriores que pretendemos utilizar una tabla con datos de alumnos y otra tabla distinta para las calificaciones de esos alumnos. Si no tomamos ninguna precaución (bien sea mediante los script o mediante el diseño de las tablas) podría darse la circunstancia de que incluyéramos calificaciones a alumnos inexistentes, en materias de las que no están matriculados, etcétera. También podría darse la circunstancia de que diéramos de baja a un alumno pero que se mantuvieran las calificaciones vinculadas a él. Todas estas circunstancias suelen producir efectos indeseados y las tablas InnoDB pueden ser diseñadas para prever este tipo de situaciones.


Sintaxis para la vinculación de tablas


Los vínculos entre tablas suelen establecer en el momento de la creación de la tabla vinculada.


CREATE TABLE tabla (campo1, campo2,...

KEY nombre (campo de vinculacion ),

FOREIGN KEY (campo de vinculacion)
REFERENCES nombre_de la tabla principal (Indice primario de la tabla principal)

) Type=InnoDB

si el campo nombre no fuera la clave principal tendríamos que emplear, por ejemplo

CREATE TABLE tabla (campo1, campo2,...

PRIMARY KEY nombre (campos clave de la tabla),

INDEX nombre (campo de vinculacion ),

FOREIGN KEY (campo de vinculacion)
REFERENCES nombre_de la tabla principal (Indice primario de la tabla principal)

) Type=InnoDB

donde el campo de vinculacion ha de ser un índice (no es necesario que sea PRIMARY KEY ni UNIQUE) y donde Indice primario de la tabla principal ha de ser un índice primario (PRIMARY KEY) de la tabla principal. Debe haber plena coincidencia (tanto en tipos como contenidos) entre ambos índices.

<?
$base="ejemplos";
$tabla1="principal";
$tabla2="vinculada";
$c=mysql_connect ("localhost","pepe","pepa");
mysql_select_db ($base, $c);
# creación de la tabla principal type InnoDB
$crear="CREATE TABLE IF NOT EXISTS $tabla1 (";
$crear.="DNI CHAR(8) NOT NULL, ";
$crear.="Nombre VARCHAR (20) NOT NULL, ";
$crear.="Apellido1 VARCHAR (15) not null, ";
$crear.="Apellido2 VARCHAR (15) not null, ";
# el indice primario es imprescindible. Recuerda que debe
# estar definido sobre campos NO NULOS
$crear.=" PRIMARY KEY(DNI) ";
$crear.=")";
$crear.=" Type=InnoDB";
# creamos la tabla principal comprobando el resultado
if(@mysql_query ($crear ,$c)){
print "La tabla ".$tabla1." ha sido creada<br>";
}else{
print "No se ha creado ".$tabla1." ha habido un error<br>";
}
# crearemos la tabla vinculada
$crear="CREATE TABLE IF NOT EXISTS $tabla2 (";
$crear.="IDENTIDAD CHAR(8) NOT NULL, ";
$crear.="calle VARCHAR (20), ";
$crear.="poblacion VARCHAR (20), ";
$crear.="distrito VARCHAR(5), ";
# creamos el índice (lo llamamos asociador) para la vinculación
# en este caso no será ni primario ni único
# Observa que el campo IDENTIDAD de esta tabla CHAR(8)
# es idéntico al campo DNI de la tabla principal
$crear.=" KEY asociador(IDENTIDAD), ";
#establecemos la vinculación de ambos índices
$crear.=" FOREIGN KEY (IDENTIDAD) REFERENCES $tabla1(DNI) ";
$crear.=") TYPE = INNODB";
# creamos (y comprobamos la creación) la tabla vinculada
if(@mysql_query ($crear ,$c)){
print "La tabla ".$tabla2." ha sido creada<br>";
}else{
print "No se ha creado ".$tabla2." ha habido un error<br>";
}
mysql_close();
?>


ejemplo239.php

Crear tablas vinculadas


Modificación de estructuras


La modificación de estructuras en tablas vinculadas puede hacerse de forma idéntica a la estudiada para los casos generales de MySQL siempre que esas modificaciones no afecten a los campos mediante los que se establecen las vinculaciones entre tablas.


Aquí tienes un ejemplo en se borran y añaden campos en ambas tablas. Como puedes ver la sintaxis es exactamente la misma que utilizamos en temas anteriores.

<?
$base="ejemplos";
$tabla="principal";
$tabla1="vinculada";
$c=mysql_connect ("localhost","pepe","pepa");
mysql_select_db ($base, $c);

if(mysql_query("ALTER TABLE $tabla ADD Segundo_Apellido VARCHAR(40)",$c)){
print "Sea ha creado el nuevo campo en ".$tabla."<br>";
}
if(mysql_query("ALTER TABLE $tabla DROP Apellido2",$c)){
print "Sea ha borrado el campo Apellido 2 en ".$tabla."<br>";
}

if(mysql_query("ALTER TABLE $tabla1 ADD DP VARCHAR(5)",$c)){
print "Sea ha creado el nuevo campo en ".$tabla1."<br>";
}
if(mysql_query("ALTER TABLE $tabla1 DROP distrito",$c)){
print "Sea ha borrado el campo distrito en ".$tabla1."<br>";
}

mysql_close();
?>


ejemplo242.php

ejecutar el ejemplo



En este otro ejemplo determinaremos el valor de CONSTRAINT y modificaremos campos asociados de la tabla vinculada.


$base="ejemplos";
$tabla="vinculada";
$tabla1="principal";
$c=mysql_connect ("localhost","pepe","pepa");
mysql_select_db ($base, $c);
$resultado=mysql_query( "SHOW CREATE TABLE $tabla",$c);
$v=mysql_fetch_array($resultado);
# extreamos de Create Table la cadena que empiza por CONSTRAINT
# y que acaba por FOREING KEY lo guardamos en el array $coin
preg_match ('/CONSTRAINT.*FOREIGN KEY/', $v['Create Table'], $coin);
# extraemos el parametro quitando el CONSTRAINT que lleva delante
# y el FOREIGN KEY que lleva al final
$para=str_replace("FOREIGN KEY",'',str_replace("CONSTRAINT",'',$coin[0]));
print "El valor de CONSTRAINT es: ".$para."&ltbr>";
# eliminamos el vinculo con la clave externa incluyendo en la sentancia
# el valor del parametro obtenido el proceso anterior
if(mysql_query("ALTER TABLE $tabla DROP FOREIGN KEY $para",$c)){
print "Se ha realizado con éxito el borrado del vínculo&ltbr>";
}
# añadimos el nuevo vínculo (en este caso rehacemos el anterior
# pero el proceso es idéntico)
if(mysql_query("ALTER TABLE $tabla ADD CONSTRAINT $para
FOREIGN KEY(IDENTIDAD) REFERENCES $tabla1(DNI)",$c)){
print "Se ha reestablecido con éxito vínculo&ltbr>";
}

mysql_close();
?>


ejemplo244.php

ejecutar el ejemplo


Añadir registros a la tabla vinculada


Si ejecutas este ejemplo habiendo seguido la secuencia de estos materiales verás que se produce un error nº 1216. Es lógico que así sea porque estamos intentando añadir un registro a la tabla vinculada y ello requeriría que en el campo DNI de la tabla principal existiera un registro con un valor igual al que pretendemos introducir en la tabla vinculada.



ejemplo245.php

Ver script

Insertar en tabla vinculada


Añadiremos un registro a la tabla principal con el DNI anterior:

ejemplo245.php

Ver script

ejemplo246.php

Insertar en tabla principal


y ahora ya podremos ejecutar -sin errores- el script que inserta datos en la tabla vinculada. Podremos ejecutar aquel script tantas veces como queramos ya que -el campo IDENTIDAD está definido como KEY y por tanto permite duplicados- no hemos establecido la condición de índice PRIMARIO ó UNICO.


Borrar o modificar registros en la tabla principal


Sin intentamos borrar un registro de la tabla principal mediante un script como el que tienes en este ejemplo verás que se produce un error nº 1217 advirtiéndonos de que no se realiza el borrado porque existen registros en la tabla vinculada con valores asociados al índice del campo que pretendemos borrar y, de permitir hacerlo, se rompería la integridad referencial ya que quedarían registros huérfanos en la tabla vinculada.



ejemplo247.php

Ver script

ejemplo247.php

Borrar en tabla principal


Sin tratamos de modificar un registro de la tabla principal y la modificación afecta al índice que realiza la asociación con la tabla (o tablas) vinculadas se produciría -por las mismas razones y en las mismas circunstancias- un error nº 1217 que impediría la modificación.

ejemplo248.php

Ver script

ejemplo248.php

Modificar DNI en tabla principal


Si -al tratar de borrar o modificar un registro de la tabla principal– no existieran en la tabla (o tablas vinculadas) registros asociados con él, el proceso de modificación se realizaría sin ningún problema y sin dar ningún mensaje de error o advertencia.


Automatización de procesos


Creamos dos tablas idénticas a las anteriores incluyendo algunos datos en ellas.

<?
$base="ejemplos";
$tabla1="principal1";
$tabla2="vinculada1";
$c=mysql_connect ("localhost","pepe","pepa");
mysql_select_db ($base, $c);
# creación de la tabla principal type InnoDB
$crear="CREATE TABLE IF NOT EXISTS $tabla1 (";
$crear.="DNI CHAR(8) NOT NULL, ";
$crear.="Nombre VARCHAR (20) NOT NULL, ";
$crear.="Apellido1 VARCHAR (15) not null, ";
$crear.="Apellido2 VARCHAR (15) not null, ";
$crear.=" PRIMARY KEY(DNI) ";
$crear.=")";
$crear.=" Type=InnoDB";
# creamos la tabla principal comprobando el resultado
if(@mysql_query ($crear ,$c)){
print "La tabla ".$tabla1." ha sido creada<br>";
}else{
print "No se ha creado ".$tabla1." ha habido un error<br>";
}
# crearemos la tabla vinculada
$crear="CREATE TABLE IF NOT EXISTS $tabla2 (";
$crear.="IDENTIDAD CHAR(8) NOT NULL, ";
$crear.="calle VARCHAR (20), ";
$crear.="poblacion VARCHAR (20), ";
$crear.="distrito VARCHAR(5), ";
#creamos la tabla vinculada las opciones de DELETE y UPDATE
$crear.=" KEY asociador(IDENTIDAD), ";
#establecemos la vinculación de ambos índices
$crear.=" FOREIGN KEY (IDENTIDAD) REFERENCES $tabla1(DNI) ";
$crear.=" ON DELETE CASCADE ";
$crear.=" ON UPDATE CASCADE ";
$crear.=") TYPE = INNODB";
# creamos (y comprobamos la creación) la tabla vinculada
if(@mysql_query ($crear ,$c)){
print "La tabla ".$tabla2." ha sido creada<br>";
}else{
print "No se ha creado ".$tabla2." ha habido un error<br>";
}
# añadimos registros a la tabla principa1
mysql_query("INSERT $tabla1 (DNI,Nombre,Apellido1,Apellido2)
VALUES ('111111','Robustiano','Iglesias','Pérez')",$c);
mysql_query("INSERT $tabla1 (DNI,Nombre,Apellido1,Apellido2)
VALUES ('222222','Ambrosio','Morales','Gómez')",$c);
# añadimos registros a la tabla vinculada1
mysql_query("INSERT $tabla2 (IDENTIDAD,calle,poblacion,distrito)
VALUES ('111111','Calle Asturias,3','Oviedo','33001')",$c);
mysql_query("INSERT $tabla2 (IDENTIDAD,calle,poblacion,distrito)
VALUES ('111111','Calle Palencia,3','Logroño','78541')",$c);
mysql_query("INSERT $tabla2 (IDENTIDAD,calle,poblacion,distrito)
VALUES ('222222','Calle Anunciación,3','Algeciras','21541')",$c);
mysql_close();
?>


ejemplo249.php

Crear tablas y datos


ejemplo250.php

Ver contenidos de tablas

php250.php

Ver codigo fuente



Modificar registros en cascada

<?
$base="ejemplos";
$tabla="principal1";
$conexion=mysql_connect("localhost","pepe","pepa");
mysql_select_db($base,$conexion);
# modificamos un registro
mysql_query("UPDATE $tabla SET DNI='123456' WHERE DNI='111111'",$conexion);
# borramos un registro
mysql_query("DELETE FROM $tabla WHERE (DNI='222222')",$conexion);
if (mysql_errno($conexion)==0){echo "<h2>Tablas actualizadas</b></H2>";
}else{
print "Ha habido un error al actualizar";
}
mysql_close();
?>


ejemplo251.php

Actualizar en cascada


ejemplo250.php

Ver contenido de la tabla


Para que puedas retornar a las condiciones iniciales, desde este enlace podrás borrar las tablas creadas para actualización en cascada. De esta forma podrás volver a crearlas, cuando desees, en las condiciones iniciales.




Fuente: