2014-12-19 11 views
6

ho una stringa restituita da una query che recita:di SQL Server utilizzando variabili nella query perno

+----------------------+  
| returnquerystring | 
+----------------------+ 
| exam1,exam2,exam3 | 
+----------------------+ 

Sto usando questo restituito stringa come nomi di colonna in una query di rotazione.

select * from (select score,exam from table1) x 
pivot (max(score) for exam in (exam1,exam2,exam3) 

Questa interrogazione mi funziona dando

+-------------+-----------+-----------+ 
| exam1 | exam2 | exam3 | 
+-------------+-----------+-----------+ 
|  10  |  20 |  30 | 
+-------------+-----------+-----------+ 

Tuttavia non sono stato in grado di ottenere il pivot "in" dichiarazione di usare qualsiasi cosa ma i valori hard coded di exam1, exam2, exam3. Ad esempio, ho utilizzato SSMS e ho creato una query che mette correttamente exam1, exam2, exam3 in @ var1. Tuttavia @ var1 genera ed errore se usato al posto di exam1, exam2, exam3.

declare @var1 varchar(100) 
select @var1 = value from table 
select * from (select score,exam from table1) x 
pivot (max(score) for exam in (@var1) 

Incorrect syntax near '@var1'. 

Per verificare che stavo facendo correttamente ho fatto questo e ha funzionato.

declare @var1 int 
select top 1 @var1 = id from name 
select * from name where id = @var1 

Questo ha fornito la riga di dati per id 1 sulla tabella nome senza errori.

Ho notato nei miei esperimenti che (esame 1, esame 2, esame 3) non può essere ('esame1, esame2, esame3') con le virgolette.

Sto utilizzando ColdFusion CFSCRIPT e sembra che le virgolette singole stiano entrando nella query, quindi ho provato vari test con le funzioni di ColdFusion per rimuoverli senza successo.

Così ho provato a utilizzare la funzione SQL Server 'replace' attorno a @ var1 e che genera un errore sulla sintassi al momento della sostituzione.

Questo è quando ho provato a utilizzare un esempio come sopra in SSMS e ho ancora errori. Quindi rimuovendo ColdFusion dall'equazione non funziona ancora. Il mio pensiero era quello di inviare l'intero dichiarare tramite pivot come una query per evitare problemi di ColdFusion ma non funziona in SSMS.

Sto usando SQL Server 8 e 11. SSMS

Tutte le idee su come fare questo lavoro?

examColumns = exam1,exam2,exam3 

public any function qryExamScores(string examColumns) { 
    thisQry = new Query(); 
    thisQry.setName("returnqry"); 
    thisQry.setDatasource(application.datasource); 
thisQry.addParam(name="columnNames",value=arguments.examColumns,cfsqltype="cf_sql_varchar"); 
    result = thisQry.execute(sql=" 
     select * from 
     (select id,score,exam 
     from table 
     where value1 = 'XXXXX' 
     and value2 = '11111') x 
     pivot 
     (
      max(score) for exam in (:columnNames) 
     ) p 

    "); 
    returnqry = result.getResult(); 
    return returnqry; 
} 
+1

CRONACA - se avete bisogno di apici per essere passato "così come sono" da ColdFusion è necessario utilizzare la funzione di 'preservesinglequotes()' - altrimenti CF sfugge helpully apici ammesso che sono parte di una variabile di carattere per inserire o aggiornare. –

+0

Credo che SQL dinamico sarà richiesto; tuttavia la tabella contiene solo una riga? nella tua verifica hai fatto il primo 1, ma nella tua selezione non l'hai fatto. Mi ha fatto pensare che più file potrebbero tornare indietro e il "dentro" non può gestirlo. – xQbert

+0

Mark sembra che ColdFusion stia mettendo le virgolette singole e io non le voglio. È CFSCRIPT quindi sto passando exam1, exam2, exam3 come un param varchar come: parametervalue. Ricevo un errore che sembra che ci siano delle virgolette ma quando esco dalla stringa che entra nella funzione non ce ne sono. Se hai un modo di usare ColdFusion, sono tutto orecchie. – dutchlab

risposta

3

è necessario utilizzare Dynamic SQL di utilizzare il valore della variabile (@ var1) all'interno Pivot

declare @var1 varchar(100)='',@sql nvarchar(max) 
select top 1 @var1 = value from table 

set @sql = 'select * from (select score,exam from table1) x 
pivot (max(score) for exam in (['[email protected]+'])) piv' 

exec sp_executesql @sql 

Se si desidera avere più di un valore in colonne di articolazione usano questo.

SELECT @var1 += '[' + Isnull(CONVERT(VARCHAR(50), value), '') + '],' 
FROM table 

SELECT @var1 = LEFT(@var1, Len(@var) - 1) 

SET @sql = 'select * from (select score,exam from table1) x 
      pivot (max(score) for exam in (' + @var1 + ')) piv' 

EXEC Sp_executesql @sql 
2

passando exam1, exam2, exam3 come varchar param come: ParameterValue

Queryparam (o legare variabili) può essere utilizzata solo su letterali. Poiché "exam1, exam2, exam3" vengono utilizzati come nomi di colonna in questa query specifica, non è possibile applicare loro queryparam. Quando lo fai, stai dicendo al database che quei valori sono semplici stringhe. Ciò causa un errore perché pivot prevede nomi oggetto, non stringhe.

Rimuovere il queryparam e la query funzionerà come previsto.Tuttavia, ovviamente, questo potrebbe esporre il database a SQL injection (a seconda dell'origine di columnNames). Lo stesso vale per l'utilizzo di qualsiasi SQL dinamico (exec, sp_executesql, ...). Quindi assicurati di convalidare completamente l'input prima di implementare questo approccio.

... 
// build pivot statement with dynamic column names 
columnNames = "exam1,exam2,exam3"; 
sqlString = "SELECT * 
      FROM (
        SELECT score,exam 
        FROM table1 
       ) x 
      PIVOT 
      ( 
       MAX(score) FOR exam IN ("& columnNames &") 
      ) 
      AS pvt "; 
result = qry.execute(sql=sqlString).getResult(); 
writeDump(result); 

Edit:

Inoltre, probabilmente si dovrebbe racchiudere i nomi delle colonne tra parentesi per evitare errori di sintassi se i valori contengono spazi o altri caratteri non validi per i nomi di colonna.

"[exam1],[exam2],[exam3]"; 
+0

Leigh, grazie per l'informazione. Sospettavo che il queryparam fosse il problema e volevo capire tutto intorno senza rimuoverlo. Ho usato con successo il metodo sql dinamico e ho passato il tutto come una query. Esaminerò per vedere quale causa meno un rischio per la sicurezza. Quindi ora il dilemma di scegliere solo una risposta corretta per questo post. Esiste la soluzione ovvia che consiste nel creare una stored procedure nel database, ma quando si è un appaltatore senza le chiavi del database è necessario trovare un lavoro. – dutchlab

+0

(Modifica) Bene, un processo memorizzato sarebbe ancora un rischio perché anch'esso richiederebbe sql dinamico. Sfortunatamente, non penso che tu possa "parametrizzare" un 'pivot' - con qualsiasi metodo. Quindi può essere sei di uno, mezza dozzina dell'altro. Francamente, SQL dinamico è sempre rischioso. Quindi non permettere ciecamente l'esecuzione di una stringa qualsiasi di sql, e accertati di convalidare - * un sacco * :) A proposito, l'altra risposta è perfettamente valida. Quindi sentiti libero di scegliere la risposta che si adatta meglio qui. Volevo solo aggiungere una spiegazione dalla prospettiva CF agli archivi. – Leigh

Problemi correlati