Strange database error in Coldfusion - coldfusion

I have two queries:
<cfquery name="getChairReview" datasource="#application.dsn#">
SELECT*
FROM eval_reviews
WHERE faculty = <cfqueryparam cfsqltype="cf_sql_numeric" value="#HTMLEditFormat(trim(arguments.id))#">
AND evalYear = <cfqueryparam cfsqltype="cf_sql_numeric" value="#HTMLEditFormat(trim(arguments.evalYear))#">
AND levels = <cfqueryparam cfsqltype="cf_sql_varchar" value="chair">
</cfquery>
<cfreturn getChairReview>
</cffunction>
<cffunction name="getDeanReview" access="public" returntype="query">
<cfargument name="id" type="numeric" required="yes">
<cfargument name="evalYear" type="numeric" required="yes">
<cfset var getDeanReview = QueryNew("")>
<cfquery name="getDeanReview" datasource="#application.dsn#">
SELECT*
FROM eval_reviews
WHERE faculty = <cfqueryparam cfsqltype="cf_sql_numeric" value="#HTMLEditFormat(trim(arguments.id))#">
AND evalYear = <cfqueryparam cfsqltype="cf_sql_numeric" value="#HTMLEditFormat(trim(arguments.evalYear))#">
AND levels = 'dean'
</cfquery>
<cfreturn getDeanReview>
</cffunction>
Both of them work fine when evalYear is 2012. If I send in 2011 I get an error on getDeanReview that states: [Macromedia][SQLServer JDBC Driver][SQLServer]Error converting data type varchar to numeric
The line it gives this error on is the AND levels = 'dean' (note: I had taken out the cfqueryparam tag to make sure I didn't goof that up.)
I find this strange because these two queries are almost identical except one has chair as a param and the other dean. (Yes, I could have had one function to do the job...with extra param for level)
I changed 'dean' to 'chair' with evalYear still 2011...guess what? It worked. This is quite odd...
levels is a varchar field.
Any ideas?

That's weird.
Okay, for grits & shins, try making the second query:
and levels like '%dean%'
Also, try it the way you have it, but remove the line about year and let it select everything regardless of year... see what your output looks like.
Lastly.. I don't think you need to worry about HTMLEditFormat in your value params in cfqueryparam.
Rob

Related

Can I return columns in text form from a function with sql query in coldfusion

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.

CF two tables have one idea match Name from the other

I am trying to combine two tables in the first table (dbo.Dealer_Track_Work) I have a dealerID this is ID matches the ID number for the second table (dbo.Dealer_Track_Dealers) and I am trying to have the dealerID match the Name from the second table and display instead of the number. Will someone please tell me where I might be going wrong?
<cffunction name="displayTable" access="public" returntype="query">
<cfset var processTable = ''>
<cfquery name="processTable">
SELECT *
FROM dbo.Dealer_Track_Work, dbo.Dealer_Track_Dealers
WHERE dbo.Dealer_Track_Work.dealerID = dbo.Dealer_Track_Dealers.Name
</cfquery>
<cfreturn processTable>
</cffunction>
<cfoutput>#Name#</cfoutput>
Table 1
Table2
<cffunction name="displayTable" access="public" returntype="query">
<cfset var processTable = ''>
<cfquery name="processTable">
SELECT name
FROM dbo.Dealer_Track_Work, dbo.Dealer_Track_Dealers
WHERE dbo.Dealer_Track_Work.dealerID = dbo.Dealer_Track_Dealers.id
</cfquery>
<cfreturn processTable>
</cffunction>
<cfoutput>#processTable.Name#</cfoutput>
Ideally you would use the ANSI join syntax
<cffunction name="displayTable" access="public" returntype="query">
<cfset var processTable = ''>
<cfquery name="processTable">
SELECT name
FROM dbo.Dealer_Track_Work
INNER JOIN dbo.Dealer_Track_Dealers ON dbo.Dealer_Track_Work.dealerID = dbo.Dealer_Track_Dealers.id
</cfquery>
<cfreturn processTable>
</cffunction>
<cfoutput>#processTable.Name#</cfoutput>

How to join two queries from different databases without qoq?

I have two different queries
<cfquery datasource="#one#" name="GetResults">
SELECT ID, Account, Value
FROM Logger_Events
left join Event_Details
on ID = EventID
where type = '123'
</cfquery>
<cfquery datasource="#two#" name="getSubtotal">
select account from daily
</cfquery>
The first query gives me like 200 records , the second query gives me like
half a million records.
Is there a way i can make the second query get the records from the first query,
without making a query of queries?
I would be using the account column to join.
The tables are in different servers.
This is one of the reasons for a QoQ. You could run the 1st query, then convert the data to XML and pass it as a parameter to a stored proc on the 2nd DB server in order to filter the 2nd query directly on the DB. Just join to the XML or use the XML to populate a temp table.
Since you are using sql server, I suggest linked servers. Pick one of your servers and set up a linked server to the other one. Then set up a stored procedure that does something like this;
declare #TempTable table (field1 datatype1, etc);
insert into #TempTable (field1, field2, etc)
select field1, field2, etc
from openquery
(linkedServerName,
'select field1, field2 etc
from blah blah blah
')
select yourfields
from #TempTable join aTableInThatDB on etc
The details are kind of painful at first, but it works very well. Also, there is lot's of information regarding linked servers and openquery on the internet.
I have done this function to Replace the foreign key of a table for a text field contained in the foreign table. This could instead append new columns to the original query with QueryAddColumn() and QuerySetCell().
The idea is to convert one of the queries into a struct.
My function is pretty basic but at the moment looks something like this:
<cffunction name="joinNameFromIDStructs" returnType="query" hint="Returns the Fund Activity">
<cfargument name="qryMain" type="query" required="Yes" hint='The query which is going to be translated' >
<cfargument name="foreignTable" type="string" required="Yes" hint='table which contains the details of our foreign column' >
<cfargument name="foreignPK" type="string" required="No" default="#arguments.foreignTable#ID" hint="Primary Key in the foreign table" >
<cfargument name="foreignKey" type="string" required="Yes" hint="column in the main table which references another table" >
<cfargument name="foreignText" type="string" required="Yes" hint="the column in the foreing table which hold the required details. It will override the foreign key column in the main table" >
<cfset var idPK = "">
<cfset var qryForeignTable = "">
<cfset var stForeignTable = StructNew()>
<cfset var listForeignPKs = evaluate("ValueList(arguments.qryMain.#arguments.foreignKey#)")/>
<cfif ListLen(listForeignPKs)>
<cfquery name="qryForeignTable" datasource='#application.siteDataSource#' >
SELECT #arguments.foreignPK#, #arguments.foreignText# FROM #arguments.foreignTable#
WHERE #arguments.foreignPK# IN (<cfqueryparam cfsqltype="cf_sql_integer" value='#arrayToList(listToArray(listForeignPKs))#' list="true" />) <!--- CF8 does not support ListRemoveDuplicates , hence we will use the array conversion to remove empties --->
</cfquery>
<cfloop query='qryForeignTable'>
<cfset stForeignTable[qryForeignTable[arguments.foreignPK][qryForeignTable.currentrow]] = qryForeignTable[arguments.foreignText][qryForeignTable.currentrow]/>
</cfloop>
<cfloop query='arguments.qryMain'>
<cfset idPK = arguments.qryMain[arguments.foreignKey]/>
<cfif idPK neq "">
<cfset arguments.qryMain[arguments.foreignKey][arguments.qryMain.currentrow] = stForeignTable[idPK]/>
</cfif>
</cfloop>
</cfif>
<cfreturn arguments.qryMain/>
</cffunction>

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!

How to pass a parameter value to a ColdFusion database query

I have written a database query to extract information in ColdFusion and I want to know how may I pass a value to the WHERE clause to get the relevant data. This is my code sample. can any one help?
<cfquery name="FILM_STRIP_QUERY" datasource="#dsn#">
select distinct tm.id as teachingmoduleid,
(select concat(prs.first_name, ' ',prs.last_name) AS Video_presenter from presentations pss
inner join topics tpcs on tpcs.id = pss.topic_id
inner join presenters prs on prs.id = pss.presenter_id
where pss.name = ps.name
and tpcs.title = tp.title
) AS video_presenter,
(select pss.43_png from presentations pss
inner join topics tpcs on tpcs.id = pss.topic_id
inner join presenters prs on prs.id = pss.presenter_id
where pss.name = ps.name
and tpcs.title = tp.title) AS png_name
from teaching_modules tm
inner join tm_segments sg on sg.module_id = tm.id
inner join topics tp on tp.id = sg.topic_id
inner join presenters prs on prs.id = tm.presenter_id
left outer join presentations ps on ps.id = sg.presentation_id
where tm.id =
</cfquery>
and this is the calling function
<cfloop = "FILM_STRIP_QUERY">
<!--- this is where I wanna pass the parameter--->
</cfloop>
Do you mean something like this?
<cfset tmId = 5 />
<!--- or something like <cfset tmId = url.id /> --->
<cfquery name="FILM_STRIP_QUERY" datasource="#dsn#">
<!--- SELECT cols FROM wherever etc... --->
WHERE tm.id = <cfqueryparam cfsqltype="cf_sql_integer" value="#tmId#" />
</cfquery>
You could just do #tmid# without the CFQueryParam tag, but it's a good idea to use it for added security (validation) and the database will also cache the execution plan, hopefully improving performance the next time the query executes.
If you are using a CFC, then a function like this would work, including the query name ensuring CF releases the memory from the local variable declaration. Also uses the parameter and the cfqueryparam function.
<cffunction name="getFILM_STRIP" access="public" returntype="query" output="false">
<cfargument name="id" required="Yes" type="numeric">
<cfset FILM_STRIP_QUERY = "">
<cfquery name="FILM_STRIP_QUERY" datasource="#variables.dsn#">
<!--- select statement --->
WHERE colname = <cfqueryparam cfsqltype="CF_SQL_INTEGER" value=#arguments.id# />
</cfquery>
<cfreturn FILM_STRIP_QUERY>
</cffunction>
You should use the cfqueryparam tag to do this. This helps DB execution and also helps prevent SQL injection. e.g.
where tm.id = <cfqueryparam value="#form.ID#" CFSQLType="CF_SQL_INTEGER">