La requête échoue car vous ne pouvez pas modifier une table et effectuer une sélection dans cette même table dans une sous-requête.
Je pense que vous pouvez contourner ce problème avec une astuce JOIN :
UPDATE meterreadings AS tgt
INNER JOIN (
SELECT * FROM meterreadings
WHERE meterreadingtype_id = 2
) AS src
ON tgt.meterreadingdate = src.meterreadingdate
AND tgt.location_id = src.location_id
AND tgt.created = src.created
AND tgt.asset_id = src.asset_id
SET tgt.meterreading = src.meterreading
Je ne suis pas un expert MySQL, mais je pense que cela fonctionne car MySQL traite d'abord la sous-requête et stocke le résultat en mémoire sous forme de table temporaire, qui ne change pas pendant la mise à jour. Un effet secondaire de ceci est que si le résultat de la sous-requête est volumineux, vous allez gruger une tonne de (ou manquer de) mémoire.
La seule façon (pour autant que je sache) de contourner le problème de mémoire est de réduire la sous-requête en utilisant des critères qui ne sont pas directement liés à la cible de mise à jour. Par exemple, si vous deviez effectuer ces mises à jour dans le cadre d'un processus nocturne, faites en sorte que le SELECT interne ne renvoie que les lignes créées au cours des ~24 dernières heures.