Sentencia compleja MySQL

oFF-sIDE

Hola.

Soy desarrollador frontend pero estoy haciendo una aplicación para un amigo que en el backend tira de PHP para conectar con una base de datos MySQL. El problema es que en cuestión SQL tengo conocimientos básicos, lo que aprendí en la carrera hace muchos años ya y me enfrento a una sentencia un poco más compleja de lo habitual.

Tengo las siguientes tablas:

  • Padres (Nif <clave primaria>, nombre, apellidos, ....)
  • Alumnos (Id, nombre, apellidos, ...)
  • Padre-alumno (IdPadre, IdAlumno, ...: tabla para relacionar a cada padre con su alumno pues es una relación "de n a n").
  • Actividades (Id, nombre, precio, ...)
  • Inscripciones (IdPadre, IdAlumno, IdActividad, PagoEfectivo, ...)

En la tabla de inscripciones tengo el ID de la actividad y el ID del alumno. Necesito el nombre del alumno y el nombre de la actividad, pero NO quiero meterlos en la tabla de inscripciones como campos propios porque si mañana cambia el nombre de la actividad me parecería una guarrada tener que ir a actualizar a la tabla de actividades el nombre de la misma.

Hay dos formas de hacerlo, bien y mal. Yo sé hacerlo de la forma chunga, pero no me sale de las narices hacer algo mal sabiendo de antemano que está mal y es una guarrada. Esta es la forma que yo había pensado:

  • Recuperar las inscripciones con el ID del padre.
  • Meterlas en un array $inscripciones
  • Recorrer las inscripciones y para cada una, buscar en Alumnos y en Actividades el nombre del alumno y de la actividad.

Es decir, una query a "padre_alumno", un recorrido del array resultante (teóricamente corto, de 1 a 6 elementos), y para cada elemento del array, hacer dos consultas más, una a Alumnos y otra a Actividades.

GUARRADA TOTAL. No acepto hacerlo así porque estoy seguro que esto se puede hacer en una sola sentencia SQL.

¿Cómo lo haríais?

Gracias y disculpad mi torpeza en temas SQL. Seguro que para la mayoría de vosotros será una sentencia chupada, pero yo llevo ya demasiado tiempo haciendo frontend y pasando de SQL.

eXtreM3

En la tabla inscripciones necesitas el IdPadre? Imagino que con la única finalidad de conocer qué padre apuntó a qué hijo a X actividad... porque en realidad con el IdAlumno va que chuta.

Obviando esto, no entiendo muy bien dónde tienes la dificultad, las tablas parecen estar bien y no habría problema en relacionar alumnos - actividades - inscripciones.

DarkSoldier

denada.

2 1 respuesta
QuitCat

#1

SELECT A.NOMBRE AS "NOMBRE_ALUMNO", B.NOMBRE AS "NOMBRE_ACTIVIDAD"
FROM ALUMNOS A, ACTIVIDADES B, INSCRIPCIONES C
WHERE A.ID=C.IDALUMNO
AND B.ID=C.IDACTIVIDAD

Con Joins queda mas elegante, pero la query debería ser parecida

Merkury

#1 Aquí con Inner Join.

SELECT a.name, ac.nombre FROM alumnos as a, actividades as ac
INNER JOIN inscripciones
ON id = alumnos_id
WHERE a.id = alumnos_id AND ac.id = actividades_id
1 respuesta
HeXaN

#3 No sabías hacer la consulta y has puesto la imagen para salir del paso, mamonaso jajaja.

2 1 respuesta
QuitCat

#5 ¿No te has quedado en un punto intermedio entre el uso JOINs y WHEREs?

2 respuestas
Merkury

#7 What?

1 respuesta
B

#8 #7 Pues eso, que lo has hecho combinando inner join y where, en vez de las 2 condiciones con joins.

1 respuesta
oFF-sIDE

ARG! Qué rabia no acordarme de que los inner joins servían precisamente para esto!!!

¡Muchas gracias!

Merkury

#9 Pero es que aunque hagas el inner te hace falta el WHERE, con dos inners joins no sacas los datos (creo), hablo todo de cabeza, sin haber probado..

1
Troyer

#1 Monta la bd de ejemplo aquí así la gente te puede ayudar mejor, yo ahora mismo no puedo pero si nadie te lo ha resuelto te lo hago después, no tiene pinta de ser muy complicado.

http://sqlfiddle.com/

oFF-sIDE

