CF queries using form variables entered by a user [duplicate] - coldfusion

This question already has an answer here:
define a list of id's for grouped item
(1 answer)
Closed 6 years ago.
I am trying to do a query matching my trans_location column with the form data the user enters. I have a dropdown that lets the user choose multiple locations. When they choose multiple it places commas in between each location. When I choose only one location the results come back correct with the correct location. But when I choose more than one location it does not find any of the locations. Do the commas make it only one name and it will not search each location?
<cfset result = {} />
<cftry>
<cfset date1 = #CREATEODBCDATETIME(form.StartDate & '00:00:00')#>
<cfset date2 = #CREATEODBCDATETIME(form.EndDate & '23:59:59')#>
<cfquery datasource="#application.dsn#" name="GetLocationInfo">
SELECT *
FROM cl_checklists
WHERE date >= #date1# AND date <= #date2#
AND trans_location = '#form.Location#'
</cfquery>
<cfoutput>#date1#</cfoutput>
<cfoutput>#date2#</cfoutput>
<cfdump var="#GetLocationInfo#">
<cfcatch type="any">
<cfset result.error = CFCATCH.message >
<cfset result.detail = CFCATCH.detail >
</cfcatch>
</cftry>
I also tried doing something like this:
AND trans_location = <cfqueryparam value='#form.Location#' />

You need to use the IN operator in conjunction with cfqueryparam with the list="true" attribute. (Here is a quick helpful tutorial for cfqueryparam: https://www.petefreitag.com/item/677.cfm)
Lastly: always, always, always use cfqueryparam when sending parameters to the database.
<cfset result = {} />
<cftry>
<cfset date1 = CREATEODBCDATETIME(form.StartDate & '00:00:00')>
<cfset date2 = CREATEODBCDATETIME(form.EndDate & '23:59:59')>
<cfquery datasource="#application.dsn#" name="GetLocationInfo">
SELECT *
FROM cl_checklists
WHERE date >= <cfqueryparam value="#date1#" cfsqltype="cf_sql_timestamp" />
AND date <= <cfqueryparam value="#date2#" cfsqltype="cf_sql_timestamp" />
AND trans_location IN ( <cfqueryparam value="#FORM.location#" cfsqltype="cf_sql_varchar" list="true" /> )
</cfquery>
<cfoutput>#date1#</cfoutput>
<cfoutput>#date2#</cfoutput>
<cfdump var="#GetLocationInfo#">
<cfcatch type="any">
<cfset result.error = CFCATCH.message >
<cfset result.detail = CFCATCH.detail >
</cfcatch>
</cftry>

Related

Check if any field is different from database value

After I submit a form, I need to check if any field in the database table changed. If changed I create a new record, if not, I don't do anything. I can't just update the record.
Is there a way to do it without checking every single field like the code below?
<cfquery name="getData" datasource="myDS">
Select * From table Where ID = #form.ID#
</cfquery>
<Cfset changed = false />
<!-- Check every field -->
<cfif form.data1 neq getData.data1>
<cfset changed = true />
</cfif>
<cfif form.data2 neq getData.data2>
<cfset changed = true />
</cfif>
<cfif form.data3 neq getData.data3>
<cfset changed = true />
</cfif>
...
Thanks
Might depend on what database you are using but you should be able to do a query that will insert if the data does not exist.
As an example I just tested this against Oracle 12c using CF2016 Enterprise and it creates a new record if the data does not exist.
<cfquery name="Testing" datasource="Test">
INSERT INTO TESTTABLE (DATA1, DATA2, DATA3)
SELECT <cfqueryparam value="#Form.Data1#" cfsqltype="CF_SQL_VARCHAR" />, <cfqueryparam value="#Form.Data2#" cfsqltype="CF_SQL_VARCHAR" />, <cfqueryparam value="#Form.Data3#" cfsqltype="CF_SQL_VARCHAR" />
FROM dual
WHERE NOT EXISTS
(SELECT DATA1, DATA2, DATA3 FROM TESTTABLE WHERE DATA1 = <cfqueryparam value="#Form.Data1#" cfsqltype="CF_SQL_VARCHAR" />,
AND DATA2 = <cfqueryparam value="#Form.Data2#" cfsqltype="CF_SQL_VARCHAR" /> AND DATA3 = <cfqueryparam value="#Form.Data3#" cfsqltype="CF_SQL_VARCHAR" />)
</cfquery>
Can you explain this a little further? Why are you allowing a form to be submitted with changed data if you can't update the record itself? If you click Save, then compare the form data with the query data and have the action call a Create function when the data is different.
Let's say you have a thing query and form:
<cfquery name="myThing">
SELECT
thing_id,
thing_name,
thing_foo
FROM
things
where
thingID = <cfqueryparam value="#url.thingID#">
</cfquery>
<form>
<input type="hidden" name="thing_id" value="#myThing.thing_id#">
<input type="text" name="thing_name" value="#myThing.thing_name#">
<input type="text" name="thing_foo" value="#myThing.thing_foo#">
<button type="submit">Submit</button>
</form>
If you need to check the submitted data against what's already in the database, you can just run the query again on the form processing page and compare those values against the submitted form values. This example assumes you named the form fields the same as the database table columns.
<cfset delta = false>
<cfloop item="key" collection="#myThing#">
<cfif structKeyExists(form, key)>
<cfif form[key] NEQ myThing[key]>
<cfset delta = true>
</cfif>
</cfif>
</cfloop>
If any values differ, then create a new record. No idea what you need to do when the submitted values haven't changed.
<cfif delta>
<!--- Create a new record. --->
<cfelse>
<!--- ¯\_(ツ)_/¯ --->
</cfif>
I've also seen it done where the original values are stored in hidden form fields and submitted along with the editable form fields. You could do this, but there's no guarantee that the values in the DB haven't been changed between you rendering the form and then submitting it.
You'll still have some challenge of how to tell if the DB values have changed on the way to the DB, but I'm not sure if you need so granular a check.
We can use the cfquery to check the table having the existing data or not. If not having the same data means we can Insert the form. The following code may related to your scenario.
<cfif structKeyExists(form,"Submit")>
<cfquery name="checkFormExisting" datasource="myDSN">
SELECT *
FROM USERS
WHERE data1 = <cfqueryparam value="#form.data1#" cfsqltype="cf_sql_varchar">
OR data2 = <cfqueryparam value="#form.data2#" cfsqltype="cf_sql_varchar">
OR data3 = <cfqueryparam value="#form.data3#" cfsqltype="cf_sql_varchar">
</cfquery>
<cfif checkFormExisting.recordCount EQ 0>
INSERT INTO
USERS (
data1,data2,data3
)
VALUES (
<cfqueryparam value="#form.data1#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#form.data2#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#form.data3#" cfsqltype="cf_sql_varchar">
)
</cfif>
</cfif>
Hope, you're asking like the above code for your scenario.

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

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>