Value getting rounded up by CFQueryParam - coldfusion

I have a self-submitting form, whose data gets used in a cfquery after it is submitted. I'm having a problem when the user submits a decimal rather than an integer.
This is for tires sizes
<select>
...
<option value="19.0">R19</option>
<option value="19.5">R19.5</option>
...
</select>
Then if the form is submitted, the results are passed on to a cfquery to show results only for that size.
<cfif form.size gt 0 >
AND ts.decDiameter = <cfqueryparam cfsqltype="cf_sql_decimal" value="#form.size#" />
</cfif>
This works perfectly for whole numbers, but when I select 19.5, it brings me back the results for 20. It is rounding up. Something weird with the cfqueryparam. It is transforming the result into a numeric value, but it is rounding it up to the next integer.

You need to add the scale parameter.
<cfqueryparam cfsqltype="cf_sql_decimal" scale="2" value="#form.size#">
You can use this reference...
http://help.adobe.com/livedocs/coldfusion/8/htmldocs/help.html?content=Tags_p-q_18.html

Related

How to set value from a query to an input textbox

When a user clicks edit of a specific row in a table, I want the input textboxes in the same page to be filled with that row's details. I tried this but it did not work.
<cfquery name="getDataForEdit" datasource="dsn">
select * from usercardetails where id = '#url.id#'
</cfquery>
<cfoutput>
<cfset #form.username# = #getDataForEdit.username#>
</cfoutput>
Try this as an example to get you going....
<cfquery name="getDataForEdit" datasource="dsn">
select * from usercardetails where id = '#url.id#'
</cfquery>
<!---
OPTIONAL IMPROVEMENT: You might change your SQL to use CFQueryParam, this will protect against SQL injection
select * from usercardetails where id = <cfqueryparam cfsqltype="CF_SQL_NUMERIC" value="#url.id#" />
--->
<!---
OPTIONAL FOR DEBUGGING: If you uncomment this block it will show you the results of your query.
<cfoutput><cfdump var="#getDataForEdit#" label="getDataForEdit" expand="No" /><br /></cfoutput>
--->
<cfoutput>
<cfif getDataForEdit.recordcount is 1> <!--- Check that you only get one row back in results --->
<!--- Coldfusion will build forms for you using cfform, but many coders keep away from it, so instead you need to build the HTML of your form yourself. --->
<form action="index.cfm" method="post">
<p><label for="username">Username</label><input type="text" id="username" name="username" value="#getDataForEdit.username#" /></p>
<p><input type="submit" id="butty01" name="butty01" value="Go" /></p>
</form>
<cfelseif getDataForEdit.recordcount is 0> <!--- If no results --->
<p>No records found</p>
<cfelse> <!--- Anything else will mean many results --->
<p>An error occurred (Multiple records with this ID found)</p>
</cfif>
</cfoutput>
I've put comments in the code around some optional improvements.
Also note that...
<cfset #form.username# = #getDataForEdit.username#>
will be causing you problems.
<cfset username = getDataForEdit.username>
Will create/set a variable username equal to the value of the username column in your query. The # tags are not necessary in this context. # prints out the value of a variable, so you could have done this...
<cfset username = "#getDataForEdit.username#">
Which would print the value of the username column into a string of text (the only thing in the string being the value), and the string of text would have been assigned to the variable username.
form
is a reserved word, as it is a structure (it's worth looking up structures) that contains all of the form variable data posted to your page. You can inspect form by using cfdump
<cfoutput><cfdump var="#form#" label="form" expand="No" /><br /></cfoutput>
To print out one of the values inside form you can do
#form.username#
So (and very confusingly when you're a beginner)...
<cfset #form.username# = #getDataForEdit.username#>
Will create a variable with the name that corresponds to the value of the form field username posted to your page, and fill it with the username from your query. You really don't want that.
Keep at it. Once you get a few basic concepts sorted Coldfusion is a lovely language to code in.

Insert data from form with dynamically named fields

OK. I've done a terrible job of explaining what I'm trying to do. I will try one more time to be more clear.
I have a list of variables that is submitted to a page with a cfquery insert. The variables come from dynamically named form fields, and are captured using a cfloop:
<cfloop list="#form.fieldnames#" index="item">
</cfloop>
What I have are form fields dynamically named, and a value added, as such:
<input type="hidden" name="ticketid_#some_number#" value="#some_quantity#">
For brevity, lets say the form field name is ticketid_6, and the value is 4. This could be a different name and value (for instance, ticketid_3 with a value of 1), or there might be several form fields of similar construct with different names and/or values.
So, on the insert page, I need to insert ticketid_6 4 times (creating 4 separate rows) into my table. So, a row in the database for each dynamically named form field, times the value of each.
I hope that explains it better.
Leigh,
I am still open to your suggestion on the previous post, but I fear I might not have explained my situation clearly enough for you to give your best recommendation. I will re-approach that question after I get this part figured out.
If you need to loop through all your field names and treat each one of those fields as a list you'd need to do two loops to insert each item.
<cfloop list="#form.fieldnames#" index="item"><!--- loop through all the form fields --->
<cfif find('ticketid_',item)><!--- if the form name contains 'ticketid_'. Use findNoCase if you want to ignore case sensitivity --->
<cfloop from="1" to="#form[item]#" index="counter"><!--- loop through the number in form.ticketid_ --->
<cfquery datasource="#dsn#">
INSERT INTO table (fieldname, fieldValue, TicketNum)
VALUES (
<cfqueryparam value="#item#" cfsqltype="cf_sql_varchar">,--fieldName from the form
<cfqueryparam value="#form[item]#" cfsqltype="cf_sql_varchar">--value of the fieldName in the form
<cfqueryparam value="#counter#" cfsqltype="cf_sql_integer">--ticket number being inserted
)
</cfquery>
</cfloop>
</cfif>
</cfloop>
You'll need to do server side validation to verify they haven't entered a non numeric number for the input box, but assuming you've done that this should achieve what you're looking for.
You need to use Evaluate function to get form dynamically input field value
Try this one
<input type="hidden" name="ticketid_#some_number#" value="#some_quantity#">
<cfloop list="#form.fieldnames#" index="item">
<cfoutpuy>Evaluate("ticketid_#item#")</cfoutpuy>
</cfloop>
You need to first bundle your data into an XML structure
<cfsavecontent variable="myFormData">
<cfoutput>
<ul class="xoxo">
<cfloop list="#form.fieldnames#" index="item">
<cfloop list="#form[item]#" index="eachItem">
<li><b>#xmlformat(item)#</b> <var>#xmlformat(eachItem)#</var>
</cfloop>
</cfloop>
</ul>
<cfoutput>
</cfsavecontent>
Then do a single insert
<cfquery>
INSERT INTO table (formData)
VALUES (<cfqueryparam value="#myFormData#" cfsqltype="cf_sql_varchar">)
</cfquery>
When you pull the data, you can
Show it as is, a bulleted list,
Promote to a bunch of rows in a table
Note that the data is inserted as both HTML and XML

How can I use dynamically generated variables from cfloop individually?

I'm not sure my title explains this very well. Frankly, I'm not sure how to put it into words, but here goes:
I am capturing variables from dynamically created form fields on another page, that have been submitted to a page containing the code below. So far, everything works as I want it to. I'm getting the dynamically named form fields. Now I need to add the subtotal dollar amounts together to create a grand total. Unfortunately, I can't figure out how to get the individual totals out of the loop so I can do the math for the final number, due to their dynamic nature.
This part of the code below generates the subtotals, and I need to be able to add all of them together to get a grand total, but I can't figure out how:
#dollarformat(val(getticket[item].ticketprice * form[item]))#
Maybe I need to take a different approach...suggestions/help appreciated.
Here's the full code:
<CFLOOP LIST="#form.fieldnames#" INDEX="item">
<cfoutput>
<cfquery datasource="outertixdb" name="getticket[item]">
select * from tickets
where ticketid = '#item#'
</cfquery>
#getticket[item].ticketname#: #dollarformat(getticket[item].ticketprice)# x #form[item]# = #dollarformat(val(getticket[item].ticketprice * form[item]))#<br/>
</cfoutput>
You would need to set the name attribute of your cfquery using the following format:
<cfquery datasource="outertixdb" name="#getticket[item]#">
To handle the total, you would first need a variable before the cfloop
<cfset total = 0 />
Then, inside the loop, you simply add the price of the ticket to the total
<cfset total = total + getticket[item].ticketprice />
Also, you should be using cfqueryparam in your query. You can read more about it here
Lastly, if you do not need all the data in the tickets table, do not use 'select *..', only pull pack the data that you need.
Not sure I completely understand, but it sounds like you are simply trying to look up a bunch of ticket records, by "id". Then display the individual costs, plus a grand total. If that is all your doing, just give the fields the same name: ticketID. For example:
<input name="ticketID" value="1" ...>
<input name="ticketID" value="22" ...>
<input name="ticketID" value="45" ...>
<input name="ticketID" value="16" ...>
Then the values will be submitted as a list ie 1,22,45,16, which you can feed into your query using an IN clause. That lets you grab all of the data in a single query. (Generally you want to avoid running queries within a loop because performing a separate database query for each id generates a lot of unnecessary overhead and degrades performance).
* Change the cfsqltype as needed
SELECT TicketID, TicketPrice
FROM YourTable
WHERE TicketID IN ( <cfquerparam value="#FORM.ticketID#"
list="true"
cfsqltype="cf_sql_integer">
)
UPDATE:
form[item] is the value of the quantity select from the previous page.
That is a confusing naming convention. I would recommend using a slightly more intuitive name like "quantity". Something more descriptive of the contents. You can still use the ticket id to generate unique names, ie quantity_#ticketID#. For example, using the same ticket id's as above:
<input name="quantity_1" ...>
<input name="quantity_22" ...>
<input name="quantity_45" ...>
<input name="quantity_16" ...>
Once you have the results, there are several ways to generate a grand total. The simplest being to initialize a variable before your loop, then increment it as you iterate. Use the query ticket ID to grab the quantity value from the FORM scope:
<cfset grandTotal = 0>
<cfoutput query="yourQuery">
<!--- extract quantity value --->
<cfset currQuantity = FORM["quantity_"& yourQuery.ticketID ]>
... display price ...
<cfset grandTotal += val(yourQuery.ticketPrice * currQuantity )>
</cfoutput>
GrandTotal <cfoutput>#grandTotal#</cfoutput>
I would recommend throwing out the whole dynamically named query thing.
<cfset total = 0>
<CFLOOP LIST="#form.fieldnames#" INDEX="item">
<cfquery datasource="outertixdb" name="getticket">
select * from tickets
where ticketid = <cfqueryparam cfsqltype="cf_sql_varchar" value="#item#">
</cfquery>
<cfset total += getticket.ticketprice />
<cfoutput query="getTicket">
#ticketname#: #dollarformat(ticketprice)# × #form[item]#
= #dollarformat(val(ticketprice * form[item]))#<br/>
</cfoutput>
</cfloop>
Output your total as needed

ColdFusion cfset issue

I am new to ColdFusion. Anyone know why this code is not working. When I leave the form null it is not showing 100 in the database.
<cfif isdefined("FORM.Percentage")>
<cfset Form.Percentage = #Form.Percentage#>
<cfelse>
<cfset Form.Percentage = 100>
</cfif>
<cfquery name="percent" datasource ="abc">
Insert into Employees
(Percentage)
Values
(#Form.Percentage#)
</cfquery>
If you have a textbox it is submitted to the form even if it's left blank, so you want to check if the field was left blank. If it was then you can set the default.
You'll also want to do some server side validation that the value is a number and use cfqueryparam for inserting your value into the database.
<cfif NOT len(trim(FORM.Percentage))>
<cfset Form.Percentage = 100>
<cfif>
<cfquery result="percent" datasource="abc">
Insert into Employees (Percentage)
Values (
<cfqueryparam cf_sql_type="cf_sql_integer" value="#Form.Percentage#">
)
</cfquery>
When using cfquery with an INSERT the name attribute doesn't provide anything. Using result would allow you to view some data about the query if needed, but generally it shouldn't be used.
You could also have dumped form to the screen by using <cfdump var="#form#"> to see what it was returning. If you want to check that the key exists for a radio button or checkbox you can use structKeyExists(form,'myCheckbox') rather than using isDefined().

CFLOOP Duplication

I have a drop down list that is generated by two loops. The inner loop generates a series of numbers ie from 0 to 23. The outer loop, is a query loop that selects the correct value from the 23 numbers based on the values stored in my database.
My issue here is that those two loops conflict that results in displaying the numbers from 0 to 23 twice. How can keep both loops but avoiding this issue? This problem also cause issues when the form is submitted by trying to submit the form twice and deleting the user's input.
This is my code:
<select id="openHours#CountVar#" name="openHours#CountVar#">
<cfloop query="doctorHours" >
<cfloop from="0" to="23" index="OpenHours">
<option value="#openHours#"
<cfif TimeFormat(doctorHours.openTime,'HH') EQ OpenHours AND CountVar EQ doctorHours.day > selected="selected"</cfif>>#OpenHours#</option>
</cfloop>
</cfloop>
</select>
This is my CFDUMP for that query
query
RESULTSET
query
CLOSETIME DAY DOCTORID OPENTIME
1 1970-01-01 16:00:00.0 4 2011041516290025478779 1970-01-01 10:00:00.0
2 1970-01-01 16:00:00.0 1 2011041516290025478779 1970-01-01 13:00:00.0
3 1970-01-01 16:00:00.0 2 2011041516290025478779 1970-01-01 13:00:00.0
CACHED false
EXECUTIONTIME 0
SQL select doctorID, opentime, closetime, day from doctorBusinessHours where doctorID='2011041516290025478779'
You should return only the hours you need and then loop for the dropdownlist creation:
DATEPART(hh,yourdate) will return the hours for your datetime value:
<cfquery name="doctorHours" datasource="#ds#">
SELECT doctorID,DATEPART(hh,openTime) As OpenHours, DATEPART(hh,closetime) As CloseHours
FROM doctorHours
WHERE day = #CountVar#
AND doctorID='#docID#'
</cfquery>
ValueList will transform your query results into a list:
<cfset openTimesList = ValueList(doctorHours.OpenHours) />
<cfset closeTimesList = ValueList(doctorHours.CloseHours ) />
ListContains will return the index of the value within your list:
<select id="openHours#CountVar#" name="openHours#CountVar#">
<cfloop from="0" to="23" index="OpenHours">
<option value="#openHours#"
<cfif ListContains(openTimesList,OpenHours) NEQ 0 >
selected="selected"
</cfif>
>#OpenHours#</option>
</cfloop>
</select>
You can use the same strategy for the closeTimesList.
Hmmm....the number of values displayed in the code above will be equivelant to the number of records returned by the query X 23. If you're query returns 2 records you will see 46 options and so on. It seems like you believe the query has only 1 record. I would suggest perhaps it has more.
Try LIMIT 1 or TOP 1 in your query - or use Maxrows (as suggested in the comments)... but make sure you know what you are including and what you are excluding. You need to know why your query is not what you expect :)