2012-06-13 31 views
14

¿Cuál es la mejor manera de almacenar "listas ordenadas" en una base de datos, de manera que actualizarlas (agregar, eliminar y cambiar el orden de las entradas) se hace fácilmente?¿La mejor manera de almacenar listas ordenadas en una base de datos?

Considere una base de datos donde tenga una tabla para usuarios y películas. Cada usuario tiene una lista de películas favoritas.

Dado que a muchos usuarios les puede gustar la misma película, hice de los usuarios y las películas tablas separadas y utilizo una tercera tabla para conectarlos, usermovies.

usermovies contiene una identificación de un usuario y una película y un "número de orden". El número de orden se utiliza para ordenar la lista de películas para los usuarios.

Por ejemplo, el usuario Josh tenga la siguiente lista:

  1. Prometeo
  2. Hombres de Negro 3
  3. El Dictador

y el usuario Jack podría tener una lista como:

  1. The Dictator
  2. Prometeo
  3. acorazado
  4. Snow White and the Huntsman

Por lo tanto, comparten algunos de los favoritos, pero no necesariamente en el mismo orden.

puedo obtener la lista de ID de película para cada usuario mediante una consulta:

SELECT movie_id FROM usermovies WHERE user_id =? ORDER BY order_number 

Luego, con los movie_ids ordenados, puedo obtener la lista de películas usando otra consulta

SELECT name FROM movies WHERE id in (?,?,?) ORDER BY FIELD (id, ?,?,?) 

Así que las consultas funcionan, pero la actualización de las listas parece realmente compleja ahora: ¿hay mejores formas de almacenar esta información para que sea más fácil obtener la lista de películas para el usuario x, agregar películas, eliminarlas y cambiar el orden de la lista?

+0

para obtener todas las películas para un usuario podría utilizar un consulta única como esta: 'SELECT nombre FROM películas INNER JOIN usermovie ON usermovie.movie_id = movies.id AND usermovie.user_id =? PEDIDO POR usermovie.order_number'. Y no veo lo que es difícil con el enfoque actual? Para agregar una película a un usuario, simplemente inserte una nueva entrada en su tabla de enlaces y para eliminarla, elimine la entrada. – Cyclonecode

+0

gracias! Eso será útil, aunque mi verdadero problema aquí es la actualización. – wannabeartist

Respuesta

5

Una tabla de unión/unión con columnas adicionales para los atributos de la asociación entre películas y usuarios es la forma estándar de realizar una asociación muchos con una clase de asociación, por lo que lo que ha hecho parece correcto.

En cuanto a la facilidad de insertar/actualizar/eliminar, tendrá que administrar toda la asociación (todas las filas para los FK de película de usuario) cada vez que realice una inserción/actualización/eliminación. Probablemente no haya una manera mágica/más simple de hacer esto.

Habiendo dicho esto, también deberá ejecutar estas operaciones en una transacción y, lo que es más importante, tener una columna 'versión' en esta tabla de unión si su aplicación es compatible con múltiples usuarios.

+0

De hecho, * hay * tal forma "mágica" de hacer la tarea cambiando solo una fila en lugar de todas las filas: http://stackoverflow.com/a/3399334/2947812 –

3

Para recuperar favoritos del usuario películas se puede utilizar una sola consulta:

SELECT um.order_number, m.name FROM movies m 
INNER JOIN usermovies um ON m.id = um.movie_id 
WHERE um.user_id = ? 
ORDER BY um.order_number 

para añadir/quitar una película favorita sólo tiene que añadir/quitar registro relacionado en la tabla usermovies.
Para modificar una orden de película simplemente cambie todo el campo order_number en la tabla user_movies relacionada con el usuario.

+0

Gracias, Todavía no estoy seguro de cómo manejar los cambios: por ejemplo, borrar la primera película también significaría cambiar los números de orden de todas las otras películas, ¿no? – wannabeartist

+0

@wannabeartist: sí, seguro – Marco

+0

¿Tendría sentido volver a crear la lista en las actualizaciones, en lugar de actualizar las filas individuales? Por ejemplo, el usuario x toma su lista, realiza cambios y pulsa "guardar" -> 1. las entradas anteriores se eliminan de una vez 2. las nuevas entradas se insertan de una vez – wannabeartist

4

Además de lo que otros han dicho, el reordenamiento de los favoritos existentes se puede hacer en una sola instrucción UPDATE, como se explica en here.

La respuesta vinculada explica el reordenamiento de dos elementos, pero se puede generalizar fácilmente a cualquier cantidad de elementos.

3

Si no está buscando un "subir/bajar" un poco la solución, y luego por defecto a añadir en la parte inferior de la lista, aquí están algunas sugerencias más:

insertar nuevas filas en una específica posición se puede hacer así: (insertar en la posición 3)

UPDATE usermovies SET order_number = ordernumber + 1 
    WHERE ordernumber > 3 and user_id = ?; 
INSERT INTO usermovies VALUES (?, 3, ?); 

y se puede eliminar de forma similar: (posición borrando 6)

DELETE usermovies WHERE order_numer = 6 and user_id=?; 
UPDATE usermovies SET order_number = ordernumber - 1 
    WHERE ordernumber > 6 and user_id = ?; 
Cuestiones relacionadas