2010-08-26 7 views
0

Je souhaite mettre à jour une colonne en comparant chaque ligne à toutes les autres lignes du tableau, mais je n'arrive pas à distinguer les noms des colonnes de la ligne en cours de mise à jour par.mySql - mise à jour en comparant des lignes dans la même table

Voici un exemple simplifié ...

personnes:
+--------+-----+----------------+
| name | age | nameClosestAge |
+--------+-----+----------------+
| alice | 20 | |
| bob | 30 | |
| clive | 22 | |
| duncan | 24 | |
+--------+-----+----------------+

Pour remplir la colonne « nameClosestAge » avec le nom de la personne qui est le plus proche en âge de chaque personne, vous pouvez le faire ...

create temporary table peopleTemp like people; 
insert into peopleTemp select * from people; 
update people set nameClosestAge = 
(select name from peopleTemp where people.name != peopleTemp.name 
order by abs(people.age - peopleTemp.age) asc limit 1); 

qui produit cette ....
+--------+-----+----------------+
| name | age | nameClosestAge |
+--------+-----+----------------+
| alice | 20 | clive |
| bob | 30 | duncan |
| clive | 22 | alice |
| duncan | 25 | clive |
+--------+-----+----------------+

Certes, il y a une façon de le faire sans créer une table en double. Je cherche la méthode la plus efficace ici car j'ai une très grande table et sa mise à jour est trop longue. J'utilise mySql avec PHP.

+0

Il est vraiment peu logique de _store_ nameClosestAge (à moins que ce soit pour la mise en cache) car cela crée de la redondance ... – Jasper

+0

Jasper. Ceci est un exemple simplifié. Le calcul pour le champ mis à jour est plus complexe pour le vrai problème. – spiderplant0

+0

... et les requêtes ultérieures nécessitent que je recherche dans le champ mis à jour. – spiderplant0

Répondre

1

Vous pouvez effectuer cela avec une seule sous-requête et aucune table temporaire.

SELECT name, age, (
    SELECT name 
    FROM people 
    WHERE name != ppl.name 
    ORDER BY ABS(people.age - ppl.age) 
    LIMIT 1 
) AS nameClosestAge 
FROM people AS ppl; 

Vérifié et fonctionne :)

EDIT: Si vous voulez être en mesure de travailler avec la ligne calc'ed, vous pouvez utiliser une vue;

CREATE VIEW people_close AS 
    SELECT name, age, (
    SELECT name 
    FROM people 
    WHERE name != ppl.name 
    ORDER BY ABS(people.age - ppl.age) 
    LIMIT 1 
) AS nameClosestAge 
    FROM people AS ppl; 

Vous ne pouvez pas mettre à jour le champ calculé, mais vous pouvez facilement y répondre.

+0

Merci pharalia. Cependant, je ne peux pas comprendre à partir de votre solution comment faire la mise à jour. C'est à dire. ce travail ne marche pas ... personnes mise à jour AS ppl = nameClosestAge définies (SELECT nom FROM personnes WHERE nom = ppl.name ORDER BY ABS (people.age - ppl.age) LIMIT 1 ) – spiderplant0

+0

OK. . c'est une honte. Vous ne pouvez pas utiliser la table que vous mettez à jour dans une sous-requête.Fonctionne avec la table temporaire d'origine en utilisant cela, mais qui bat l'objet de la question ... 'créer une table temporaire peopleTemp like people; insérer dans peopleTemp sélectionnez * parmi les personnes; UPDATE personnes SET le plus proche = (SELECT nom de gensTemp WHERE noms.nom! = PeopleTemp.name ORDRE PAR ABS (people.age - peopleTemp.age) LIMIT 1); ' Une autre façon que vous pourriez le faire pour créer un vue avec la colonne nameClosestAge incluse. – pharalia

Questions connexes