2011-12-07 13 views
12

Tengo una tabla con índice único en dos columnas, id_parent y sort_order para ser precisosMysql suprimir temporalmente índice único

+----+-----------+------------+-------------+-------------+-------------+ 
| id | id_parent | sort_order | some_data | other_data | more_data | 
+----+-----------+------------+-------------+-------------+-------------+ 
| 1 |   1 |   1 | lorem ipsum | lorem ipsum | lorem ipsum | 
| 2 |   1 |   2 | lorem ipsum | lorem ipsum | lorem ipsum | 
| 3 |   1 |   3 | lorem ipsum | lorem ipsum | lorem ipsum | 
+----+-----------+------------+-------------+-------------+-------------+ 

Ahora quiero actualizarlos, sus datos y su sort_order en una marcha. sort_order cambiaría de 1 - 2 - 3 a, por ejemplo, 2 - 3 - 1.

Pero cuando empiezo a ejecutar las instrucciones de actualización, el índice único me bloquea, como se esperaba, diciendo que no puedo tener dos filas con id_parent = 1 and sort_order = 2. Bueno, podría configurarlo 4 por ahora, actualizar otras filas en el orden correcto y luego configurar esta. Pero luego, tendría que ejecutar una declaración adicional, y probablemente agregue lógica adicional a mi lenguaje de scripting para determinar el orden correcto de las actualizaciones. También uso ORM, y se vuelve aún más inconveniente.

Mi pregunta ahora, ¿hay algún método para hacer caso omiso de MySQL temporalmente este índice? Como comenzar una transacción especial, ¿en qué índices se calcularían justo antes de comprometerla?

+0

Son sus tablas InnoDB o MyISAM? – Pacerier

Respuesta

6

Por lo que yo sé que no es posible.

La única vez que he visto nada de eso es que se pueden deshabilitar las teclas no únicos en tablas MyISAM. Pero no en InnoDB y no en claves únicas.

Sin embargo, para ahorrarle una actualización o dos, no hay necesidad de tener el número exacto 1, 2 y 3. Se podría así tener 4, 5 y 6. Derecho? Lo usarías en un orden por y nada más para que los números exactos no sean importantes. Incluso te guardará una actualización si eres inteligente. Desde su ejemplo

update table set sort_order = 4 where sort_order = 1 and id = 1 and id_parent = 1; 

Nuevo orden de clasificación es 2, 3, 1. Y en una sola actualización.

+1

Lástima de mí, usar 4-5-6 era tan obvio. – Nameless

+0

Estoy de acuerdo con que eso sea imposible con múltiples actualizaciones. Sin embargo, actualizarlos en una sola declaración podría funcionar. De cualquier manera, es +1 para una solución que es clara y simple. –

4

‘Pero cuando comienzo a correr actualización declaraciones ...’ - Lo entiendo, se trató la actualización de los valores utilizando instrucción UPDATE múltiple, como en un bucle. ¿Es eso así? ¿Qué hay de actualizarlos de una vez? Así, por ejemplo:

UPDATE atable 
SET sort_order = CASE sort_order WHEN 3 THEN 1 ELSE sort_order + 1 END 
WHERE id_parent = 1 
    AND sort_order BETWEEN 1 AND 3 

Una sola instrucción es atómica, por lo que, en el momento termina esta actualización, los valores de sort_order, aunque ha cambiado, siguen siendo únicos.

no puedo probar esto en MySQL, lo siento, pero definitivamente funciona en SQL Server, y creo que el comportamiento respeta las normas.

+0

No lo he pensado. Sin embargo, sería doloroso usarlo con ORM. Esto está más cerca de la respuesta correcta en una pregunta específica y luego responde por Andreas, pero probablemente termine usando su consejo. ¿Qué debo hacer con la respuesta seleccionada en este caso? Darlo a la respuesta que voy a usar, o para responder cuál está más cerca del tema? – Nameless

+0

Bueno, en caso de que más de una respuesta coincida con la * pregunta *, probablemente debería ir con la que va a aplicar para resolver el * problema real *. Entonces, probablemente sea la respuesta de Andreas la que debes elegir. Sin embargo, pueden existir otras consideraciones. ¡Estoy bien con tu decisión, de todos modos! –

+3

Eso no funcionará a menos que las filas se actualicen realmente en el orden correcto. No hay tiempo durante la ejecución, se puede violar la clave única. 'update sorttest set sort = sort + 1 order by sort desc;' no funcionará sin la ordenación descendente, la primera fila violaría la clave, incluso si la segunda fila está a punto de moverse fuera de lugar. –

0

Nota: Algunos comentarios han mencionado que la respuesta a continuación no siempre a suprimir restricciones únicas, especialmente en InnoDB. Si puede mejorar esta respuesta, haga clic en "Editar" y realice mejoras.

Usted puede simplemente añadir esta línea al inicio de la secuencia de comandos:

SET UNIQUE_CHECKS=0; 

Es común el uso de esto en conjunción con:

SET FOREIGN_KEY_CHECKS=0; 

La variable UNIQUE_CHECKS se menciona en los documentos aquí:
http://dev.mysql.com/doc/refman/5.0/en/converting-tables-to-innodb.html

+2

Acabo de probar esto en 5.6, NO funciona con InnoDB. La clave duplicada todavía arrojó un error. – bluecollarcoder

+0

@bluecollarcoder ¿Has intentado establecer * both * 'UNIQUE_CHECKS' y' FOREIGN_KEY_CHECKS' en cero? ¿Y está seguro de que no está duplicando una * clave principal * que probablemente todavía no está permitida? –

+1

La clave única está en una columna que no hace referencia a ninguna otra tabla, por lo que 'FOREIGN_KEY_CHECKS' es irrelevante aquí. Y la columna con clave única definitivamente no es parte de la clave principal. ¿En qué situación pudo obtener 'UNIQUE_CHECKS = 0' para funcionar como se esperaba en este caso? – bluecollarcoder

Cuestiones relacionadas