Mysql
 sql >> Database >  >> RDS >> Mysql

Query di selezione MySQL con nome di colonna variabile

La soluzione più semplice consiste nell'utilizzare due query separate.

Usiamo il risultato della prima query per generare dinamicamente il testo SQL per la seconda query.

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 ;

NB incluso @colname come parte del testo SQL, SQL preparato dinamicamente, è una potenziale vulnerabilità di SQL Injection.

Se il requisito è fare qualcosa di simile nel contesto di un single SQL, quindi l'istruzione deve anticipare i possibili valori da restituire per la query da table1 e includere riferimenti espliciti alle possibili colonne da table2. Ad esempio, qualcosa del genere:

  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 ...

Questo non è necessariamente il modo più efficiente per scrivere la query, ma mostra il modello.

All'interno di un'istruzione SQL, gli identificatori (nomi di tabelle, nomi di colonne, nomi di funzioni) devono essere specificati in modo esplicito; questi non possono essere derivati ​​dinamicamente in fase di esecuzione. Ciò è dovuto al modo in cui le istruzioni SQL vengono elaborate... analizzando il testo SQL per la sintassi, quindi analizzando la semantica (riferimenti e privilegi validi), valutando il costo relativo per i percorsi di accesso disponibili, selezionando un piano di esecuzione e quindi eseguendo quel piano.

Cioè, il comportamento osservato con questo SQL è quello che ci aspettiamo:

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

Viene preparato il testo SQL e, al momento dell'esecuzione, per ogni riga in table2, la sottoquery in SELECT viene eseguito l'elenco. Se la sottoquery restituisce un valore scalare, il valore scalare viene restituito come colonna della query esterna. Il valore restituito dalla sottoquery è un valore , non è (e non può essere) valutato come nome di colonna.