2009-05-27 6 views
11

Essentiellement je dois faire quelque chose comme ça .... c'est juste un exemple ... mais la syntaxe de la première requête ne fonctionne pas dans MySQLmysql SELECT imbriquée UPDATE de même table

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>; 

Une seule personne peut avoir le prix Or dans n'importe quelle classe. Je ne connais que le person_id de la personne qui reçoit le prix Or.

J'essaie d'éliminer tous les anciens gagnants du prix Or dans la même classe que person_id dans la première requête. Ensuite, définissez le nouveau gagnant Gold dans la seconde. Je crois que je dois utiliser un type de jointure interne, mais je ne suis pas sûr à 100% sur ce point.

Ce qui serait encore plus intelligent si je pouvais faire le tout en une seule requête!

Quelqu'un peut-il donner des conseils?

Merci :)

Répondre

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

Cela accordera tous les utilisateurs avec un prix Silver, à l'exception du @lucky celui qui obtient le Gold.

Si vous avez seulement besoin de mettre à jour le @lucky et l'ex-champion, exécutez la commande suivante:

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

Cela ne veut pas faire la même chose que publiée dans la question. Vous remplacez tous les prix d'une classe par "Or" ou "Argent", tandis que la requête ci-dessus ne supprime que les prix "Or" et en définit une nouvelle. Exemple: et si une personne avait un prix "Bronze"? – VVS

+0

@David Hympohl: Bon point, vous pouvez le faire en ajoutant "WHERE class = 'Gold' ou id = @lucky" à la fin de la requête. – Andomar

+0

@David: la requête @ op définit le prix sur '' pour chaque personne de la classe. Je viens de remplacer un '' par 'Silver' pour plus de lisibilité. – Quassnoi

0

Vous pouvez certainement créer une procédure stockée qui prend l'identifiant du nouveau lauréat du prix comme argument.

Ensuite, vous pouvez appeler cette procédure stockée sur une ligne.

J'utilise MS SQL ici, mais quelque chose de similaire à:

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 vous êtes après une seule déclaration, vous pouvez utiliser l'opérateur CASE? Non utilisé MySQL, mais quelque chose comme:

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'est-ce que CASE QUAND '' ALORS est supposé faire? Renvoie toujours false sur mon serveur. :) – Andomar

+0

ah désolé, ne l'avait pas testé. Vous pouvez utiliser le prix CASE WHEN 'Gold' ALORS .... ou si vous avez besoin d'utiliser une expression CASE WHEN = prix 'Gold' ALORS ... WHEN prize = '' ALORS .... –

0

Depuis que vous faites deux mises à jour distinctes, il n'y a pas besoin de le faire dans une requête. Si vous avez peur des données incohérentes car l'une des deux requêtes peut échouer, vous pouvez utiliser les transactions et l'annulation de l'une des deux requêtes échoue.

Votre requête actuelle est totalement lisible et compréhensible alors que les solutions affichées sont loin d'être faciles à lire.

10

Il n'est pas toujours préférable de faire des mises à jour complexes dans une seule requête SQL. En fait, il pourrait être plus efficace d'exécuter deux requêtes simples. Veillez donc à comparer les deux solutions.

MySQL prend en charge une extension à la syntaxe UPDATE pour la mise à jour multi-tables. Vous pouvez effectuer un JOIN dans le cadre de la mise à jour au lieu d'utiliser des sous-requêtes.

Ensuite, vous pouvez utiliser la fonction IF() (ou CASE) pour modifier la valeur prize à différentes valeurs conditionnellement.

Donc, si vous devez absolument utiliser une seule requête, essayer quelque chose comme ceci:

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'; 

Ou cette alternative:

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

les prix des propriétaires de leur médaille? – Andomar

+0

@Andomar: Vous avez raison. J'ai édité la réponse avec ceci en tête. –