2016-04-07 16 views
1

Ich verwende ColdFusion und versuche eine Funktion zu erstellen, mit der ich den Wert einer bestimmten Spalte in einem bestimmten Konto abrufen kann (jedes Konto ist sein eigener Datensatz/Reihe).Abrufen einer einzelnen Ausgabe von cfquery, wenn die Abfragespalte die Variable cfqueryparam ist

Eine Funktion wie das funktioniert gut:

<cffunction name="getColumnValueFromAccount" access="public" returntype="string" > 
    <cfargument name="accountName" type="string" required="yes" /> 

    <cfquery name="getColumn" datasource="mydatasource"> 
     <!--- Note that the line below is 'hard-coded.' ---> 
     SELECT role_ExampleSystem 
     FROM table_name 
     WHERE (accountName = <cfqueryparam cfsqltype="cf_sql_varchar" maxlength="50" value='#accountName#'>) 
    </cfquery> 

    <!--- It's easy to return the column value when you know what its name was. ---> 
    <cfreturn getColumn.role_ExampleSystem > 

</cffunction> 

Aber was ich eigentlich will, ist eine Funktion, die mir die Spaltennamen lesen aus, und beseitigt die Notwendigkeit für die Herstellung eine Reihe von nahezu identischen CF angeben kann, Funktionen, die nur einen anderen fest codierten SELECT-Parameter haben. Ich denke, es sollte ungefähr so ​​aussehen, aber ich habe Probleme, die einzelne Zeichenfolge zu lesen, von der ich glaube, dass sie zurückkehren sollte.

