Loop over the cfquery tag values - coldfusion

I have the following query where I loop over a list of values but I am getting an error at the last comma:
<cfquery datasource="#application.dsn#">
INSERT INTO #session.tablename# ( #lFields# )
VALUES (
<cfloop list="#lFields#" index="kk">
<cfqueryparam value="#TRIM(sVideoGame['#kk#'])#" cfsqltype="cf_sql_varchar" null="#NOT LEN(TRIM(sVideoGame['#kk#']))#" />,
</cfloop>
)
</cfquery>
Problem occurs with the last comma. I tried setting up a counter before the cfloop, setting it 0 and incrementing to 1 inside the cfloop. However, I am not sure how to remove the last comma based upon some condition check.

In order to keep track of the position, you will need a from/to loop instead of a list loop. Then add a comma after you pass the first query parameter.
For ColdFusion 2016+ it can be done using the "item" and "index" attributes:
...
<cfloop list="#yourListVariable#" item="keyName" index="position">
<!--- if we've passed the first parameter, add a comma --->
<cfif position gt 1>,</cfif>
<cfqueryparam value="#TRIM(sVideoGame[ keyName ])#"
cfsqltype="cf_sql_varchar"
null="#NOT LEN(sVideoGame[keyName])#" />
</cfloop>
...
CF11 and earlier require a little more work. To simplify the code, I would recommend converting the list to an array:
<cfset keyArray = listToArray(yourListVariable)>
...
<cfloop from="1" to="#arrayLen(keyArray)#" index="position">
<!--- if we've passed the first parameter, add a comma --->
<cfif position gt 1>,</cfif>
<cfqueryparam value="#TRIM(sVideoGame[ keyArray[position] ])#"
cfsqltype="cf_sql_varchar"
null="#NOT LEN(sVideoGame[ keyArray[position] ])#" />
</cfloop>
...
Side note, I noticed the query uses dynamic table and column names. Be sure those values are NOT user supplied, or the query is vulnerable to sql injection.

If your only question is how to deal with the last comma, then you can do it with
<cfset listCount = 1>
<cfloop list="#lFields#" index="kk">
<cfqueryparam value="#TRIM(sVideoGame['#kk#'])#"
cfsqltype="cf_sql_varchar" null="#NOT LEN(TRIM(sVideoGame['#kk#']))#" />
<cfif listLen(lFields) is not listCount>,</cfif>
<cfset listCount = listCount+1>
</cfloop>

Related

insert into table by looping over structure

I am trying to insert into the code but it is inserting value in every row, rather than question value in question and answer value in answer:
<cfset StructDelete(structform,'title')>
<cfset StructDelete(structform,'mode')>
<cfset StructDelete(structform,'formsubmission')>
<cfset StructDelete(structform,'file_upload')>
<cfset StructDelete(structform,'czContainer_czMore_txtCount')>
<CFSET StructDelete(structform,'action')>
<CFLOOP collection="#structform#" index="whichPair">
<cfset Questions = "question" & structform[whichPair]>
<cfset answer = "answer" & structform[whichpair]>
<cfquery name="insertData" datasource="aas">
insert into faqsquestions(question,answer,createdon,faqID)
values(<cfqueryparam cfsqltype="cf_sql_varchar" value="#Right(questions, Len(questions)-8)#">,
<cfqueryparam cfsqltype="cf_sql_longvarchar" value="#Right(answer, Len(answer)-8)#">,
<cfqueryparam cfsqltype="cf_sql_date" value="#CreateODBCDate(now())#">,
<cfqueryparam cfsqltype="cf_sql_integer" value="#getLastID#">)
</cfquery>
</CFLOOP>
can anyone tell what i am doing wrong here, i know i am using question as a static value just inside the loop as cfset and doing a right to remove that question variable which makes no sense but i will remove it when i am finished fixing my code
questions and answers are like this:
http://prntscr.com/lntu2l
That's the wrong type of loop for what you're trying to do. The reason is a structure loop iterates once - for each field. When what you want is to loop once - for each pair of fields.
A simple option is add a hidden field to your form, containing the total number of pairs.
<input type="hidden" name="NumberOfQuestions" value="#TheTotalNumberHere#">
Then use the total number with a from and to loop. On each iteration, extract the current value of the question and answer fields, and use them in your query:
<cfloop from="1" to="#FORM.NumberOfQuestions#" index="pairNum">
<cfset question = FORM["question"& pairNum]>
<cfset answer = FORM["answer"& pairNum]>
<cfquery ...>
INSERT INTO faqsQuestions(question,answer,createdon,faqID)
VALUES (
<cfqueryparam cfsqltype="cf_sql_varchar" value="#question#">
, <cfqueryparam cfsqltype="cf_sql_longvarchar" value="#answer#">
, <cfqueryparam cfsqltype="cf_sql_date" value="#now()#">
, <cfqueryparam cfsqltype="cf_sql_integer" value="#getLastID#">
)
</cfquery>
</cfloop>

