instrucción de actualización con la asignación de valores de columna dinámica: SQL

StackOverflow https://stackoverflow.com/questions/556509

  •  05-09-2019
  •  | 
  •  

Pregunta

Imagine la siguiente consulta SQL:

UPDATE MYTABLE
SET COL2 = (SELECT COL2 + 1 FROM (SELECT MAX(COL2) FROM MYTABLE) AS X)
WHERE ID IN (1,2,3,4,5)

Supongamos que antes de ejecutar la actualización MAX (COL2) es 1.

Mi intención es que para la actualización donde ID = 1 COL2 se actualiza a 'max (COL2) + 1' (es decir, 2), y que para las actualizaciones subsiguientes 'MAX (COL2) + 1' es re-evaluado, por lo que para ID = 2, COL2 = 3 e ID = 3, COL2 = 4 etc ...

Lo que realmente ocurre es que para todas las filas (ID = 1,2,3,4,5), el valor de col2 es 2.

¿Hay una manera inteligente de tener el valor de MAX (col2) 1 "re-evaluado" en cada actualización? Soy consciente de que puede haber problemas de rendimiento con hacer esto, pero tengo curiosidad ninguno de los de menos! ¿Hay una mejor alternativa (que no implica múltiples instrucciones de actualización)?

Por cierto: en caso que usted se está preguntando acerca de la sintaxis utilizada para la consulta anterior (la tabla interna anidada) ver aquí:

¿Fue útil?

Solución

UPDATE mytable, (
  SELECT @loop := MAX(col1)
  FROM
    mytable
  ) o
SET col1 = (@loop := @loop + 1)

Lo que encontró aquí se llama query stability.

No se consulta puede ver los cambios realizados por ella misma o con la siguiente consulta:

UPDATE mytable
SET col1 = col2 + 1
WHERE col1 > col2 

no tendría fin.

Otros consejos

Esta es la forma en que lo haría:

SELECT MAX(col2) FROM mytable INTO @max;

UPDATE mytable
SET col2 = @max:=@max+1
WHERE id IN (1,2,3,4,5)
ORDER BY id;

He probado esto en MySQL 5.1.30 y funciona.

Me puse la variable @max primera simplemente porque encuentro @ truco de hacerlo en un producto cartesiano ser innecesario y menos legible de Quassnoi.

Tenga en cuenta que MySQL soporta ORDER BY en un comunicado UPDATE (esto no es SQL estándar), y usted debe hacer esto, para asegurar que los valores se actualizan en el orden que desee. De lo contrario MySQL garantiza ningún orden específico.

declare @loop int
select @loop = 1

UPDATE MYTABLE
SET COL1 = @loop,
    @loop = @loop+1
WHERE ID IN (1,2,3,4,5)
  
    

¿Hay una manera inteligente de tener el valor de MAX (col1) 1 "reevaluado" en cada insertar?

  

No, a menos que actualice las filas de uno en uno: (

Esto funcionaría en MSSQL, dunno sobre MySQL, pero podría darle una idea:

DECLARE @Counter int

SELECT @Counter = MAX(COL2) FROM MYTABLE

UPDATE MYTABLE
SET @Counter = @Counter + 1,
    COL1 = @Counter
WHERE ID IN (1,2,3,4,5)

EDIT: Creo que la instrucción SET se puede simplificar en MSSQL a:

SET @Counter = COL1 = @Counter + 1

Debe ser re-evaluando en cada una inserción; presumiblemente el máximo de col2 no está cambiando. ¿Estás segura de que no desea seleccionar MAX (COL 1 )? La lectura de su pregunta de nuevo, usted mezcló los términos de inserción y actualización (que ahora es fijo), y conseguir lanzado para un bucle.


Usted está tratando de actualizar muchos registros a la vez, sino que tenga que actuar como si está actualizando cada uno individualmente. Esto no funcionará mientras está con la intención.

Se puede crear un procedimiento almacenado para recorrer cada registro donde id IN (1,2,3,4,5) y actualizar de forma individual. O bien, ya que sólo está haciendo 5 filas, ¿por qué no copiar y pegar la declaración cinco veces y cambiar la cláusula WHERE para WHERE ID = 1 (y 2, 3, 4, 5 en las líneas posteriores).

scroll top