PHP - Relacionar tablas
4 seguidores
A ver si los maestros del PHP echan una mano a este joven aprendiz ;)
tengo datos en dos tablas MySQL y las tengo relacionadas por un identificador único. Tengo que mostrar los datos de cada registro de una de las tablas y algunos de los correspondientes de la otra, pero aquí es donde me pierdo, en cómo relacionar esos datos para mostralos en pantalla.
Por si no se ha entendido pongo el ejemplo:
Titular <--- Tabla 1
Texto <--- Tabla 1
Usuario <--- Tabla 2
Me he explicado???
Salu2
meddle
txuma
Me he explicado???
si pero no :)
a ver, tienes dos tablas, con un campo que las relaciona. debo suponer que ese campo es unico en tabla1 pero no lo es en tabla2 (si fuera unico en las dos, entonces no necesitas dos tablas). necesitas los join (o hacerlo a lo cutre como yo y crear bucles con subqueries).
Pongamos un ejemplo.
Campos Tabla1 (autor): autor_id, nombre, apellido
Campos Tabla2 (libro): libro_id, titulo, paginas, autor_id
Supongamos que quieres sacar un listado de todos los autores con los libros que han escrito:
<code>
SELECT nombre, apellido, titulo FROM autor, libro WHERE autor.autor_id = libro.autor_id
</code>
Eso te crea lo que quieres.
OJO: puesto que en la tabla libros puedes tener varios registros con el mismo autor_id (un autor puede escribir mas de un libro) esa SELECT te devuelve tantos registros como filas tengas en la tabla libro, repitiendo autores. Si lo que quieres es tener los titulos que ha escrito un autor determinado (es distinto) debes hacer:
<code>SELECT titulo FROM autor,libro WHERE (libro.autor_id = (SELECT autor_id FROM autor WHERE nombre = 'Pepe') AND libro.autor_id = autor.autor_id)</code>
gandalias
Bueno... Yo intentaré explicar lo del Join con la misma estructura que ha puesto meddle.
tabla 1 (autores) --> id_autor (clave principal), nombre, apellidos
tabla 2 (libros) --> id_libro (clave principal), titulo, páginas, id_autor
1) Para Obtener TODOS los registros de AUTORES y solo los LIBROS donde el id_autor coincida --> LEFT JOIN
SELECT autores.id_autor, autores.nombre, autores.apellidos, libros.titulo, libros.paginas, libros.id_libro
FROM autores LEFT JOIN libros ON autores.id_autor = libros.id_autor;
En este caso si existe algún autor que no tenga asignado algun libro, porque lo hayamos dado de baja en nuestra biblioteca por ejemplo, este autor aparecerá en la consulta pero con los campos referentes a los libros como valor NULL. Esto es muy util en ocasiones para obtener los autores que no tienen asignados libros. Para hacer esto bastaría con añadir una clausula WHERE al final de la consulta diciendo que seleccione aquellos registros cuto id_libro sea null. Es decir:
SELECT autores.id_autor, autores.nombre, autores.apellidos, libros.titulo, libros.paginas, libros.id_libro
FROM autores LEFT JOIN libros ON autores.id_autor = libros.id_autor
WHERE id_libro is null;
2) Para Obtener TODOS los registros de LIBROS y solo los AUTORES donde el id_autor coincida --> RIGHT JOIN
SELECT autores.id_autor, autores.nombre, autores.apellidos, libros.titulo, libros.paginas, libros.id_libro
FROM autores RIGHT JOIN libros ON autores.id_autor = libros.id_autor;
3) Para Obtener TODOS los registros de AUTORES y de LIBROS donde el id_autor coincida (solo los coincidentes) --> INNER JOIN
SELECT autores.id_autor, autores.nombre, autores.apellidos, libros.titulo, libros.paginas, libros.id_libro
FROM autores INNER JOIN libros ON autores.id_autor = libros.id_autor;
Espero que te aclare algo...
Un saludo
txuma
Antes de nada muchas gracias por vuestro interés. Creo que lo que yo estoy preguntando no va por ahi. pero estoy espeso y no me entero ni epxlico bien. (aun así, eso que habéis puesto me va a venir de puta madre para otra cosa, mil gracias)
De hecho tengo la sensación de que lo que estoy preguntando es una chorrada super simple, pero no lo pillo.
El problema que planteo no es tanto hacer la SELECT como la forma correcta de pintar los datos. A ver si consigo explicarlo siguiendo con vuestro ejemplo:
Extraigo los datos de la tabla libros y se los asigno a un array y obtengo, por ejemplo esto.
id_libro = 1
titulo: El Quijote
paginas: 543
id_autor = 1.
Bueno, pues ¿cómo hago para que al pintar los datos ponga ahí 'Cervantes', que es el dato que tengo guardado en la otra tabla?
Espero haberme explicado mejor. Y si la solución es muy simple no os riais demasiado alto, que os oigo ;)
gandalias
Bueno, mi respuesta anterior la he modificado porque en el punto 2 habia un error que ya he corregido. Si quieres lo repasas otra vez...
No se como tendrás montado el tinglado. Te pongo el ejemplo con los datos de un libro metidos en un array tal y como pones y como obtener el nombre y apellidos. Para eso lo que hago es hacer un select a la tabla de autores con una clausula where que filtre por el id_autor
<?php
$libro=array("1","El Quijote",230,"5");
/* Comentario
Con esto Tenemos
$libro[0]="1" <-- id_libro
$libro[1]="El Quijote" <-- titulo
$libro[2]=230 <-- páginas
$libro[3]="5" <-- id_autor
Fin Comentario
*/
// Conexion
$biblio=mysql_pconnect("localhost","root","");
// Base de Datos
mysql_select_db("biblioteca",$biblio);
// Consulta del autor deseado: El id_autor '5'
$txtquery="SELECT nombre,apellidos from autores where id_autor='".$libro[3]."'";
$consulta=mysql_query("SELECT nombre,apellidos from autores where id_autor='".$libro[3]."'",$biblio);
$encontrado=mysql_num_rows($consulta);
if ($encontrado>0) {
$autor=mysql_fetch_array($consulta);
echo $autor['nombre']." ".$autor['apellidos'];
} else {
echo "No encontrado";
}
// Cerramos la Conexion
mysql_close($biblio);
?>
Al principio del post decias que querias sacar todos los registros de una de las tablas (supongo LIBROS) y aquellos de autores donde el campo id_coincida. De ahi que te explicamos Meddle y yo lo de cruzar las tablas. Te pongo el código para obtener esta consulta "Todos los libros con la información del autor correspondiente". No entiendo muy bien porque introduces los datos del libro en un array si después vas a sacar TODOS los libros. ¿vas machacando el array cada vez que obtienes un registro de libros o lo metes en un array de 2 dimensiones (una dimension para la fila y la otra para los campo de libros)?... Si esto fuera así y tuvieras que mostrar 10000 libros necesitarias un array de 10000 filas x 4 columnas!!! En el mejor de los casos en el que obtuvieras como maximo siempre 4 o 5 libros necesitas 1 consulta para obtener los libros y tantas consultas a la tabla autores como libros haya. En la solución mezclando tablas solo realizas una consulta a la base de datos.
No se si todo esto es realmentelo que quieres hacer y pero sirva como justificación al uso de unir tablas por medio de join. Te pongo el código
<?php
// Conexion
$biblio=mysql_pconnect('localhost','root','');
// Base de Datos
mysql_select_db('biblioteca',$biblio);
// Consulta de todos los libros
$libros=mysql_query('SELECT libros.id_libro,libros.titulo,libros.paginas,libros.id_autor,autores.id_autor, autores.nombre, autores.apellidos
FROM autores RIGHT JOIN libros ON autores.id_autor = libros.id_autor;',$biblio);
// Carga de libros en el Array
$num_libros=mysql_num_rows($libros);
for ($i=0;$i<$num_libros;$i++) {
$libro=mysql_fetch_array($libros);
echo $libro['id_libro'].' '.$libro['titulo'].' '.$libro['paginas'].' '.$libro['id_autor'].' '.$libro['nombre'].' '.$libro['apellidos'].'<br>';
}
mysql_close($biblio);
?>
Un saludo
txuma
Creo que el problema es que no me estoy explicando muy bien.... :(
Entiendo el ejemplo que me pones, pero ahí haces una SELECT específica buscando un autor concreto, y no es lo que yo quiero. Yo pretendo mostrar TODOS los libros.
La verdad que a lo mejor el ejemplo que estoy usando no es el más adecuado. Lo que estoy intentando es programar por mi cuenta un sistema muy simple de news*, y en una tabla tengo las news y en otra los autores, y quiero mostrar las últimas 30 que se hayan puesto y en cada uno tendrá que aparecer quién la ha escrito y su email.
Espero haberme explicado mejor ahora :oops:
(*) Ya sé que hay por hay montones de sistemas de news ya hechos, pero quiero programarlo a mano desde cero, porque si al final me pongo a copiar y pegar no aprendo en la vida... ;)
gandalias
Pos chico, a ver si no me explico yo :)
Yo lo haria como te he puesto en en anterior post con el RIGHT JOIN. Puedes añadir una clausula where en la consulta para que te muestre a partir del id que quieres mostrar hasta el id+30 y ordenadarlo por fecha.
No se me ocurre otra cosa. Tendría que ver tu código para hacerme a la idea de como muestras SIN EL AUTOR los 30 registros y la estructura que tienes en la base de datos. De todas formas creo que esto puede servirte. Al menos un poco.
Tablas
news --> id_news, fecha, titulo, id_autor
autores --> id_autor, nombre
news
'1' '2003-08-01' 'Video Conferencias' '34'
'2' '2003-09-03' 'Nuevas Consultas Disponibles' '78'
'3' '2003-11-12' 'Nueva Nota Interna' '456'
..
..
'789' '2004-01-01' 'Feliz Año' '1'
autores
'1' 'The Boss'
'2' 'Machaquito'
..
..
'4567' 'Majete'
El código para mostrar desde el id='45' hasta los 30 siguientes
<?php
// Conexion
$basedatos=mysql_pconnect('localhost','root','');
// Base de Datos
mysql_select_db('news',$basedatos);
// Consulta de todos los libros
$news=mysql_query('SELECT news.id_news,news.fecha,news.titulo, autores.nombre
FROM autores RIGHT JOIN news ON autores.id_autor = news.id_autor WHERE news.id_news>="45" order news.id_fecha',$basedatos);
// Carga de libros en el Array
$num_news=mysql_num_rows($news);
// Si hay mas de 30 registros que muestre solo 30,en caso contrario que devuelva todos. Lo hago con un operador ternario pero valdría un IF
$max_reg=($num_news>30?29?$num_news);
for ($i=0;$i<$max_reg;$i++) {
$noticia=mysql_fetch_array($news);
echo $noticia['id_news'].' '.$noticia['fecha'].' '.$noticia['titulo'].' '.$noticia['nombre'].'<br>';
}
mysql_close($basedatos);
?>
No he comprobado el código y puede que haya algun error por ahi pero a ver si sirve de algo... A alguien le servirá... Otra aclaración. Este SELECT devuelve todas las filas y no solo las 30 primeras. Se podría haber filtrado en el SELECT para que devuelva solo las 30 que necesitas añadiendo la condicion en el where por ejemplo 'and news.id_news<="75"' pero esto valdría suponiendo que entre los id estan en incrementos de 1 y no hay huecos tipo '30' '31' '34' '50'. Como te digo depende de la estructura de tu base de datos. Y bueno, los id para la consulta deberían ser dinámicos ;) ...
Haleee!! Me voy a comer gorrinos de un matanza. ¡¡VIVA EL VEGETAL!! :)
:) :) :) Y VIVA EL VINO DE LAS VERDES MATAS
txuma
Bueno, salir ya me ha salido.... MILLONES DE GRACIAS ;)
... pero no acabo de entender muy bien lo que he hecho y eso no me mola porque lo de repetir mecanicamente sin entender no me va. :( O sea que no entiendo muy bien el resultado de la select, así que voy a analizarlo concienzudamente a ver si lo pillo.
Gracias !!!!
meddle
txuma, ¿por que no nos dices que tienes y que quieres hacer exactamente? asi a bote pronto se puede ayudar pero si quieres algo muy especifico... :)
txuma
jejejeje, he pillado a meddle en un renuncio.... jejeje (es broma). Es lo que ponía un par de post atrás: un sistema de noticias de lo más simple, y no quiero coger ninguno hecho porque sino no aprendo a programar un poquito en la vida ;)
Ya he conseguido que salga con el RIGHT JOIN, pero ahora estoy en esa fase de analizarlo para entender bien el código (no me vale sólo que el resultado sea bueno, también lo quiero entender)
Dentro de un rato me pondré a terminarlo, a ver si a lo largo de la tarde os puedo enseñar el resultado.
Gracias a los dos por la ayuda !!!
meddle
con el primer codigo que puse te deberia ir. es decir algo como:
<code>SELECT nombre, apellido, titulo FROM autor, libro WHERE autor.autor_id = libro.autor_id</code>
Supongo que puedes limitarlo a 30 news, haciendo:
<code>SELECT nombre, apellido, titulo FROM autor, libro WHERE autor.autor_id = libro.autor_id LIMIT 30</code> (pero no lo he probado).
¿Quieres saber cómo funciona? Vamos a ello. Al hacer una SELECT de dos tablas, lo que el sistema hace es crear una tabla temporal, que seria el resultado de SELECT * FROM autor, libro. Esa tabla temporal contiene registros con información correcta y registros en los cuales hay pares de datos no correctos. Si tienes 3 registros en una tabla y 5 en la otra, esta temporal tendrá 3x5=15 registros, cuando en realidad lo que tu quieres son 5 registros, ¿verdad? Solo los que contienen la misma informacion en las columnas autor_id son los registros correctos.
Por eso necesitamos un campo común, en este caso autor_id, y lo vamos a añadir en la query haciendo el WHERE autor.autor_id = libro.autor_id
Este tipo de JOIN se llama Cross Join o Cartesian Join.
txuma
Eureka !!! Ya lo he entendido !!! Pero ha sido la ostia... he estado casi un cuarto de hora rebanandome el cerebro, hasta que he cogido papel y boli y he empezado a escribir cómo sería esa tabla temporal de SELECT * FROM autor, libro . Y al verlo escrito ya lo he entendido (las pista ha sido lo de 3x5=15 registros). Gracias Meddle !!
Y gracias también a Gandalias, porque ahora que me he aclarado también empiezo a pillar como funciona LEFT JOIN, RIGHT JOIN e INNER JOIN... aunque a esto aún tengo que darle una vueltecita más ;)
meddle
me alegro ;)
un saludo
gandalias
¡¡Tomando nota del LIMIT!!
Gracias Meddle
salú!
meddle
la verdad es que el pequeño tuto me ha servido para recordarme que no tengo que ser tan perro (suelo usar subqueries), que las join estan para algo ;)
txuma
Tengo que reconocer que esta consulta que os he hecho me ha servido para aprender un montón. He programado un pequeño sistema de news, muy básico, pero 'picando' todo el código, y con vuestras explicaciones he aprendido un montón de cosas que me van a venir fenomenal para programar un proyecto más grande que quiero hacer. Millones de gracias ;)
helenp
si se puede, pero parece que las columnas tienen que ser del mismo tipo, el truco consistirá en añadir una columna que indica que es,
como tabla limpiezas: fecha_limpieza, tipo-limpieza, tabla reservas: fecha_llegada, tipo_llegada, fecha_salida, tipo_salida,
esto da dos columnas unidas:
$result = mysql_query ("SELECT id, llegada FROM bookings
UNION ALL
SELECT id, fecha FROM limpiezas
UNION ALL
SELECT id, salida FROM bookings", $dbh);
if ($row = mysql_fetch_array($result)){
echo "<table border = '1'> \n";
echo "<tr> \n";
echo "<td><b>id</b></td> \n";
echo "<td><b>llegada</b></td> \n";
echo "</tr> \n";
do {
echo "<tr> \n";
echo "<td>".$row["id"]."</td> \n";
echo "<td>".$row["llegada"]."</td> \n";
echo "</tr> \n";
} while ($row = mysql_fetch_array($result));
echo "</table> \n";
} else {
echo "¡ La base de datos está vacia !";
}