identifying the coldfusion value comng to run against query

I am passing dynamically named parameters in the url. (The number of sSearch parameters can go beyond 5 to 7 or 8 etc)
sSearch_0
sSearch_1
sSearch_2
sSearch_3
sSearch_4
sSearch_5
I want to run a loop to do a search within a query. I am trying like this:
<cfloop from="0" to="5" index="k">
<cfset counter = k>
<cfif IsDefined('url.sSearch_' & counter)>
<cfset "check_" & k = 'url.sSearch_' & counter>
</cfif>
</cfloop>
I am trying to write in a query like this:
<cfquery datasource="#coldfusionDatasource#" name="qFiltered">
SELECT *
FROM mytable
<cfif len(trim(url.sSearch))>
WHERE
<cfloop list="#listColumns#" index="thisColumn">
<cfif thisColumn neq listFirst(listColumns)> OR </cfif>
#thisColumn# LIKE <cfqueryparam cfsqltype="CF_SQL_VARCHAR"
value="%#trim(url.sSearch)#%" />
</cfloop>
</cfquery>
But it is not working. The error says check_ is undefined.
For dynamic variable naming using quotes, try:
<cfset "check_#k#" = 'url.sSearch_' & counter>
See this article

how to determine the rollback cause in a cftransaction

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!

Why isn't my mysql query seeing this one combination of two variables but sees the rest?

