web-dev-qa-db-fra.com

Passer une valeur à une sous-requête imbriquée

J'ai la requête suivante (allégée pour plus de concision), dont le but est de créer le w8 valeur utilisée pour classer les résultats:

SELECT elements.id, [ ... ],
(SELECT 
    COALESCE(craft_w8_a.weight, 0) + COALESCE(SUM(craft_w8_b.weight), 0) 
    FROM `craft_w8` `craft_w8_a`
    LEFT JOIN `craft_w8` `craft_w8_b` 
        ON craft_w8_b.elementId
        IN ( SELECT targetId FROM `craft_relations`
                WHERE fieldId IN (15, 16)
                  AND sourceId = elements.id)
    WHERE craft_w8_a.elementId = elements.id
) as w8
FROM `craft_elements` `elements`
[ ... ]
GROUP BY `elements`.`id`
ORDER BY `w8` DESC, `name` ASC LIMIT 100

Le problème que je rencontre est que la deuxième sous-requête imbriquée (celle de la jointure gauche) est incapable de trouver la colonne elements.id à partir de la sélection initiale.

D'après ce que j'ai trouvé, la recherche autour de SQL ne transmet les valeurs qu'à un niveau et je n'ai pas pu trouver de solution de contournement appropriée.

Est-il possible de forcer SQL à passer une valeur plus profonde qu'un niveau? Ou existe-t-il un moyen de modifier la requête pour ne pas utiliser une autre sous-requête, mais toujours obtenir le même résultat?

Désolé si je fais quelque chose de stupide ou si j'ai raté quelque chose d'évident, SQL n'est pas mon point fort!

4
Tam

À ma connaissance, cette limitation concerne SQL spécifiquement dans MySQL. Tous les autres produits SQL que je connais ne l'ont pas.

Il ne semble pas y avoir de solution à ce problème en général: vous ne pouvez pas forcer une référence de colonne à être reconnue plus profondément qu'un niveau dans MySQL. Cependant, il existe une solution simple dans votre cas spécifique: remplacez le elements.id dans la requête la plus profonde avec craft_w8_a.elementId:

SELECT elements.id, [ ... ],
(SELECT 
    COALESCE(craft_w8_a.weight, 0) + COALESCE(SUM(craft_w8_b.weight), 0) 
    FROM `craft_w8` `craft_w8_a`
    LEFT JOIN `craft_w8` `craft_w8_b` 
        ON craft_w8_b.elementId
        IN ( SELECT targetId FROM `craft_relations`
                WHERE fieldId IN (15, 16)
                  AND sourceId = craft_w8_a.elementId)
    WHERE craft_w8_a.elementId = elements.id
) as w8
FROM `craft_elements` `elements`
[ ... ]
GROUP BY `elements`.`id`
ORDER BY `w8` DESC, `name` ASC LIMIT 100

Ceci est un substitut équivalent car quel que soit craft_w8_a.elementId sera transmis à la sous-requête IN qui correspondra à elements.id en fonction du filtre de la requête qui transmet la valeur.

4
Andriy M