Mysql
 sql >> Base de données >  >> RDS >> Mysql

Requête de sélection MySQL avec nom de colonne variable

La solution la plus simple consiste à utiliser deux requêtes distinctes.

Nous utilisons le résultat de la première requête pour générer dynamiquement le texte SQL de la deuxième requête.

mysql> SET @colname := '' ; 
mysql> SELECT t.rslt FROM table1 t WHERE t.id = 1 ORDER BY t.rslt LIMIT 1 INTO @colname ;

mysql> SET @sql := CONCAT('SELECT `',@colname,'` FROM table2 ORDER BY 1') ;
mysql> PREPARE stmt FROM @sql ; 
mysql> EXECUTE stmt ;

mysql> DEALLOCATE PREPARE stmt ;

N.B. y compris @colname dans le cadre du texte SQL, SQL préparé dynamiquement, est une vulnérabilité potentielle d'injection SQL.

Si l'exigence est de faire quelque chose de similaire dans le contexte d'un célibataire SQL, l'instruction doit anticiper les valeurs possibles à renvoyer pour la requête de table1 et inclure des références explicites aux colonnes possibles de table2. Par exemple, quelque chose comme ceci :

  SELECT CASE ( SELECT t.rslt FROM table1 t WHERE t.id = 1 LIMIT 1 )
           WHEN 'r1' THEN r.r1 
           WHEN 'r2' THEN r.r2 
           WHEN 'r3' THEN r.r3 
           ELSE NULL
         END AS c2
    FROM table2 r
   ORDER BY ...

Ce n'est pas nécessairement la manière la plus efficace d'écrire la requête, mais cela illustre le modèle.

Dans une instruction SQL, les identificateurs (noms de table, noms de colonne, noms de fonction) doivent être spécifiés explicitement ; ceux-ci ne peuvent pas être dérivés dynamiquement au moment de l'exécution. Cela est dû à la façon dont les instructions SQL sont traitées... analyser le texte SQL pour la syntaxe, puis analyser la sémantique (références et privilèges valides), évaluer le coût relatif des chemins d'accès disponibles, sélectionner un plan d'exécution, puis exécuter ce plan.

Autrement dit, le comportement observé avec ce SQL correspond à ce que nous attendons :

 SELECT (SELECT rslt FROM table1 WHERE id = 1) FROM table2

Le texte SQL est préparé, et au moment de l'exécution, pour chaque ligne de table2, la sous-requête dans le SELECT liste est exécutée. Si la sous-requête renvoie une valeur scalaire, la valeur scalaire est renvoyée sous forme de colonne de la requête externe. La valeur renvoyée par la sous-requête est une valeur , il n'est pas (et ne peut pas être) évalué comme un nom de colonne.