I wrote a script that takes date entries and for some reason whenever I specify just a starting date with a blank end date the query never picks it up. Here's what I wrote.
<cfquery name="stec_mysql_loan_tracking_qry" result="meta_tracking" datasource="STLinux1MySQL">
Select
tslo.created,
tslo.created_by,
tslo.last_modified,
tslo.last_modified_by,
tslo.active,
tslo.is_manager,
tslo.pick_userid,
tslo.customer_code,
tslo.name,
tst.user_ip as ip,
tsl.loan_identifier,
tst.command,
tsl.tax_search_loan_id as id
From
tax_search_loan_officers tslo Left Join
tax_search_loans tsl On tsl.tax_search_loan_officer_id =
tslo.tax_search_loan_officer_id Left Join
tax_search_track tst On tst.pick_userid = tslo.pick_userid
Where
tslo.customer_code In (<cfqueryparam value="#tw_custcodes#" cfsqltype="cf_sql_varchar" list="yes">)
<cfif IsDefined('url.active')>
<cfif url.active neq "">
AND
tslo.active = <cfqueryparam value="#Trim(url.active)#" cfsqltype="cf_sql_varchar" list="yes">
</cfif>
</cfif>
<cfif IsDefined('url.is_managed')>
<cfif url.is_managed neq "">
AND
tslo.is_manager = <cfqueryparam value="#Trim(url.is_managed)#" cfsqltype="cf_sql_varchar" list="yes">
</cfif>
</cfif>
<cfif IsDefined('url.start_end')>
<cfif url.start_date neq "" and url.end_date eq "">
AND
<cfqueryparam value="#Trim(url.start_date)#" cfsqltype="cf_sql_date"> <= DATE_FORMAT(tslo.last_modified, '%Y-%m-%d')
AND
DATE_FORMAT(tslo.last_modified, '%Y-%m-%d') <= DATE_FORMAT(NOW(), '%Y-%m-%d')
</cfif>
</cfif>
<cfif IsDefined('url.start_date')>
<cfif url.end_date neq "" and url.start_date eq "">
AND
'2012-01-01' <= DATE_FORMAT(tslo.last_modified, '%Y-%m-%d')
AND
DATE_FORMAT(tslo.last_modified, '%Y-%m-%d') <= <cfqueryparam value="#Trim(url.end_date)#" cfsqltype="cf_sql_date">
</cfif>
</cfif>
<cfif isDefined('url.start_date')>
<cfif (url.start_date neq "") and (url.end_date neq "")>
AND
<cfqueryparam value="#Trim(url.start_date)#" cfsqltype="cf_sql_date"> <= DATE_FORMAT(tslo.last_modified, '%Y-%m-%d')
AND
DATE_FORMAT(tslo.last_modified, '%Y-%m-%d') <= <cfqueryparam value="#Trim(url.end_date)#" cfsqltype="cf_sql_date">
</cfif>
</cfif>
</cfquery>
And here is what it sees if url.end_date = "" but url.start_date = a value:
Select
tslo.created,
tslo.created_by,
tslo.last_modified,
tslo.last_modified_by,
tslo.active,
tslo.is_manager,
tslo.pick_userid,
tslo.customer_code,
tslo.name,
tst.user_ip as ip,
tsl.loan_identifier,
tst.command,
tsl.tax_search_loan_id as id
From
tax_search_loan_officers tslo Left Join
tax_search_loans tsl On tsl.tax_search_loan_officer_id =
tslo.tax_search_loan_officer_id Left Join
tax_search_track tst On tst.pick_userid = tslo.pick_userid
Where
tslo.customer_code In (?)
However, every other combination is fine. I've tried rewriting the cfif blocks but this structure is the only one that gets 2/3 while the rest fail.
(From the comments ..)
<cfif IsDefined('url.start_end')>
It looks like you have three date variables: url.start_date, url.end_date and url.start_end. What is url.start_end - is it a typo?
As an aside, you might want to set defaults values for the variables so you could eliminate some of the cfif conditions. Then work on simplifying the rest of the logic, because it seems more complex than is necessary ... Dan's response contains some good suggestions. I strongly suspect you could simplify the code and make the query more efficient to boot by getting rid of the DATE_FORMAT(ColumnName, '%Y-%m-%d') statements, because they will prevent the database from properly utilizing indexes on the referenced column.
Update:
After taking a closer look, I think this is what the code is trying to accomplish:
If both dates are present, filter on the given values
If only one of the dates is present, apply a default for the missing date. Then filter on both values.
If neither date is present, skip the filtering.
Something along these lines should mimic the behavior of current code. Note, it uses this type of comparison as a more index-friendly way of handling "time" issues:
WHERE column >= {startDateAtMidnight}
AND column < {dayAfterEndDateAtMidnight}
Example:
<!--- default both to something that is NOT a valid date --->
<cfparam name="url.start_date" default="">
<cfparam name="url.end_date" default="">
<!---
If at least ONE of the dates was supplied, apply
the desired defaults for missing values
--->
<cfif isDate(url.start_date) || isDate(url.end_date)>
<cfset url.start_date = isDate(url.start_date) ? url.start_date : "some default like 2012-01-01 here">
<cfset url.end_date = isDate(url.end_date) ? url.end_date : now()>
</cfif>
<cfquery ....>
SELECT ...
FROM ...
WHERE ...
<!--- apply the filter when both dates are populated. --->
<cfif isDate(url.start_date) and isDate(url.end_date)>
AND tslo.last_modified >= <cfqueryparam value="#url.start_date#" cfsqltype="cf_sql_date">
AND tslo.last_modified < <cfqueryparam value="#dateAdd('d', 1, url.end_date)#" cfsqltype="cf_sql_date">
</cfif>
</cfquery>
It might not be the cause, but you are mixing data types. This:
and <cfqueryparam value="#Trim(url.start_date)#" cfsqltype="cf_sql_date">
<= DATE_FORMAT(tslo.last_modified, '%Y-%m-%d')
will have a date on the left hand side of your comparison operator and a string on the right. Even if it runs without error, you might get unexpected results. As a minimum, remove the date_format function from the right hand side.
Then we have this:
AND DATE_FORMAT(tslo.last_modified, '%Y-%m-%d') <= DATE_FORMAT(NOW(), '%Y-%m-%d')
at least it's comparing a string to a string, but it's inefficient. In the overall scheme of things, maybe you want something like this:
and tslo.last_modified >=
<cfqueryparam value="#Trim(url.start_date)#" cfsqltype="cf_sql_date">
and tslo.last_modified =< now()

