2009-05-08 6 views
19

J'ai une question générique que je vais essayer d'expliquer en utilisant un exemple.MySQL/SQL: Mise à jour avec sous-requête corrélée de la table mise à jour elle-même

Dire que j'ai une table avec les champs: « id », « name », « catégorie », « rapport » « apparences » et

L'idée est que j'ai plusieurs éléments, chacun liés à un seul catégorie et "apparaît" plusieurs fois. Le champ de ratio doit inclure le pourcentage d'apparitions de chaque élément sur le nombre total d'apparitions d'éléments dans la catégorie.

En pseudo-code ce que je dois est le suivant:

  • Pour chaque catégorie
    trouver la somme totale des apparences pour les éléments qui s'y rattachent. Par exemple, il peut être fait avec (select sum("appearances") from table group by category)

  • Pour chaque élément
    définir la valeur du rapport que les apparences de l'élément divisé par la somme trouvée pour la catégorie ci-dessus

Maintenant, je suis essayer d'y parvenir avec une seule requête de mise à jour, mais ne peut pas sembler le faire. Ce que je pensais que je devrais faire est:

update Table T  
set T.ratio = T.appearances/ 
( 
select sum(S.appearances)  
from Table S  
where S.id = T.id  
) 

Mais MySQL n'accepte pas le T alias dans la colonne de mise à jour, et je n'a pas trouvé d'autres moyens d'y parvenir.

Des idées?

Répondre

45

Après les deux réponses que j'ai reçues (dont aucune n'était complète, j'ai écrit la mienne), ce que j'ai finalement fait est comme suit:

UPDATE Table AS target 
INNER JOIN 
(
select category, appearances_sum 
from Table T inner join (
    select category as cat, sum(appearances) as appearances_sum 
    from Table 
    group by cat 
) as agg 
where T.category = agg.cat 
group by category 
) as source 
ON target.category = source.category 
SET target.probability = target.appearances/source.appearances_sum 

Cela fonctionne très rapidement. J'ai aussi essayé avec la sous-requête corrélée mais c'était beaucoup plus lent (ordres de grandeur), donc je m'en tiens à la jointure.

+0

Veuillez marquer une réponse comme réponse afin que cette question soit retirée de la liste des questions sans réponses :) –

+1

@Frans: J'ai dû attendre 48 heures avant que je puisse le faire, règles de stack-overflow :) –

+0

Nice. Merci d'avoir pris le temps de donner un exemple complet! – Ben

3

Voici comment cela se fait dans MSSQL, je pense que MySQL est identique ou similaire:

create table T (id int, ratio float, appearances int) 
insert T values (1, null, 2) 
insert T values (1, null, 3) 

update T 
set ratio = cast(appearances as float)/ agg.appearancesSum 
from T join (
    select id, sum(appearances) as appearancesSum 
    from T 
    group by id 
) as agg on t.id = agg.id 
+0

Désolé, cela ne fonctionne pas dans MySQL. Je ne suis pas en train de voter parce que je suis sûr que cela fonctionne sur mssql ... –

6

Utiliser joint juste après MISE À JOUR: Reference Manual – 13.2.11 UPDATE Syntax

si MISE À JOUR table1 jointure interne table2 sur. ... set table1.foo = valeur où table2.bla = someothervalue

Avec ce genre de choses, regardez toujours le manuel. MySql a un manuel de référence approprié, donc il ne devrait pas être si difficile d'obtenir la bonne syntaxe;)

+0

Merci, je vais essayer dès que je peux. Et en passant - j'ai fait RTFM et essayé tout ce qui avait du sens avant de poster la question :) –

+0

merci, l'entrée manuelle m'a clearifié la solution.positif pour vous également –