I am new to coldfusion and I am stuck with looping a query within a function. For example, I have a function within which has a query which returns the names which starts with 'a'. but i am able to get only one value (first value) from the database.Actually in the db we have more than 1 values for this query.How should i loop the query within the function?
Any help is appreciated...
<cffunction name="getNames" returntype="any">
<cfargument name="letter" required="true">
<cfquery name="getNamesfrmDB" datasource="test">
select * from employee where firstname like '#arguments.letter#%'
</cfquery>
<cfreturn getNamesfrmDB/>
</cffunction>
<cfoutput>#getNames('a').firstname#</cfoutput>
Thanks in advance...
ahh. I ready your question wrong... disregard previous answer..
You are passing the query straight out of the function, so it will be coming out as a query and you can treat it as such.
Use query="qname" in your cfouptut
<cffunction name="getNames" returntype="any">
<cfargument name="letter" required="true">
... your query ..
<cfreturn getNamesfrmDB/>
</cffunction>
<!---call the function--->
<cfset names = getNames('a')>
<!---now loop over the results using cfoutput--->
<cfoutput query="names">
<p>#firstname#</p>
</cfoutput>
<!---OR ALTERNATIVELY, as you can't use cfoutput inside cfoutput.. so if you are already inside a cfouput, you can also output query results using cfloop--->
<cfoutput>
..some other stuff...
<cfloop query="names">
<p>#firstname#</p>
</cfloop>
..some other stuff..
</cfoutput>
Related
I want to write a function in CF, that has a query that returns multiple columns. I researched and read and could only find examples of functions with sql queries only returning the table view of the struct.
How would I write a function in CF with sql queries and output each column in text format
I been googling it and looking on tutorial websites, with no luck
<cffunction name="queryListEmployee" returntype="query" output="false">
<cfargument name="EMPID" type="numeric" default="1"/>
<cfset var listEmployee = ""/>
<cfquery name="local.listContractors" datasource="DB">
SELECT E.FIRSTNAME, E.LASTNAME
FROM EMPLOYEE E
WHERE E.ID = <cfqueryparam value="#arguments.EMPID#" cfsqltype="cf_sql_decimal" scale="0"/>
</cfquery>
<cfreturn local.listEmployee/>
I want to be able to output column names like queryListEmployee.firstname and queryListEmployee.lastname
You've got the idea right. Just a few tweaks:
<cffunction name="getEmployeeByID" returntype="query" output="false">
<cfargument name="EMPID" type="numeric" default="1"/>
<cfquery name="local.employee" datasource="DB">
SELECT E.FIRSTNAME, E.LASTNAME
FROM EMPLOYEE E
WHERE E.ID = <cfqueryparam
value="#arguments.EMPID#"
cfsqltype="cf_sql_integer"/>
</cfquery>
<cfreturn local.employee/>
</cffunction>
Then call this function like so:
<cfset qEmployee = getEmployeeByID(1)>
and output the data like this:
<cfoutput query="qEmployee">
<li>#qEmployee.FIRSTNAME# #qEmployee.LASTNAME#</li>
</cfoutput>
This function will only ever return one record. You can search and figure out how to dynamically adjust the search criteria in order to return multiple records.
You might check out http://www.learncfinaweek.com/ to get learn more of the basics of ColdFusion.
I have a query that gets called multiple times depending on the the variable vchrStatus
<cffunction name="getGalleriesByStatus" output="no" returntype="query">
<cfargument name="vchrStatus" type="string" required="yes">
<cfquery
name="getGalleries"
datasource="#Application.dsn#">
/// Long complicated query in here
</cfquery>
<cfset var result="#getGalleries#">
<!--- Return it --->
<cfreturn result>
</cffunction>
I tested the function with cfdump and it is outputing the desired results.
Now I want to loop over the results in a cfoutput
<cfoutput query="getGalleriesByStatus('Pending')">
But I'm getting the error: The value of the attribute query, which is currently getGalleriesByStatus('Pending'), is invalid.
<cfoutput> takes the name of the query variable (ie: a string). It does not take an expression which evaluates to a query. So you need this:
<cfset someVar = getGalleriesByStatus('Pending')>
<cfoutput query="someVar">
This is counter-intuitive, but is the case. It's also not in the docs, which sux.
I could not use student_id in cfoutput with query. My argument didn't pass in getStudentAnswers function. How can I do this?
I want to create JSON and need to add question and questions' answers near exam like this:
[
{
"id": "7",
"type": "2",
"question_id": "20",
"question": "Write a summary by answering the questions below: * What is convergence? * What will be the implications of convergence on classical media? on users? * Which devices/media forms do you think will converge nowadays/in the future? * What will be the opportunities and threats emerged by the convergence?",
"question_type": "0",
"answer": "",
"name": "Assignment3ver2",
"deadline_date": "2014-11-22 00:00:00.0"
}
Functions:
<cffunction name="getQuestion" >
<cfargument name="exam_id" type="string" required="true" >
<cfargument name="student_id" type="string" required="true" >
<cfset mert="#student_id#" >
<cfquery dataSource="mobileCourse" name="questselect">
SELECT id,question,question_type FROM dbo.Questions WHERE exam_id=#exam_id#
</cfquery>
<cfoutput query="questselect">
"question_id": "#id#",
"question": "#question#",
"question_type": "#question_type#",
#getStudentAnswers(mert, id, question)#
</cfoutput>
<cfreturn />
<cffunction name="getStudentAnswers" >
<cfargument name="student_id" type="string" required="true" >
<cfargument name="question_id" type="string" required="true" >
<cfargument name="question" type="string" required="true" >
<cfquery dataSource="mobileCourse" name="questselecta">
SELECT * FROM dbo.ANSWERS WHERE question_id=#question_id# AND student_id=#student_id#
</cfquery>
<cfif #questselecta.recordcount# gte 1>
<cfoutput query="questselecta">
"answer": "#answer#",
</cfoutput>
<cfelse>
"answer": "",
</cfif>
<cfreturn />
This is not a direct answer to your question. However, even ignoring the errors mentioned in the comments, the code above is not an efficient way to get the job done. It is not necessary to run a separate query for each question in the exam. Just run a single query using a JOIN instead. Since you appear to want all questions, even ones without an answer, make it an OUTER JOIN.
Note: Never use raw parameters in a cfquery because it puts your database at risk for sql injection. Instead use cfqueryparam with whichever cfsqltype matches actual data types of your columns (see documentation matrix).
<!--- adjust cfsqltypes as needed --->
<cfquery name="yourQueryName" ....>
SELECT q.id, q.question, q.question_type, a.answer, ... other columns
FROM Questions q LEFT JOIN Answers a
ON a.question_id = q.question_id
AND a.student_id = <cfqueryparam value="#ARGUMENTS.student_id#"
cfsqltype="cf_sql_integer">
WHERE q.exam_id = <cfqueryparam value="#ARGUMENTS.exam_id#"
cfsqltype="cf_sql_integer">
</cfquery>
Once you have the query results, use it to build your result object. The exact structure depends on your application, but assuming there can be multiple questions - an array of structures would be a good example.
Be sure to properly scope all variables. All function local variables should be var/local scoped to prevent potential threading issues: that includes query names.
<!--- localize all variables --->
<cfset var yourQueryName = "">
<cfset var resultArray = "" >
<cfset var data = "" >
.... run query ....
<!--- first initialize the array --->
<cfset resultArray = []>
<!--- loop through your query and build an array of structures --->
<cfloop query="yourQueryName">
<!--- create new structure to store current question --->
<cfset data = {}>
<cfset data["question_id"] = yourQueryName.question_id>
<cfset data["question"] = yourQueryName.question>
<cfset data["answer"] = yourQueryName.answer>
... other keys ....
<!--- append the question to your array --->
<cfset arrayAppend(resultArray, data)>
</cfloop>
Finally, use serializeJSON to return the array of structures in JSON format:
<cfreturn serializeJSON(resultArray)>
I have a function which loops over a query and updates a database row for each item. After about 7000 iterations it's throwing an out of memory error - Java heap space.
Is there anything obviously wrong with this code ?
<cfloop query=loc.fixItems>
<cfset loc.count = loc.count + 1>
<cfset var categoryName = loc.fixItems.categoryName>
<cfinvoke component="Item" method="updateCode"
itemId="#loc.fixItems.itemId#" code="#loc.fixItems.newCode#"/>
<!--- Increment counter for category --->
<cfif structKeyExists(categoryMap, categoryName)>
<cfset var inc = structFind(categoryMap, categoryName) + 1>
<cfset structUpdate(categoryMap, categoryName, inc)>
<cfelse>
<cfset structInsert(categoryMap, categoryName, 1)>
</cfif>
</cfloop>
and in the update component:
<cffunction name="updateCode">
<cfargument name="itemId" type="numeric" required="yes">
<cfargument name="code" type="string" required="yes">
<cfset var loc = {}>
<cfquery name="loc.update">
update items
set code = <cfqueryparam value="#code#">
where id = <cfqueryparam value="#itemId#">
</cfquery>
</cffunction>
Don't use cfinvoke to create your Item component every iteration of your fixItems query. Create it once before that using createObject and simply call the updateCode method each time directly on the object.
The following can be done:
Change your <cfqueryparam> to use the appropriate cf_sql type. Are code and id really strings?
Don't give your <cfquery> a name. You are not keeping the result anyway. var loc doesn't help either
Bump up you memory to the JVM Addtional approach Use Java 7 and G1GC
Every 100 to 1000 iterations do a forced Garbage Collect
Update your data in bulk. XML based table variables can do this.
Make your function silent
Consider ORM on this
I have set of inserts that are wrapped in a <cftransaction> block, and I am getting a error and the insert is being rolled back.
Here is the code in question stubbed for space:
<cffunction name="InsertTCUV" access="public">
<cfargument name="vehicle required="true" type="xml" />
//Parsing the xml document here
<cftransaction>
<cfquery name="TCUVinsert datasource="mydb">
INSERT INTO tcuv
VALUES(...)
<cfquery>
<cfquery name="qLatestTCUVID" datasource="mydb">
SELECT TOP 1 tcuv_id FROM dbo.tcuv ORDER BY tcuv_id DESC
</cfquery>
<cfset curTCUVID = qLatestTCUVID.tcuv_ID>
<cfset optionsResult = insertOptions(curTCUVID,vehicle>
<cfset imagesResult = insertImages(curTCUVID,vehicle)>
<cfset standardFeaturesResult = insertStandardFeatures(curTCUVID,vehicle
</cftransaction>
</cffunction>
<cffunction name="insertOptions" access="private">
<cfargument name="TCUVID required="true type="numeric" />
<cfargument name="vehicleInfo" required="true" type="xml" />
<cfset var result = "good">
<cftry>
<cfset optionNode = xmlSearch(arguments.vehicleInfo[1], "p:RemarketingOption">
<cfloop index="i" from="1" to="#arrayLen(optionNode)#">
<cfset optionNodeNotes = XmlSearch(optionNode[#i#], "p:OptionNotes")>
<cfset optionNotes = "">
<cfloop index="j" from="1" to="#ArrayLen(optionNotesNodes)#">
<cfoutput>
<cfset optionNotes = optionNotes & " " & #optionNotesNodes[j].xmlText#>
</cfoutput>
</cfloop>
<cfquery name="insertOptions" datasource="mydb">
INSERT INTO dbo.tcuv_options
VALUES (
<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.TCUVID#">,
<cfqueryparam cfsqltype="cf_sql_varchar" value='#xmlSearch(optionNode[i], "p:OptionID")[1].xmlText#'>,
<cfqueryparam cfsqltype="cf_sql_varchar" value='#xmlSearch(optionNode[i], "p:OptionTypeCode")[1].xmlText#'>,
<cfqueryparam cfsqltype="cf_sql_varchar" value='#xmlSearch(optionNode[i], "p:OptionShortDescription")[1].xmlText#'>,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#optionNotes#">
)
</cfquery>
</cfloop>
<cfcatch type="database">
//dumping cfcatch.* information
<cfset result = "error"
</cfcatch>
</cftry>
<cfreturn result>
</cffunction>
This whole thing is in a loop on the calling page, and everything works fine the first time through the loop. One the second pass, the TCUVInsert works, but I get to the insertOptions function, a coldfusion error is thrown saying that, variable insertOptions is undefined, and when I get the database, the second row isn't there, which tells me there was an error and the insert rolled back. So, there is an error with the insert of the options, and coldfusion isn't giving me the right error to diagnose it. So either I have to look in the database logs, which apparently are not setup, or try to extract the error from the cftransaction block, which I'm not sure how to do.
coldfusion 9, sql server 2008 r2
Any thoughts?
<cffunction name="insertOptions" access="private">
You are overwriting the function by using the same name for a query variable:
<cfquery name="insertOptions" datasource="imports">
Interestingly it is all because the query name was not var scoped. Functions are stored in the variables scope of the component. So by failing to localize the query name, you end up overwriting the function stored in variables.insertOptions when you run the query. Because insert statements do not return a resultset, that variable ends up being undefined. Hence the error. In this case the solution is to either scope the query name, or better yet remove it entirely (since it is not populated anyway).
Just one more reason to always var/local scope function variables - yes, query names too!