ColdFusion cfselect display two query columns - sql

I'm trying to display the results of a query, but I'm having a hard time combining two values that the query produces... Here's the query I have
<cffunction name="getStudentData" returntype="query">
<cfargument name="nameVar" type="string" required="yes">
<cfargument name="timeframe" type="numeric" required="yes">
<cfquery datasource="#Application.hds#" name="gsd">
select (s.lastname + ', ' + s.firstname) as StudData,
('[' + r.hallname + ' ' + r.roomnumber + ']') as roomdata,
s.studentnumber
from tblstudents s left join
(select h.hallname, ra.roomnumber, studentid
from tblroomassignments ra, tblhalls h
where ra.TimeFrame = #Arguments.timeframe#
and ra.hallid = h.hallid) r
on s.studentid = r.studentid
where s.lastname like '#Arguments.nameVar#%'
</cfquery>
<cfreturn #gsd#>
</cffunction>
What I'm trying to figure out is how to display StudData+' '+roomdata IF they both exist together since some students won't have a room assigned to them. (I'm just trying to produce a list of students that have a dorm/room assigned to them. In my cfselect...
<cfselect name="RecipientName"
query="studentdata"
display="StudData+' '+roomdata"???????
value="studentnumber">
</cfselect>
I don't know how to get StudData and roomdata in the display attribute without the page giving me an query column error. I'm very new to coldfusion and it's my understanding that you can only display one variable? Is there a way to combine StudData and roomdata into a variable and then display that variable?
Anyone have any ideas? Could this be simplified?
Hope this all makes sense!

I wouldn't use a cfselect at all.
<select name="RecipientName">
<cfoutput query="studentdata">
<option value="#studentnumber#">#StudData# #roomdata#</option>
</cfoutput>
</select>
If you really want to use cfselect, then I'd concatenate the columns in your query.
StudData + roomdata AS expanded_student_data
...
<cfselect name="RecipientName"
query="studentdata"
display="expanded_student_data"
value="studentnumber"
>
</cfselect>

Related

ColdFusion count the amount without using SQL

I am trying to count the amount without using SQL count() code
Is there a way to extract the results including the number amount over ColdFusion?
Select test
From ......
Where .....
<Cfif not test.RecordCount>
No records found
</Cfif>
<cfoutput query="test">#amount#</cfoutput>
It should display like this
TEST CountOutput
TEST A: 22
TEST B: 32
TEST B: 1
TEST C: 23
(From comments ...)
Why can't you use SQL for this? Unless there's a valid reason you can't use COUNT, it's by far the simplest way to aggregate. You don't need to know the specific values in the database table in order to perform a COUNT. Just do:
SELECT column, count(*) AS someAlias
FROM tableName
GROUP BY column
Yes, it is possible to do the same in ColdFusion code, but again unless there's a specific reason to do so, it's more efficient to use SQL.
<cfset data = {} />
<cfset names = {} />
<cfloop query="test">
<cfif not structKeyExists(data, test.name)>
<cfset data[test.name] = 0 />
<!--- if you need to preserve original case of name --->
<cfset names[test.name] = test.name />
</cfif>
<cfset data[test.name] += 1 />
</cfloop>
<cfoutput>
<cfloop collection="#data#" item="key">
#names[key]#: #data[key]#<br />
</cfloop>
</cfloop>
To get the total count without using SQL, Use
QUERYVARIABLE.RECORDCOUNT
Based on the condition used in the SQL query it will give you the count.
FOR Example,
<cfquery name="test">
SELECT * FROM database WHERE name=testA
</cfquery>
<cfdump var="#test.RECORDCOUNT#" />
Use this within a function, call it and store the return value in a stack or an array.
I strongly recommend you use a SQL Count(). I cannot imagine why you would want to do it inside a CFLoop or CFOutput, but it is possible if you use the Group attribute, and count each row that way.
Did you know that after you execute CFQuery against your SQL server to get all those detail records, you can run a "query of queries" summarize the SQL data. This article seems to explain it:
https://www.quackit.com/coldfusion/tutorial/coldfusion_query_of_queries.cfm

Add and subtract float values from database

So I have this query to get the results from my database tables with the columns in and out.
<cfquery name="getInfo" datasource="testing">
select in, out from test
</cfquery>
Now what I need to do is to take a static number, eg; 100, and ADD the in and SUBTRACT the out from that static number.
So this is what I tried:
<cfquery name="getInfo" datasource="testing">
select in, out from test
</cfquery>
<table>
<cfset balance = 100>
<cfloop query="getInfo">
<cfset balance = balance + in - out> <!--- THIS IS WHAT I TRIED --->
<tr>
<td>#in#</td>
<td>#out#</td>
<td>#balance#</td>
</tr>
</cfloop>
</table>
So as you can see, I did set this code <cfset balance = 100 + in - out>. Basically what I am trying to do is to get the original value of balance which is 100 and add the values of in and subtract the value of out and save it as the new balance.
However, I am getting an error saying The value '' cannot be converted to a number..
I have set the values for in and out to be float in the database.
Where am I going wrong?
You need to update your query to cover NULL conditions
<cfquery name="getInfo" datasource="testing">
select ISNULL([in], 0) AS [in], ISNULL([out], 0) AS [out]
FROM test
</cfquery>
Also I put square brackets around in and out because they look like they might be key words
Also consider doing the math on the DB, you might get better performance

Creating a survey using Coldfusion: Stuck on the table data insert

I'm trying to create a survey tool in Coldfusion and I'm stuck on one part.
My tables are:
t_forms (id, name, desc)
t_questions (id, question, type, formid, order)
t_cdata (id, email)
t_cqdata (formid, questionid, customerid, answergiven)
The form fields are dynamically built using a url variable and look like this, for example:
<cfquery name="gs">
select * from t_forms where id = #url.sid#
</cfquery>
<cfquery name="gq">
select * from t_questions where fid = #gs.id# ORDER BY order ASC
</cfquery>
<cfform name="survey" method="post" action="">
<cfloop query="gq">
<cfinput type="text" name="q#gq.id#">
</cfloop>
<cfinput type="text" name="email">
<cfinput type="hidden" name="fid" value="#url.fid#">
<cfinput type="submit" name="submit" value="Save">
</cfform>
However, I'm having trouble when I need to put the value of the answer into the t_cqdata table, as the form element input needs to go into the table as well.
If anyone could help or point out where I am going wrong, that would be appreciated .
There is more than one way to have form fields associated with database identifier values. This is the one I find easiest to comprehend.
On the form page.
<cfoutput query="somequery">
<input name="field1#databaseID#">
<input name="field2#databaseID#">
etc
On the processing page.
<cfloop list="#form.fieldnames#" index="ThisElement">
<cfif left (ThisElement, 6) is "field1">
<cfset ThisID = RemoveChars(ThisElement, 1, 6)>
<cfset ThisField1Value = form[ThisElement]>
<cfset ThisField2Value = form['field2' & ThisID]>
Continue to set variables and then do something with them. In fact, in this example, once you've set ThisID, setting more variables is optional. You can simply use the form variables directly using the synax shown.
You will need to use an insert into cfquery.
You would use something like:
INSERT INTO t_cqdata
(q1
,q2
,q3
,q4
,q5
,q6
,q7)
VALUES
(
,
,
,
,
,)

how to prevent coldfusion sql-injection on order by clause

Since cfqueryparam doesn't work in an order by, would using xmlformat stop sql injections?
ORDER BY #xmlformat(myVariable)#
Thanks,
http://www.petefreitag.com/item/677.cfm
A good way to get around this limitation is to use the ListFindNoCase function, to limit the sortable column names, for example:
<cfset sortable_column_list = "age,height,weight,first_name">
<cfquery ...>
SELECT first_name, age, height, weight
FROM people
ORDER BY <cfif ListFindNoCase(sortable_column_list, url.sort_column)>#url.sort_column#<cfelse>first_name</cfif>
</cfquery>
This is from a stored procedure, but translate an #ORDER_BY value to an actual database column and a #SORT_ORDER value to a SQL command.
ORDER BY
CASE WHEN #ORDER_BY = 'LENDER' AND #SORT_ORDER = 'D' THEN l.tms_name END DESC,
CASE WHEN #ORDER_BY = 'LENDER' AND #SORT_ORDER != 'D' THEN l.tms_name END,
CASE WHEN #ORDER_BY = 'LOAN_NUMBER' AND #SORT_ORDER = 'D' THEN p.Loan_Number END DESC,
CASE WHEN #ORDER_BY = 'LOAN_NUMBER' AND #SORT_ORDER != 'D' THEN p.Loan_Number END,
XML Format won't handle all cases.
The column check is good, but I'm guessing that the advantage of letting the user define what the order by is, is because you can make it more complex than just a single column. For instance, you could add several columns and an Ascending, Descending etc...
I'd suggest you make a globally available function that strips out any character that isn't a number, letter or comma. If someone did attempt to do a SQL Injection it would just fail.
<cfif refindnocas('^\w+ ?(desc|asc)?$', myVariable)>
ORDER BY #myVariable#
</cfif>
or
<cfset columnList = 'col1,col2,etc' /> <!--- might want to use in select as well --->
<cfset regexColList = replace(columnList, ',', '|', 'all') />
<cfif not refindnocas('^(#regexColList#) ?(desc|asc)?$', myVariable)>
<cfset myVariable = "DefaultSort" />
</cfif>
ORDER BY #myVariable#
or
ORDER BY #query_sort(myVariable, columnList, defaultSort)#
...
<cffunction name="query_sort">
<cfargument name="sort" />
<cfargument name="columns" />
<cfargument name"default" />
<cfset var regexcolumns = replace(columns, ',', '|', 'all') />
<cfif refindnocas('^(#regexcolumns#) ?(desc|asc)?$', sort)>
<cfreturn sort />
<cfelse>
<cfreturn default />
</cfif>
</cfargument>
etc
Another option is a slight twist on the ListFindNoCase approach. Column information can be stored in a structure. The key would be the publicly visible column name and the value is the real column name. It is a little more complex. But I like the fact that it does not require you to expose your schema. It also supports more compound statements as Dave mentioned.
<cfset sortCols = { defaultCol="DepartmentName"
, date="ReportDate"
, type="DepartmentName"
, num="EmployeeID" } />
....
SELECT Columns
FROM TableName
ORDER BY
<cfif structKeyExists(sortCols, url.sort_column)>
#sortCols[url.sort_column]#
<cfelse>
#sortCols["defaultCol"]#
</cfif>

SQL Array being returned as number, not String in ColdFusion

In Coldfusion, I'm using a cfc that binds one select box to another (basically, choose a State from one box, the second box is populated with County names.) The value for the County box is a 5-digit number WHICH IS FORMATTED AS TEXT (ie. the value comes from a text field.)
The problem is that I'm finding that if the value of the selected county id starts with a '0', it's been cut off.
So I get stuff like:
ID County
11223 A
2300 B (should be 02300)
Can someone help make sure that leading 0s are not cut off?
Here's the select boxes on the page:
<!--- State Name options --->
<b>State:</b><br />
<cfselect bind="cfc:states.getStates()" bindonload="true" name="search_state" id="search_state" value="StateUSAbb" display="StateName">
</cfselect><br />
<!--- County Name options --->
<b>County:</b><br />
<cfselect bind="cfc:states.getCounties({search_state})" name="search_county" id="search_county" value="FIPS_County" display="CountyName">
</cfselect>
I hate pasting the whole .cfc but pay attention to the latter part, particularly the cfloop which uses a cfset to populate array RESULT:
<cfcomponent output="false">
<!--- Get array of media types --->
<cffunction name="getStates" access="remote" returnType="array">
<!--- Define variables --->
<cfset var data="">
<cfset var result=ArrayNew(2)>
<cfset var i=0>
<!--- Get data --->
<cfquery name="data" datasource="bridges">
SELECT DISTINCT tblLoc.StateUSAbb, lkuState.StateName
FROM lkuState INNER JOIN tblLoc ON lkuState.FIPS_State = tblLoc.FIPS_State
WHERE (lkuState.StateName <> 'New Brunswick')
UNION
SELECT '' AS StateUSAbb, ' ALL' AS StateName
FROM lkuState
ORDER BY StateName
</cfquery>
<!--- Convert results to array --->
<cfloop index="i" from="1" to="#data.RecordCount#">
<cfset result[i][1]=data.StateUSAbb[i]>
<cfset result[i][2]=data.StateName[i]>
</cfloop>
<!--- And return it --->
<cfreturn result>
</cffunction>
<!--- Get counties by state --->
<cffunction name="getCounties" access="remote" returnType="array">
<cfargument name="stateabb" type="string" required="true">
<!--- Define variables --->
<cfset var data="">
<cfset var result=ArrayNew(2)>
<cfset var i=0>
<!--- Get data --->
<cfquery name="data" datasource="bridges">
SELECT '' AS FIPS_COUNTY, ' ALL' as CountyName
FROM lkuCnty
UNION
SELECT FIPS_County, CountyName
FROM lkuCnty
WHERE StateAbb = '#ARGUMENTS.stateabb#'
ORDER BY CountyName
</cfquery>
<!--- Convert results to array --->
<cfloop index="i" from="1" to="#data.RecordCount#">
<cfset result[i][1]=data.FIPS_County[i]>
<cfset result[i][2]=data.CountyName[i]>
</cfloop>
<!--- And return it --->
<cfreturn result>
</cffunction>
</cfcomponent>
If the data is a fixed length you can use NumberFormat to force leading zero's. In general, CF is typeless so there must be some underlying conversion happening that is causing the data to get corrupt. You might try forcing the value toString(), or to debug add something like a single quote as the first character in the column value (eg. SELECT '''' + FIPS_County, '''' + CountyName FROM lkuCnty) to see if they keep all their characters.
[Update]
Based on your comments about how SQL is not returning 5 char, use this updated query to go from INT to VARCHAR with leading zeros.
SELECT DISTINCT
RIGHT('00000' + CONVERT(VARCHAR(5),StateUSAbb),5),
lkuState.StateName
FROM lkuState INNER JOIN tblLoc ON lkuState.FIPS_State = tblLoc.FIPS_State
WHERE (lkuState.StateName <> 'New Brunswick')
UNION
SELECT '' AS StateUSAbb,
' ALL' AS StateName
FROM lkuState
ORDER BY StateName
append a space to the end of the number, then CF will treat it as a string and no leading 0 will be chopped.
simple workaround: <cfset result[i][1]=data.StateUSAbb[i] & " ">
btw, you know that query object is supported for populating cfselect right? So you don't even need the loop. You can do the same workaround but in SQL inside your cfquery
UPDATE: anyway, the idea is that if u want to preserve the leading 0 and keep using CF's built in serializeJSON() or calling the cfc remote method in JSON style (which will internally invoke serializeJSON(), you can append a space so CF will treat it as a string and leading 0 will be preserved. If your script somehow must need "012345" with no trailing space, then look for another JSON seralizer from riaforge or cflib.
You're sure the data returned from your query is a text string which contains the leading zero, rather than just the integer value? Regardless, I think Zachary's suggestion of NumberFormat(x, "00000") is the way to go.