Looping over data submittted via jquery ajax routine with Coldfusion

If FF firebug window, I see this is being passed to my coldfusion action page:
RowOrder[]=&RowOrder[]=row_5&RowOrder[]=row_2&RowOrder[]=row_1&RowOrder[]=row_3&RowOrder[]=row_4&RowOrder[]=row_6&RowOrder[]=row_7&RowOrder[]=row_8&RowOrder[]=row_11
Now I need to loop over this to get the updated sort order but due to the [], I'm having issues. How can I loop over this so that I can update my table??? I expected this to be the easy part but I'm obviously missing something.
+ I'm using the jquery plugin (http://www.isocra.com/2008/02/table-drag-and-drop-jquery-plugin/). +
Here is the code I'm using to loop over the submitted data:
<cfif StructKeyExists(form, "RowOrder")>
<!---<cfset variables.Order = ReReplaceNoCase(form.RowOrder, "(&){0,1}row_\[\]=", ",", "all") />--->
<cfset variables.Order = ReplaceNoCase(form["RowOrder[]"],"row_","","all")>
<cfloop from="1" to="#ListLen(variables.Order)#" index="index">
<cfquery name="qryOrder" datasource="#dsn#">
update SystemTypes
set Order = <cfqueryparam value="#index#" cfsqltype="cf_sql_integer" />
where WETypeNum = <cfqueryparam value="#ListGetAt(variables.Order, index)#" cfsqltype="cf_sql_integer" />
</cfquery>
</cfloop>
</cfif>
+ The ajax code I'm using is as follows:
$("#RowOrder").tableDnD({
onDrop: function(table, row) {
var RowOrderData = $.tableDnD.serialize();
$.ajax({
type: 'POST',
url: '../../ajax/UpdateListingOrder.cfm',
cache: false,
data: RowOrderData
});
}
});
+
The + indicates information that was added after posting question
How is the problem manifesting itself? Are you getting an error, the query is not executing, .. ?
Dump the FORM scope to verify the name of field being passed? It looks like FORM['RowOrder[]'] rather than form.RowOrder. In which case you would need to use:
<cfif StructKeyExists(form, "RowOrder[]")>
<cfset variables.Order = ReReplaceNoCase(form["RowOrder[]"], "(&){0,1}row_\[\]=", ",", "all") />
... rest of code ...
<cfelse>
oops, that variable name does not exist
</cfif>
Could you not match the number rather than replace?
I've done the regex match within the loop - You can then focus on just one part of the string at a time.
An an illustration of the approch:
<cfif structKeyExists(form, "rowOrder")>
<cfset data = listToArray(form.rowOrder, "&")/>
<cfif not arrayIsEmpty(data)>
<cfloop form="1" to="#arrayLen(data)#" index="index">
<cfset match = reFind("[1-9][0-9]+", data[index], 1, true)/>
<cfif arraySum(match)>
<cfset weTypeNumber = val(mid(data[index], match["pos"], match["len"]))/>
<cfquery name="qryOrder" datasource="#dsn#">
UPDATE
system_types
SET
order = <cfqueryparam cfsqltype="cf_sql_integer" value="#index#"/>
WHERE
we_type_num = <cfqueryparam cfsqltype="cf_sql_integer" value="#weTypeNumber#"/>
</cfquery>
</cfif>
</cfloop>
</cfif>
</cfif>