Select en MySQL con tablas relacionadas

varuk

Hola.

Tengo tres tablas en MySQL:

poker_usuarios

poker_partidas

poker_partidas_apuntadas

Los datos de poker_partidas_apuntadas se actualizan, o se borran, al cambiar los datos de un usuario en la tabla "poker_usuarios" o al borrar una partida en "poker_partidas". Bien.

Sé hacer para listar los jugadores que están jugando una partida, por ejemplo la partida número 2:
SELECT usuario FROM poker_partidas_apuntadas WHERE iddelapartida=2

Ahora bien, dado que el nombre de una partida podria repetirse, he tenido que poner en la última tabla la ID de la partida. ¿Cómo podría hacer para listar las partidas en las que está inscrito un jugador? Por ejemplo, que me diga el nombre de todas las partidas donde "peral" está apuntado, no la ID.

Muchas gracias.

BLZKZ

que problema hay? xD sacas las id de las partidas del usuario y de ahi sacas el nombre de la partida :S con subconsultas, mira : http://dev.mysql.com/doc/refman/5.0/es/subqueries.html

varuk

Me imaginaba que había algo, pero no podía buscarlo en Google porque ni sabía el nombre que recibía ni nada... y después de un rato buscando "consultas tablas relacionadas" he venido aquí.

Muchas gracias BLZKZ. Cuando te vea algún dia te debo una caña.

B

Haces una unión de las tablas poker_partidas y poker_partidas_apuntadas utilizando la foreign key como pivote, un join.

SELECT poker_partidas.nombrepartida AS Partida
FROM poker_partidas, poker_partidas_apuntadas
WHERE poker_partidas.idpartida = poker_partidas_apuntadas.iddelapartida AND
poker_partidas_apuntadas.usuario = 'peral';

Si lo haces de esta forma en lugar de utilizando el operador join, es conveniente que pongas la tabla con menor número de tuplas delante para mejorar el rendimiento.

Como la tabla poker_partidas_apuntadas es una relación M:N entre usuarios y partidas, lo que debería tener es la combinación de la primary key de esas dos tablas como primary key propia. Deberías usar el identificador de usuario en la relación en lugar del nombre ya que es la pk de la otra tabla y definirla como fk.

BLZKZ

pero para eso no deberia marcarlas como foreing key? xD

B

#5 para qué? :s

BLZKZ

me referia a que a la hora de crear las tablas no deberias crear el campo como foreign key? o las puedes usar como tal sin haberlo especificado antes?

Khanser

SELECT pp.nombrepartida from poker_partidas pp, poker_partidas_apuntadas ppa WHERE pp.idpartida = ppa.iddelapartida AND ppa.usuario = 'peral'

eso es lo que necesitas?

Edit: En Mysql creo que MyISAM no da soporte para FK's, hay que usar innoDB, de todas formas para lo unico que le sirve es para activar excepciones cuando intente borrar algo de una tabla A, si tiene una valor de pk referenciado en B

1
varuk

Me acaba de salir usando esto:

SELECT nombrepartida FROM poker_partidas WHERE idpartida = ANY (SELECT iddelapartida FROM poker_partidas_apuntadas WHERE usuario="peral" );

Con lo de #8 también funciona.

B

#7 Se puede, comprueba los campos sin más, lo que ocurre es que en lo que ha puesto él, no sé cómo lo habrá hecho pero si ha puesto el nombre de usuario en lugar del id en la relación no creo que haya definido usuario como fk de login, o hubiese sido un poco extraño, y en teoría se puede insertar cualquier tupla aunque haga referencia a algo que no existe. No tienes nada que mantenga la integridad referencial.

Como a mi me enseñaron a hacerlo sería:
iduser como pk
idpartida como pk

iddeusuario, iddelapartida como pk
iddeusuario fk
iddelapartida fk

No sé, lo mismo no he entendido el problema y me estoy montando aquí un lío xd

dagavi

Bienvenido al mundo de las JOIN.

En cualquier curso de BD te "obligarian" a realizar consultas "simples" (incluyendo joins, etc) antes que realizar subconsultas. Los SGBD no pueden optimizar muy bien las consultas que incluyen subconsultas.

Edit: Hace unas semanas utilicé en Windows un MySQL 5 usando un programa de estos que te ponen el apache, mysql, apache, etc y solo hay que darle a "start" y el MySQL (sin configurar nada) se pasaba por el forro de los webos la integridad referencial. Por mucho que pusiear "FOREING KEY" solo "parseaba la frase" (no decía syntax error), pero como si no existiera, no servía de nada.

varuk

Las tablas están creadas así:

spoiler
B

#11 Utilizaste el query browser? Ese se los pasa por el forro todas, en cuanto haces lo mismo en el workbench peta por todas partes.

no se si la suite que dices es el xampp, pero apesta

