Pregunta Representar ordenando en una base de datos relacional


Tengo una colección de objetos en una base de datos. Imágenes en una galería de fotos, productos en un catálogo, capítulos en un libro, etc. Cada objeto se representa como una fila. Quiero poder ordenar estas imágenes de forma arbitraria, almacenando ese orden en la base de datos para que cuando muestre los objetos, estén en el orden correcto.

Por ejemplo, digamos que estoy escribiendo un libro, y cada capítulo es un objeto. Escribo mi libro y coloco los capítulos en el siguiente orden:

Introducción, accesibilidad, forma vs. función, errores, consistencia, conclusión, índice

Va al editor y vuelve con el siguiente orden sugerido:

Introducción, forma, función, accesibilidad, consistencia, errores, conclusión, índice

¿Cómo puedo almacenar este orden en la base de datos de una manera robusta y eficiente?

He tenido las siguientes ideas, pero no estoy entusiasmado con ninguna de ellas:

  1. Formación. Cada fila tiene una ID de pedido, cuando se cambia la orden (a través de una eliminación seguida de una inserción), se actualizan las ID de la orden. Esto hace que la recuperación sea fácil, ya que es solo ORDER BY, pero parece fácil de romper.

    // REMOVAL
    UPDATE ... SET orderingID=NULL WHERE orderingID=removedID
    UPDATE ... SET orderingID=orderingID-1 WHERE orderingID > removedID
    // INSERTION
    UPDATE ... SET orderingID=orderingID+1 WHERE orderingID > insertionID
    UPDATE ... SET orderID=insertionID WHERE ID=addedID

  2. Lista enlazada. Cada fila tiene una columna para el ID de la siguiente fila en el orden. El recorrido parece costoso aquí, aunque de alguna manera puede haber uso ORDER BY en lo que no estoy pensando

  3. Matriz espaciada Establezca el ID de orden (como se usa en el n. ° 1) para que sea grande, de modo que el primer objeto sea 100, el segundo sea 200, etc. Luego, cuando ocurra una inserción, simplemente colóquelo en (objectBefore + objectAfter)/2. Por supuesto, esto debería reequilibrarse de vez en cuando, para que no tenga cosas muy juntas (incluso con flotadores, eventualmente se encontraría con errores de redondeo).

Ninguno de estos parece particularmente elegante para mí. ¿Alguien tiene una mejor manera de hacerlo?


32
2017-08-21 23:01


origen


Respuestas:


Otra alternativa sería (si su RDBMS lo admite) usar columnas de tipo array. Si bien esto rompe las reglas de normalización, puede ser útil en situaciones como esta. Una base de datos que sé que tiene matrices es PostgreSQL.


5
2017-08-22 05:32



La mezcla de act_as_list en Rails maneja esto básicamente de la forma en que se delineó en # 1. Busca una columna INTEGER llamada posición (de la cual puede anular el nombre del curso) y la usa para hacer un ORDER BY. Cuando desee volver a pedir cosas, actualice las posiciones. Me ha servido muy bien cada vez que lo he usado.

Como nota al margen, puede eliminar la necesidad de volver a posicionar siempre en INSERTS / DELETES mediante el uso de numeración dispersa - algo así como básico en el día ... puede numerar sus posiciones 10, 20, 30, etc. y si necesita insertar algo entre 10 y 20, solo debe insertarlo en una posición de 15. Del mismo modo, al eliminar puede simplemente eliminar la fila y dejar el espacio. Solo necesita volver a numerar cuando realmente cambia el pedido o si trata de hacer un inserto y no hay espacio adecuado para insertarlo.

Por supuesto, dependiendo de su situación particular (por ejemplo, si tiene las otras filas ya cargadas en la memoria o no) puede o no tener sentido utilizar el enfoque de brecha.


3
2017-08-21 23:11



Solo un pensamiento considerando opción # 1 vs # 3: ¿la opción de matriz espaciada (n. ° 3) solo pospone el problema de la matriz normal (n. ° 1)? Sea cual sea el algoritmo que elija, o está roto, y tendrá problemas con el # 3 más tarde, o funciona, y luego el # 1 debería funcionar igual de bien.


3
2017-08-25 17:24



Haría un número consecutivo, con un disparador sobre la mesa que "da lugar" a una prioridad si ya existe.


2
2017-08-21 23:12



Si los objetos no están fuertemente codificados por otras tablas, y las listas son cortas, borrar todo en el dominio y simplemente reinsertar la lista correcta es lo más fácil. Pero eso no es práctico si las listas son grandes y tiene muchas limitaciones para ralentizar la eliminación. Creo que tu primer método es realmente el más limpio. Si lo ejecuta en una transacción, puede estar seguro de que no ocurre nada extraño mientras está en el medio de la actualización para arruinar el pedido.


2
2017-08-22 01:39



Use un número de coma flotante para representar la posición de cada artículo:

Artículo 1 -> 0.0

Artículo 2 -> 1.0

Artículo 3 -> 2.0

Artículo 4 -> 3.0

Puede colocar cualquier elemento entre otros dos elementos por simple bisección:

Artículo 1 -> 0.0

Artículo 4 -> 0.5

Artículo 2 -> 1.0

Artículo 3 -> 2.0

(Artículo movido 4 entre los artículos 1 y 2).

El proceso de bisección puede continuar casi indefinidamente debido a la forma en que los números de punto flotante están codificados en un sistema informático.

Artículo 4 -> 0.5

Artículo 1 -> 0.75

Artículo 2 -> 1.0

Artículo 3 -> 2.0

(Mueva el ítem 1 a la posición justo después del Ítem 4)


2
2017-09-18 00:22



Hice esto en mi último proyecto, pero fue para una tabla que solo ocasionalmente necesitaba pedirse específicamente, y no se accedía con demasiada frecuencia. Creo que la matriz espaciada sería la mejor opción, porque el reordenamiento sería más barato en el caso promedio, con solo un cambio en un valor y una consulta en dos).

Además, me imagino que ORDER BY sería bastante optimizado por los proveedores de bases de datos, por lo que aprovechar esa función sería ventajoso para el rendimiento en comparación con la implementación de la lista vinculada.


1
2017-08-22 01:58