2009-05-27 11 views
11

Esencialmente tengo que hacer algo como esto .... esto es sólo un ejemplo ... pero la sintaxis de la primera consulta no funciona en MySQLmysql SELECT anidado en ACTUALIZACIÓN misma mesa de

update people set prize = '' 
where prize = 'Gold' and class = (select class from people where id = person_id); 
update people set prize = 'Gold' where id = <id>; 

Solo una persona puede tener el premio de oro en cualquier clase. Solo conozco la persona_id de la persona que recibe el premio de oro.

Estoy tratando de borrar a cualquier ganador de un premio Oro anterior en la misma clase que person_id en la primera consulta. Luego establece el nuevo ganador de Oro en el segundo.

Creo que necesito usar algún tipo de unión interna, pero no estoy 100% seguro de esto.

¡Lo que sería incluso más inteligente si pudiera hacer todo en una consulta!

¿Alguien puede prestar asesoramiento?

Gracias :)

Respuesta

7
UPDATE people 
SET prize = CASE WHEN id = @lucky THEN 'Gold' ELSE 'Silver' END 
WHERE class = (
     SELECT class 
     FROM people 
     WHERE id = @lucky 
     ) 

Esto conceder a todos los usuarios con un premio Silver, excepto el @lucky que obtiene el Gold.

Si sólo necesita actualizar el @lucky y el ex campeón, emita el siguiente:

UPDATE people 
SET prize = CASE WHEN id = @lucky THEN 'Gold' ELSE 'Silver' END 
WHERE id = @lucky 
     OR (class, prize) = 
     (
     SELECT class, 'Gold' 
     FROM people 
     WHERE id = @lucky 
     ) 
+0

Esto no hace lo mismo que ha escrito en la pregunta. Está anulando todos los premios dentro de una clase con "Oro" o "Plata" mientras que la consulta anterior solo quita los premios "Oro" y establece uno nuevo. Ejemplo: ¿qué pasa si una de las personas tiene un precio "Bronce"? – VVS

+0

@David Hympohl: Buen punto, podrías hacer eso agregando "DONDE class = 'Gold' o id = @lucky" al final de la consulta. – Andomar

+0

@David: la consulta de @op fija el premio en '' para cada persona dentro de la clase. Acabo de reemplazar un '' con 'Plata' por legibilidad – Quassnoi

0

Sin duda se puede crear un procedimiento almacenado que toma el identificador del nuevo ganador de premios como argumento.

Luego puede llamar a ese procedimiento almacenado en una línea.

estoy usando MS SQL aquí, pero algo similar a:

CREATE PROC UpdatePrize 
    @newid int 

AS 

UPDATE people 
SET prize = '' 
WHERE prize = 'Gold' 
AND class = (SELECT class 
       FROM people 
       WHERE id = @newid) 

UPDATE people 
SET prize = 'Gold' 
WHERE id = @newid 

GO 
1

Si estás después de una única sentencia que podría utilizar el operador CASO? No se utiliza MySQL, pero algo como:

UPDATE people 
SET prize = CASE 
       WHEN 'Gold' AND id != @newid THEN '' 
       WHEN '' AND id = @newid THEN 'Gold' 
      END 
WHERE class = ( 
       SELECT class 
       FROM people 
       WHERE id = @newid 
      ) 
+0

¿Qué CASO CUANDO '' SE DEBE hacer? Siempre devuelve falso en mi servidor. :) – Andomar

+0

ah, lo siento, no lo había probado. Puedes usar el premio CASE CUANDO 'Oro' ENTONCES .... o si necesitas usar una expresión CASO CUANDO premio = 'Oro' ENTONCES ... CUANDO premio = '' ENTONCES .... –

0

Dado que realiza dos actualizaciones distintas, no es necesario hacerlo en una consulta. Si tiene miedo a los datos incoherentes porque una de las dos consultas puede fallar, puede usar las transacciones y la reversión de cualquiera de las dos consultas falla.

Su consulta actual es totalmente legible y comprensible, mientras que las soluciones publicadas no son fáciles de leer.

10

No siempre es mejor hacer actualizaciones complejas en una sola consulta SQL. De hecho, podría ser más eficiente ejecutar dos consultas simples. Así que asegúrese de comparar ambas soluciones.

MySQL admite una extensión de UPDATE sintaxis para la actualización de varias tablas. Puede realizar un JOIN como parte de la actualización en lugar de utilizar subconsultas.

Luego puede usar la función IF() (o CASE) para cambiar el valor prize a diferentes valores condicionalmente.

Así que si es absolutamente necesario utilizar una sola consulta, intentar algo como esto:

UPDATE people p1 JOIN people p2 
    ON (p1.class = p2.class AND p2.id = <person_id>) 
SET prize = IF(p1.id = <person_id>, 'Gold', '') 
WHERE p1.id = <person_id> OR p1.prize = 'Gold'; 

O esta alternativa:

UPDATE people p1 JOIN people p2 
    ON (p1.class = p2.class AND p2.id = <person_id>) 
SET p1.prize = CASE 
    WHEN p1.id = <person_id> THEN 'Gold' 
    WHEN p1.prize = 'Gold' THEN '' 
    ELSE p1.prize -- other cases are left as is 
END CASE; 
+0

¿No robaría esto? los dueños de los premios de su medalla? – Andomar

+0

@Andomar: tienes razón. He editado la respuesta con esto en mente. –

Cuestiones relacionadas