#12 Vale, aunque hayas puesto el nombre y no la id lo has solucionado haciendo que no se pueda repetir el nombre, esta bien pero ten cuidado, no es lo más convencional. Cómo lo has hecho no tendría que darte problemas.

varuk

#13 ¿Quieres decir que en la tabla poker_partidas_apuntadas ponga el ID del usuario en vez del "login"?

B

#14 Sí, a eso me refería. Lo más normal es poner como fks pks de otras tablas en lugar de otro atributo que no sea primario, te sueles evitar problemas. Si así te va bien, adelante, yo es que nunca lo he hecho así. Cuestión de gustos.

NeB1

yo como #15, me parece todo mucho más limpio y robusto usando enteros además...

P

Notas:
-Efectívamente, usa los JOIN's mucho antes que concatenar tablas en el FROM uniéndolas en el WHERE, o peor aún, subconsultas tipo WHERE ID IN (select tururu FROM tarara Where piripipi). Son sensiblemente más rápidas de ejecutar.
-Poner FK's (claves foráneneas) o no ponerlas no te impide "unir" tablas. Las foreign keys sirven para mantener la integridad de la base de datos, es decir, que los datos sean consistentes y fiables Esto quiere decir que si borras una fila de una tabla maestra, o la modificas, los cambios se aplicarán en cascada a las tablas relacionadas (si así lo has indicado cuanco creas el foreign key). Bastante útil y recomendable usar Foreigns keys, pero entonces tu tablas deberás convertirlas al tipo INNODB y no MYISAM o cosas raras.
-SIEMPRE usa CLAVES PRIMARIAS para identificar filas de una tabla mediante foreign keys, no otros campos ni campos UNIQUE por muy golosos que parezcan. Te ahorrarás futuras fallas y calentamientos de cabeza. Este error importante lo cometes en la tabla "poker_partidas_apuntadas" usando el nombre de usuario en vez de su ID para la columna "usuario". CAMBIALO.

La consulta sería algo así como

SELECT pu.login
FROM poker_usuarios pu
LEFT JOIN poker_partidas_apuntadas ppa ON pu.usuario=ppa.idusuario
WHERE ppa.idpartida=2

Esto sólo funcionaría si haces el cambio que te digo arriba sobre la tabla "poker_partidas_apuntadas".

ppu y pa se llaman "alias" (se puede poner cualquier alias a cualquier tabla, pero la utilidad es que el alias sea lo mas corto posible) y sirven para no tener que escribir entero el nombre de la tabla cuando quiero acceder a un campo de ellas y para saber a qué campo de qué tabla estás usando en el caso de que algunas tabals tengan campos con el mismo nombre.

varuk

#17 Muy buena explicación. Muchas gracias ^^

dagavi

Aprovecho el post que ya va sobre SQL para ver si alguien me podría decir, por mera curiosidad, como se puede ejecutar, en PostgreSQL 9 (usando pgAdminIII), un script PG/PLSQL sin tener que crear un procedimiento almacenado.

He leído que justo en PostgreSQL 9 han introducido la sentencia DO, pero al ser una palabra tan común en inglés y tan pequeña consigo obtener información mediante búsquedas.

En Oracle esto se puede, y la cosa sería que si quiero hacer un pequeño script para, por poner un ejemplo, meter 100 filas en una tabla:

DECLARE
    i INTEGER
BEGIN
    i := 0;
    WHILE i < 100 LOOP
        INSERT INTO (.....);
    END LOOP;
END
$$ LANGUAGE pgplsql

Que eso no tenga que ser metido dentro de un procedure, que se pueda ejecutar "on the fly".

0buS

Acostumbrate a usar JOINS porque es lo que siempre funciona xD

P

Dagavi, you uso mysql y no tengo problemas con ejecutar al vuelo scripts pl/sql, aunque suelo hacer ese tipo de tareas con scripts en PHP que hago más rápidamente y me dan menos problemas. De todas formas con una simple busqueda:
http://www.google.es/#hl=es&biw=1920&bih=887&q=execute+script+postgresql+pgAdmin&aq=f&aqi=&aql=&oq=&gs_rfai=&fp=aff284a721dd317e

Me han salido muchas soluciones que no puedo probar. Ésta es una de las más completas que he visto:
http://www.pgadmin.org/docs/dev/pgscript.html

Aquí también dice que su Query Editor permite ejecutar scripts al vuelo (debajo de la segunda foto):
http://www.pgadmin.org/docs/1.12/query.html

1
dagavi

El primer link describe el lenguaje PgScript, que supongo que es una alternativa al PL/PgSQL, sin embargo el link me ha ido bien ya que hay, dentro de esa web, un link a la lista de comandos de Postgres 8.3, he cambiado el número a 9.0 y allí si he podido encontrar la definición del comando DO que antes dije.

Era casi como lo intentaba, pero me faltaban dos "$$" al inicio y final.

DO [LANG] code;

Usuarios habituales