<cffunction name="getColumnValueFromAccount" access="public" returntype="string" > 
    <cfargument name="accountName" type="string" required="yes" /> 
    <!--- Trying to accept a column name as an argument ---> 
    <cfargument name="columnName" type="string" required="yes" /> 

    <cfquery name="getColumn" datasource="mydatasource"> 
     <!--- I'm trying to use cfqueryparam to add specify the column name to select. ---> 
     SELECT <cfqueryparam cfsqltype="cf_sql_varchar" maxlength="50" value='#columnName#'> 
     FROM table_name 
     WHERE (accountName = <cfqueryparam cfsqltype="cf_sql_varchar" maxlength="50" value='#accountName#'>) 
    </cfquery> 

    <!--- This line doesn't work. ---> 
    <cfreturn getColumn[#columnName#] > 

</cffunction> 

Ich dachte, dass Sie in der Lage waren, in einer Klammer-Notation Variablen verwenden wie getColumn[#columnName#] oder getColumn[columnName], weil jemand es in einem comment erwähnt. Aber wenn ich versucht habe, Variablen selbst zu verwenden, hat es nicht wie erwartet funktioniert. Ich bekomme diese Fehlermeldung:

The value returned from the getColumnValueFromAccount function is not of type string. If the component name is specified as a return type, it is possible that either a definition file for the component cannot be found or is not accessible.

Jede Idee, welchen Weg ich soll, wenn ich das einzige Ergebnis eines cfquery erhalten möchten, aber ich bin nicht eine hartcodierte Spaltennamen in der SELECT-Teil meiner Verwendung Abfrage? Normalerweise ist dieser Prozess sehr einfach, aber wenn Ihr Spaltenname eine Variable ist, werden die Dinge etwas anders.

+0

* Ich versuche cfqueryparam zu verwenden, um den zu wählenden Spaltennamen anzugeben. * Dies ist nicht möglich. CFQueryparam kann nur für Literale verwendet werden, nicht für Dinge, die als SQL-Befehle ausgewertet werden müssen - wie Tabellen- oder Spaltennamen. – Leigh

+0

Das könnte Teil des Problems sein, und technisch brauche ich nicht den SQL-Injection-Schutz, den cfqueryparam bietet, weil das cfargument für columnName etwas ist, das ich in einer anderen serverseitigen Funktion angegeben habe. Keine Notwendigkeit, die Eingabe zu reinigen, weil ich weiß, dass es etwas sein wird, das ich geschrieben habe. – Ectropy

+1

Ich habe das 'cfqueryparam' entfernt, wie Sie es vorgeschlagen haben, und es durch eine '# variable #' ersetzt. Dann habe ich Mark A Krugers korrigiertes Beispiel für die Verwendung der Klammernotation verwendet. Es sieht so aus, als ob es wie erwartet funktioniert! Ich poste, was ich am Ende für den Fall habe, dass es den Menschen in der Zukunft hilft. – Ectropy

Antwort

1

Meine Lösung:

Basierend auf Leighs Rat, den ich nicht cfqueryparam in der Art und Weise verwenden, kann ich es zu benutzen versuchte, und Mark A Krügers answer konnte ich meinen Code modifizieren und bekommen sie zu arbeiten. Es sieht nun wie folgt aus:

<cffunction name="getColumnValueFromAccount" access="public" returntype="string" > 
    <cfargument name="accountName" type="string" required="yes" /> 
    <cfargument name="columnName" type="string" required="yes" /> 

    <cfquery name="getColumn" datasource="mydatasource"> 
     SELECT #columnName# 
     FROM table_name 
     WHERE (accountName = <cfqueryparam cfsqltype="cf_sql_varchar" maxlength="50" value='#accountName#'>) 
    </cfquery> 

    <cfreturn getColumn[columnName][1] > 

</cffunction> 

es jetzt ein Konto Rolle in einem bestimmten System korrekt zurückgibt, dh wenn Konto accountName ein admin in ExampleSystem ist und ich bestanden in role_ExampleSystem der Funktion als ColumnName die Funktion admin zurück, wie erwartet .

Warnung: Meine Lösung könnte bei falscher Verwendung ein SQL-Injektionsrisiko darstellen!

ein Coldfusion-Variable in einer SQL-Anweisung wie diese keinen Schutz vor SQL-Injection bietet nicht verwenden, so dass es eine sehr schlechte Idee ein Benutzer sein würde, erlauben, die Daten einzugeben, die hier für die columnName verwendet wird .In meinem Fall wird diese Funktion immer nur von anderen serverseitigen Funktionen aufgerufen, die von mir geschrieben wurden, und die Daten, die für columnName verwendet werden, sind in der serverseitigen Funktion hartcodiert. Die accountName, auf der anderen Seite, ist benutzerdefiniert, so ist es wichtig, dass es in einem cfqueryparam ist.

Eine Alternative, sicherere Lösung:.

Mark A Kruger mentioned dass es vielleicht eine bessere Idee, nur jede Spalte auszuwählen, die Sie benötigen könnten und lesen nur die, die Sie in wirklich interessiert Dies scheint ein ziemlich gute Idee. Schließlich ist es unwahrscheinlich, dass jede (relevante) Spalte für einen Datensatz einen viel größeren Datenbankaufruf als mein einzelnes Spaltenbeispiel erhält - es sei denn, Ihre Datenbank enthält riesige Datensätze mit Tonnen von Spalten. Sie können es auch so machen, und als Nebeneffekt brauchen Sie sich keine Gedanken über die SQL-Injektionen zu machen, die Sie mit einer normalen Coldfusion in einem cfquery eröffnen könnten.

Alle Antworten und Kommentare zu lesen war sehr aufschlussreich. Hoffentlich hilft diese Frage und ihre Antworten anderen Menschen, die an ähnlichen Dingen in ColdFusion interessiert sind!

+2

Ja, ich war im Begriff zu sagen, nicht mit der Funktion zu tun :) Viel einfacher, nur alle Spalten zurückgeben, wie Mark vorgeschlagen. Wenn die Tabelle nicht eine Reihe von BLOB-Spalten enthält, sollte dies ein großer Deal sein. – Leigh

+0

Einverstanden. All diese Arbeiten, um SQL nur einen Wert zurückzugeben, sind irgendwie sinnlos, da die Bandbreite heutzutage ziemlich billig ist. – Ectropy

+1

Außerdem speichert die Datenbank den Ausführungsplan wahrscheinlich effektiver als eine Reihe verschiedener Anweisungen, die verschiedene Spalten auswählen. Vor allem, wenn Sie cfqueryparam verwenden. – Leigh

3

Eine Abfrage ist eine Struktur von Arrays wie in Queryname [Schlüssel] [1].

Es funktioniert in erster Linie wegen der Abwärtskompatibilität. Von Anfang an könnten Sie queryname.columnname und CF die erste Zeile der Abfrage für diese Spalte ausgeben. Sobald Sie zur Objektsyntax wechseln, funktioniert das nicht mehr so.

Versuchen Sie dies in Ihrem cfreturn:

getColumn[columnName][1] 

Hinweis - Sie nicht über die Pfund-Zeichen in Ihrem cfreturn Beispiel benötigen.

+0

Diese Methode funktionierte, nachdem ich '' columnName' 'cfqueryparam' geändert und durch eine reguläre Coldfusion-Variable wie # # columnName #' ersetzt hatte. – Ectropy

+0

yeah - habe das Problem nicht in deinem Code gesehen, sorry. cfqueryparam bindet eine Variable an einen primitiven "Typ" - daher ist sie nicht als Spaltenname verfügbar. –

+2

Denken Sie nur daran, dass Sie mit dem Spaltennamen in Ihrer Abfrage auf SQL Injection zugreifen (da ich eine Zeichenfolge übergeben kann, die direkt in Ihrer Abfrage dynamisch verwendet wird). Lassen Sie daher keine USER-Eingaben an die Funktion zu. In der Tat, es gibt keinen Grund, nicht nur jede Spalte auszuwählen und lassen Sie Ihre cfreturn aussortieren, was Sie zurückgeben eh? –