No os preocupéis, si ya conocía los inner joins y los he usado, pero no sé por qué leches no me acordaba de ellos jajaja. Ya está todo claro, mil gracias ;)

1 respuesta
DarkSoldier

#6 no me jodas hombre, claro que sabía hacerla xD enseña a pescar y no le des el pez es mi filosofía xDD

#13 depende de lo que hagas.. mírate CQRS (denada de nuevo)

1 respuesta
RaymaN

Si el alumno solo tendrá asociado un padre en vez de los dos, puedes cargarte la tabla padre-alumno y guardar el id-padre en la tabla de alumnos.

1 respuesta
eXtreM3

#15 yo he pensado lo mismo, pero se da por hecho que quiere guardar información de N padres (padre, madre, tutor legal... whatever)

#14 con los fram3w0rks la consulta es:

$this->db->get('alumnosEnActividades')->result()

y listo, ni inners ni wheres ni pollas!

2 respuestas
RaymaN

#16 parece coña pero la gente está más obsesionada últimamente con controlar el último framework de moda que con aprender a manejar una base de datos relacional eficientemente. Luego la web va a pedales y lo primero que hacen es volver a cambiar de framework xD

oFF-sIDE

A ver, no os preocupéis por el diseño de la base de datos. Si tengo una tabla intermedia es porque la relación es de N a N. Soy 100% front-end, pero cuando diseñé la base de datos cogí todos los apuntes de la carrera y me apoyé en internet para hacer el diseño. Si no he optado por la forma rápida y fácil que he puesto antes es precisamente porque, hasta mi límite, me gusta hacer las cosas bien.

Lógicamente queda mal que diga esto y que no recuerde que el INNER JOIN estaba para estas cosas. Lo he visto muchas veces en la carrera y mil veces en mi vida laboral y sinceramente me avergüenza no haberme acordado, pero en cuanto a la base de datos, está diseñada así por algo.

Lo malo es que me va a tocar que hacer 2 INNER JOIN porque necesito el nombre de la actividad y el nombre del alumno (cada uno está en una tabla maestra). No sé si me penalizará mucho el rendimiento. Lo bueno es que el resultado del WHERE sobre la tabla de inscripciones no debería devolver más de 5 o 6 registros sobre los que haré los dos inner join.

1 respuesta
Merkury

#16 Sabes que ese get, al final va a hacer los Joins por ti no? XD

#18 No necesitas dos INNER JOIN para nada, porque si haces la query sobre Alumno o actividad, solo tienes que hacer el join una vez. Aunque en cualquier Framework, para tener la tabla que tiene el, tendria que hacer la tabla intermedia tambien y hacer las relaciones Alumno - Tabla Intermedia, Actividad - Tabla Intermedia, Padre - Tabla Intermeda (por aquello de guardar id del padre, del hijo y de la actividad) con lo que tu get, no serviría y tendrías que escribirte la consulta igualmente.

1 respuesta
Merkury

shit doble post...

eXtreM3

#19 xDDD. Bueno, el hilo no da para más. Result queda, digo resuelto.

B

Cuidadito con los joins de campos no indexados, que en local muy bien y luego en producción te llevas el palo cuando tienes que hacer búsquedas de millones de registros.

2
oFF-sIDE

Weno, aquí está la sentencia que estaba buscando, por si había algún interesado:

SELECT ins.Id,
		ins.IdTemporada,
		ins.IdClub,
		ins.IdSocio,
		ins.IdActividad,
		act.Nombre as Actividad,
		ins.IdAlumno,
		concat(alu.Nombre, ' ', alu.Apellidos) as Alumno,
		ins.ImpEfectivo,
		ins.Efectivo,
		ins.Baja
FROM inscripciones as ins
INNER JOIN alumnos as alu
ON ins.IdAlumno=alu.Id
	AND ins.IdTemporada=alu.IdTemporada
	AND ins.IdClub=alu.IdClub
INNER JOIN actividades as act
ON ins.IdActividad=act.Id
	AND ins.IdTemporada=act.IdTemporada
	AND ins.IdClub=act.IdClub
WHERE ins.IdTemporada='1'
	AND ins.IdClub='1'
	AND ins.IdSocio='22652072Q';

Gracias por las aportaciones. Por mi podéis cerrar el hilo :)

1

Usuarios habituales

  • oFF-sIDE
  • eXtreM3
  • Merkury
  • RaymaN
  • DarkSoldier
  • QuitCat
  • HeXaN