Hay dos casos a considerar, pienso:
- Mover una fila por lo que aparece antes en el pedido.
- Mueva una fila para que aparezca más adelante en el orden.
No es trivial de ninguna manera. No está claro si hay una restricción única en la columna 'orden'; El resultado final ciertamente se supone que tiene un orden único.
Notación:
- 'On' se refiere a la fila con valor 'orden = n' en los viejos valores
- 'Nn' se refiere a la fila con 'order = n' en los nuevos valores
En el ejemplo (ilustrativa de caso 1):
- O3 -> N1
- O1 -> N2
- O2 -> N3
Como alternativa, considere mover id = 2, de modo que tiene orden = 4:
- O2 -> N4
- O3 -> N2
- O4 -> N3
Usted es básicamente sumar o restar uno de los 'otros' filas, donde los son las filas en el orden anterior entre la posición anterior de la fila movida y la nueva posición de la fila movida. En un pseudo-código, usando $ antiguo y $ nueva para identificar el antes y después de las posiciones de la fila movido, y tratar con el caso 1 (edad> $ nueva $):
UPDATE AnonymousTable
SET order = CASE
WHEN order = $old THEN $new
WHEN order >= $new AND order < $old THEN order + 1
END CASE
WHERE order BETWEEN $new AND $old;
El código correspondiente para el caso 2 ($ $ antigua < nuevo) es:
UPDATE AnonymousTable
SET order = CASE
WHEN order = $old THEN $new
WHEN order > $new AND order <= $old THEN order - 1
END CASE
WHERE order BETWEEN $old AND $new;
Teniendo en cuenta la cláusula WHERE de las correspondientes actualizaciones en su conjunto, puede ser capaz de eliminar el segundo cuando en el caso y reemplazarlo con una simple cosa.
UPDATE AnonymousTable
SET order = CASE
WHEN order = $old THEN $new
ELSE order + 1
END CASE
WHERE order BETWEEN $new AND $old;
UPDATE AnonymousTable
SET order = CASE
WHEN order = $old THEN $new
ELSE order - 1
END CASE
WHERE order BETWEEN $old AND $new;
creo que es un procedimiento almacenado con el fin - la elección entre los dos estados en base a los parámetros de entrada $ edad, $ nueva. Es posible que pueda hacer algo con una combinación juiciosa de expresiones como '($old - $new)/ABS($old - $new)
' y 'MIN($old, $new)
' y 'MAX($old, $new)
' donde el MIN/MAX no son agregados sino funciones de comparación para un par de valores (como se encuentran en Fortran, entre otros) lenguajes de programación).
Tenga en cuenta que asumo que mientras se está ejecutando una sola declaración de SQL, la restricción de exclusividad (si existe) no se aplica ya que cada fila se cambia, solo cuando la instrucción se completa. Esto es necesario ya que no puede controlar realmente el orden en que se procesan las filas. Sé de DBMS donde esto causaría problemas; Sé de otros donde no sería así.
Todo se puede hacer en una sola instrucción SQL - pero usted quiere un procedimiento almacenado para solucionar los parámetros a la declaración. Uso IBM Informix Dynamic Server (11.50.FC6 en MacOS X 10.6.2), y ese es uno de los DBMS que impone la restricción única en la columna 'orden' al final de la instrucción. Hice el desarrollo del SQL sin la restricción ÚNICA; eso funcionó también, por supuesto. (Y sí, IDS le permite deshacer declaraciones DDL como CREAR TABLA y CREAR PROCEDIMIENTO. ¿Qué dijo? ¿Su DBMS no lo hace? ¡Qué pintoresco!)
BEGIN WORK;
CREATE TABLE AnonymousTable
(
id INTEGER NOT NULL PRIMARY KEY,
title VARCHAR(10) NOT NULL,
order INTEGER NOT NULL UNIQUE
);
INSERT INTO AnonymousTable VALUES(1, 'test1', 1);
INSERT INTO AnonymousTable VALUES(2, 'test2', 2);
INSERT INTO AnonymousTable VALUES(3, 'test3', 3);
INSERT INTO AnonymousTable VALUES(4, 'test4', 4);
SELECT * FROM AnonymousTable ORDER BY order;
CREATE PROCEDURE move_old_to_new(old INTEGER, new INTEGER)
DEFINE v_min, v_max, v_gap, v_inc INTEGER;
IF old = new OR old IS NULL OR new IS NULL THEN
RETURN;
END IF;
LET v_min = old;
IF new < old THEN
LET v_min = new;
END IF;
LET v_max = old;
IF new > old THEN
LET v_max = new;
END IF;
LET v_gap = v_max - v_min + 1;
LET v_inc = (old - new)/(v_max - v_min);
UPDATE AnonymousTable
SET order = v_min + MOD(order - v_min + v_inc + v_gap, v_gap)
WHERE order BETWEEN v_min AND v_max;
END PROCEDURE;
EXECUTE PROCEDURE move_old_to_new(3,1);
SELECT * FROM AnonymousTable ORDER BY order;
EXECUTE PROCEDURE move_old_to_new(1,3);
SELECT * FROM AnonymousTable ORDER BY order;
INSERT INTO AnonymousTable VALUES(5, 'test5', 5);
INSERT INTO AnonymousTable VALUES(6, 'test6', 6);
INSERT INTO AnonymousTable VALUES(7, 'test7', 7);
INSERT INTO AnonymousTable VALUES(8, 'test8', 8);
EXECUTE PROCEDURE move_old_to_new(3,6);
SELECT * FROM AnonymousTable ORDER BY order;
EXECUTE PROCEDURE move_old_to_new(6,3);
SELECT * FROM AnonymousTable ORDER BY order;
EXECUTE PROCEDURE move_old_to_new(7,2);
SELECT * FROM AnonymousTable ORDER BY order;
EXECUTE PROCEDURE move_old_to_new(2,7);
SELECT * FROM AnonymousTable ORDER BY order;
ROLLBACK WORK;
Los pares de invocaciones del procedimiento almacenado con los números invertidos restablecieron el orden original cada vez. Claramente, podría redefinir la variable v_inc
para que en lugar de ser solo ± 1, fuera 'LET v_inc = v_inc - v_min + v_gap;
' y luego la expresión MOD sería simplemente 'MOD(order + v_inc, v_gap)
'. No he comprobado si esto funciona con números negativos.
La adaptación a MySQL u otro DBMS se deja como un ejercicio para el lector.
¿Cuál es tu pregunta? ¿Que estás tratando de hacer? ¿Está tratando de devolverlos en el orden del valor de la columna de orden? (ORDEN POR orden) – Theresa
La idea es (creo): establecer el número de orden de id = 3 a 1 (de 3); ahora, vuelva a ordenar los registros entre los valores nuevos y antiguos (orden = 1, 2) para conservar el orden anterior, pero luego de id = 3. Entonces, cuando los datos se seleccionan con 'ORDER BY order', la secuencia será id = 3, 1, 2, 4. –
Estoy buscando un procedimiento o método que actualice los valores de orden para ordenarlo según la actualización valor. Actualizo una sola fila, y luego valores más bajos que el orden real de esta fila y más alto que la orden actualizada obtendrá +1 en su valor – markcial