Ver Mensaje Individual
  #3 (permalink)  
Antiguo 28/06/2012, 10:37
leonardo_josue
Colaborador
 
Fecha de Ingreso: enero-2007
Ubicación: México
Mensajes: 2.097
Antigüedad: 17 años, 3 meses
Puntos: 447
Respuesta: Listar registros con atributos en columnas

Hola aovalle:

Complementando el comentario de quimfv, el utilizar funciones de agrupación (MAX, MIN, SUM) es una manera "tramposa" de hacerlo, ya que de entrada puedo suponer que el campo valor_atributo es de tipo VARCHAR, ya que almacenas tanto valores como cadenas y valores nulos... de tal forma que el resultado puede ser un tanto impredecible... hay otra forma de obtener el mismo resultado utilizando LEFT JOIN's sobre la tabla de atributoslibros, utilizando alias, de esta manera:

Código MySQL:
Ver original
  1. mysql> SELECT * FROM libros;
  2. +----------+-------------+
  3. | id_libro | titulolibro |
  4. +----------+-------------+
  5. |        1 | Odisea      |
  6. |        2 | Soledad     |
  7. +----------+-------------+
  8. 2 rows in set (0.00 sec)
  9.  
  10. mysql> SELECT * FROM atributoslibros;
  11. +----------+-------------+----------------+
  12. | id_libro | id_atributo | valor_atributo |
  13. +----------+-------------+----------------+
  14. |        1 |           1 | 10000          |
  15. |        1 |           2 | 1980           |
  16. |        1 |           3 | 1              |
  17. |        1 |           4 | Rustico        |
  18. |        2 |           1 | 0              |
  19. |        2 |           2 | 1945           |
  20. |        2 |           3 | NULL           |
  21. |        2 |           4 | Tapa dura      |
  22. +----------+-------------+----------------+
  23. 8 rows in set (0.01 sec)
  24.  
  25. mysql> SELECT
  26.     ->   l.id_libro,
  27.     ->   l.titulolibro,
  28.     ->   alPrecio.valor_atributo precio,
  29.     ->   alFecha.valor_atributo fecha,
  30.     ->   alVolumen.valor_atributo volumen,
  31.     ->   alEmpaste.valor_atributo empaste
  32.     -> FROM libros l
  33.     -> LEFT JOIN atributoslibros alPrecio
  34.     ->    ON l.id_libro = alPrecio.id_libro AND alPrecio.id_atributo = 1
  35.     -> LEFT JOIN atributoslibros alFecha
  36.     ->    ON l.id_libro = alFecha.id_libro AND alFecha.id_atributo = 2
  37.     -> LEFT JOIN atributoslibros alVolumen
  38.     ->    ON l.id_libro = alVolumen.id_libro AND alVolumen.id_atributo = 3
  39.     -> LEFT JOIN atributoslibros alEmpaste
  40.     ->    ON l.id_libro = alEmpaste.id_libro AND alEmpaste.id_atributo = 4;
  41. +----------+-------------+--------+-------+---------+-----------+
  42. | id_libro | titulolibro | precio | fecha | volumen | empaste   |
  43. +----------+-------------+--------+-------+---------+-----------+
  44. |        1 | Odisea      | 10000  | 1980  | 1       | Rustico   |
  45. |        2 | Soledad     | 0      | 1945  | NULL    | Tapa dura |
  46. +----------+-------------+--------+-------+---------+-----------+
  47. 2 rows in set (0.00 sec)

Tal como te menciona quimfv en su post, el problema es que la asignación de los alias para cada columna lo estoy haciendo de manera arbitraria, es decir sin tomar en cuenta el contenido del catálogo de atributos. Finalmente, puedes simplificar la consulta de quimfv sin necesidad de utilizar subconsultas, asi:


Código MySQL:
Ver original
  1. mysql> SELECT
  2.     ->   l.id_libro,
  3.     ->   l.titulolibro,
  4.     ->   MAX(IF(a.id_atributo = 1, a.valor_atributo, NULL)) precio,
  5.     ->   MAX(IF(a.id_atributo = 2, a.valor_atributo, NULL)) fecha,
  6.     ->   MAX(IF(a.id_atributo = 3, a.valor_atributo, NULL)) volumen,
  7.     ->   MAX(IF(a.id_atributo = 4, a.valor_atributo, NULL)) empaste
  8.     -> FROM libros l INNER JOIN atributoslibros a ON l.id_libro = a.id_libro
  9.     -> GROUP BY l.id_libro, l.titulolibro;
  10. +----------+-------------+--------+-------+---------+-----------+
  11. | id_libro | titulolibro | precio | fecha | volumen | empaste   |
  12. +----------+-------------+--------+-------+---------+-----------+
  13. |        1 | Odisea      | 10000  | 1980  | 1       | Rustico   |
  14. |        2 | Soledad     | 0      | 1945  | NULL    | Tapa dura |
  15. +----------+-------------+--------+-------+---------+-----------+
  16. 2 rows in set (0.00 sec)

Repitiendo, que el uso de la función MAX sobre un campo tipo varchar puede traer problemas.

Finalmente, podrías optar por cambiar el modelo de BD, después de todo no creo que los atributos de un libro sean muchos aparte de estos... podrías cambiar a un modelo con sólo dos tablas:

Código MySQL:
Ver original
  1. mysql> SELECT * FROM libros;
  2. +----------+-------------+
  3. | id_libro | titulolibro |
  4. +----------+-------------+
  5. |        1 | Odisea      |
  6. |        2 | Soledad     |
  7. +----------+-------------+
  8. 2 rows in set (0.00 sec)
  9.  
  10. mysql> select * from atributoslibros;
  11. +----------+--------+-------+---------+-----------+
  12. | id_libro | precio | fecha | volumen | empaste   |
  13. +----------+--------+-------+---------+-----------+
  14. |        1 |  10000 |  1980 |       1 | Rustico   |
  15. |        2 |      0 |  1945 |    NULL | Tapa dura |
  16. +----------+--------+-------+---------+-----------+
  17. 2 rows in set (0.07 sec)

Podrías agregar una columna de comentarios para agregar atributos adicionales... podrías definir tus campos precio, fecha y volumen de tipo numérico, lo que te permitiría obtener consultas por ejemplo de rangos de precios o de años en específicos (cosa que con tu modelo no lo podrías hacer).

Saludos
Leo.

Última edición por leonardo_josue; 28/06/2012 a las 10:48