conditional query in coldfusion - coldfusion

I need to provide some status on items in my table which I do in the last column of my table.
First I go and query one table to see if I have a confirmation for the item .
<cfquery name="focnotice" datasource="******" result="FocResult">
SELECT ecspc
FROM tbl_CNR_H
WHERE icsc = '#myarray[i].ICSC#'
AND asr_no = '#myarray[i].ASR#'
</cfquery>
The ECSPC is a field in my Table, so logic is see if there is a record. If so, see if the ECSPC value is something other then "". If so, query another table to see if there is a matching record for this ECSPC.
<cfset ISUPStatus = "#focnotice.ecspc#">
<cfif ISUPStatus NEQ "">
<cfquery name="isupStatus" datasource="******" result="ISUPResult">
select *
from tbl_ISUP
where dpc = '#ISUPStatus#'
</cfquery>
<cfset isupcount = #ISUPResult.RecordCount#>
<cfif #isupcount# GT 0>
<cfset ISUPorder = "Yes">
<cfelse>
<cfset ISUPorder = "No">
</cfif>
<cfelse>
<cfset ISUPorder = "No">
</cfif>
I get the following error in my debug
Complex object types cannot be converted to simple values.
The expression has requested a variable or an intermediate expression
result as a simple value. However, the result cannot be converted to a
simple value. Simple values are strings, numbers, boolean values, and
date/time values. Queries, arrays, and COM objects are examples of
complex values. The most likely cause of the error is that you tried
to use a complex value as a simple one. For example, you tried to use
a query variable in a cfif tag.
What am I missing here ?

You are passing invalid parameter into the Query "myarray[i].ICSC",'#myarray[i].ASR#'. You need to specify what index of array you are using.
<cfquery name="focnotice" datasource="*******" result="FocResult">
Select ecspc
From tbl_CNR_H
Where icsc = <cfqueryparam cfsqltype="cf_sql_varchar" value="#myarray[1].ICSC#">
AND
asr_no = <cfqueryparam cfsqltype="cf_sql_varchar" value="#myarray[1].ASR#">
</cfquery>

I believe the error causing you the issue lies in:
<cfset isupcount = #ISUPResult.RecordCount#>
From a quick look of your code, try using instead:
<cfset isUpCount = isUpStatus.recordCount>
But in addition please look at the comments above, especially joins.

Related

Merging a array of queries into a single query

I want to merge an array of queries into one query
I have tried this
<cfquery name="MergedData" dbtype="query">
<cfloop from="1" to="#arrayLen(arData)#" index="k">
SELECT *
FROM arData[k]
<cfif k LT ArrayLen(arData)>UNION</cfif>
</cfloop>
ORDER BY EID
</cfquery>
I get an error that looks like
<br><b>Query Of Queries syntax error.</b><br> Encountered "[k].
Try an alternative way of looping over your array. You need to create your own counter though to figure out the logic of if you need to keep appending 'UNION' to your SQL statement.
<cfset i = 1>
<cfquery name="MergedData" dbtype="query">
<cfloop index="k" array="#arData#">
SELECT *
FROM k
<cfif i LT ArrayLen(arData)>UNION</cfif>
<cfset i++>
</cfloop>
ORDER BY EID
</cfquery>
NB: you wouldn't need to calculate a counter yourself if you're using Railo instead of Adobe CF, as you can then do both index and item like so, as Peter mentioned in the comments above:
<cfloop index="i" item="k" array="#arData#">
If you'd like to accomplish this with functional programming, you could use the Underscore.cfc library (requires CF 10+ or Railo 4+):
// instantiate Underscore library
_ = new Underscore();
// convert the array of queries to a single array of structs
mergedArray = _.reduce(arrayOfQueries, function (memo, query) {
// convert current query to an array of structs
// and concatenate it to the rest of the result
return _.concat(memo, _.toArray(query));
}, []);
// convert the array of structs back to a query
mergedQuery = _.toQuery(mergedArray);
This solution utilizes reduce() to combine the array of queries into a single array of structs. The anonymous function passed to reduce() converts each query in the array of queries to an array of structs using toArray(), then concatenates that array with the rest of the array of structs (the memo value).
Once the array of queries has been converted to a single array of structs, it is a simple matter to convert it back to a query using toQuery() (assuming that is necessary).
Note: I wrote the Underscore library
Try like this:
<cfsavecontent variable="testing">
<cfset j = 1>
<cfloop array="#test#" index="i">
SELECT id FROM #i# LIMIT 10
<cfif j LT ArrayLen(test)> UNION </cfif>
<cfset j++>
</cfloop>
</cfsavecontent>
<cfquery name="qTest" datasource="#application.dsn#">
#testing#
</cfquery>
This is what end up working
<cfquery name="local.qryMergedData" dbtype="query">
<cfloop array="#arguments.Data#" index="k">
<cfset local.currentIndex++>
<cfset setvariable("Data_#local.currentIndex#", k)>
SELECT *
FROM Data_#local.currentIndex#
<cfif local.currentIndex LT local.MaxIndex>UNION</cfif>
</cfloop>
ORDER BY EID
</cfquery>
I really don't like that I am setting a variable inside of a <cfquery>, but at least it is only one query

Set a variable dynamically into a structure via CFLOOP

I am trying to set a variable dynamically into a structure via CFLOOP. I have read Ben Nadal's blog post but cant seem to get the assignment correct. I would like to use dot notation and make the VIN a sub structure of values.
Here is my code:
<cfloop query="VINs">
<cfquery name="carsQue" datasource="carsData">
SELECT VIN, MODEL, MAKE, etc
FROM CarsDB
WHERE (VIN = #VIN#)
</cfquery>
<cfset carsStruct= StructNew()>
<cfset carsStruct.[VIN].MAKE = '#carsQue.MODEL#'>
<cfset carsStruct.[VIN].MODEL = '#carsQue.MAKE#'>
</cfloop>
Any guidance would be greatly appreciated,
Thanks
Running a query inside a loop is almost always a bad idea. In your case, a better option would be:
<cfif ListLen(valuelist(vins.vin)) gt 0>
<cfquery name=CarsQue datasource = "carsData">
select vin, model, make, etc
from carsDB
where vin in (<cfqueryparam cfsqltype="cf_sql_varchar"
value="#valuelist(vins.vin)#" list="true">)
</cfquery>
<cfset carsStruct = StructNew()>
<cfloop query="carsQue">
code for your struct
</cfloop>
<cfelse>
code for vins query returning no data
</cfif>
Better yet would be to get all the data with one query. You didn't provide enough information to determine if this was possible, but it often is.
Create a structure outside loop and and setting variable within loop can solve the problem. in a current scenario each time loop run its create a new structure.
you can do some thing like this
<cfset carsStruct= StructNew()>
<cfloop query="VINs">
<cfquery name="carsQue" datasource="carsData">
SELECT VIN, MODEL, MAKE, etc
FROM CarsDB
WHERE VIN = <cfqueryparam cf_sql_type="cf_sql_varchar" value="#VINs.VIN#">
</cfquery>
<cfset carsStruct[VINs.VIN].MAKE = carsQue.MODEL>
<cfset carsStruct[VINs.VIN].MODEL = carsQue.MAKE>
</cfloop>
Based on the limited information you've given you should be able to run one query and loop through that to add to your struct.
<cfset carsStruct= {}> //new struct
<cfif VINs.RecordCount> //your VINs query has records
<cfquery name="carsQueue" datasource="carsData">
SELECT VIN, MODEL, MAKE, etc
FROM CarsDB
// Quoted list of all your VINs. cfqueryparam prevents against SQL injection
WHERE VIN IN (<cfqueryparam cf_sql_type="cf_sql_varchar" value="#ValueList(VINs.VIN)#" list="true">
</cfquery>
<cfloop query="carsQueue">
<cfset carsStruct.[carsQueue.VIN].MAKE = carsQueue.MODEL>
<cfset carsStruct.[carsQueue.VIN].MODEL = carsQueue.MAKE>
</cfloop>
<cfelse>
// if VINs query return nothing a blank struct will be returned.
//You do NOT need this <cfelse> unless you are returning something when the query is blank
</cfif>

ColdFusion having multiple cfqueries in cffunction

I am trying to write a function for a survey where it pulls questions from a database. The catch is that there are both active and unactive questions. I need older questions to show up when someone views the results from an old survey.
Here is the code I am trying within a CFC:
<cffunction name="getAllQuestions" access="public" returntype="query">
<cfargument name="survey" default=0>
<cfif len(#survey#) gt 0>
<cfquery name="getsdate" datasource="blah.database">
select * from past_survey
where survey_id = #survey#
</cfquery>
<cfreturn getsdate>
</cfif>
<cfquery name="getquestions" datasource="blah.database">
select * from pool_questions
<cfif len(#survey#) eq 0>
where active_flag='Y'
<cfelse>
where <cfqueryparam value="#dateformat
(getsdate.survey_date, "yyyy/mm/dd")#"> BETWEEN start_date AND
end_date
</cfif>
order by qtn_nb
</cfquery>
<cfreturn getquestions>
</cffunction>
#survey# is the survey id which is generated by the form. What I am trying to do is that if survey has a value to run query getsdate. Then the second query would run no matter if survey has a value or not. If there is not value it should pull all active questions. If there is a value then it should check if the survey date is between the start date and end date for past questions.
Any advice on how to make this work would be greatly appreciated. Thank you in advance!
<cffunction name="getAllQuestions" access="public" returntype="struct">
<cfargument name="survey" required="true" default="0" type="numeric">
<cfset var qryReturn = ""> <!---Always var scope your variables to prevent them from leaking to other functions --->
<cfset var structReturn = structNew()>
<cfset structReturn.pastSurvey = "">
<cfset structReturn.surveyQuestions = "">
<cfif survey GT 0>
<cfquery name="qryReturn" datasource="blah.database">
SELECT *
FROM past_survey
<!--- Always cfqueryparam to prevent SQL injection attacks & also always reference the scope to prevent confusion --->
WHERE survey_id = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.survey#">
</cfquery>
<cfset structReturn.pastSurvey = qryReturn>
<cfelse>
<cfquery name="qryReturn" datasource="blah.database">
SELECT *
FROM pool_questions
<cfif arguments.survey EQ 0>
WHERE active_flag = 'Y'
<cfelse>
WHERE <cfqueryparam value="#dateformat
(getsdate.survey_date, "yyyy/mm/dd")#"> BETWEEN start_date AND
end_date
</cfif>
ORDER BY qtn_nb
</cfquery>
<cfset structReturn.surveyQuestions = qryReturn>
</cfif>
<cfreturn structReturn>
</cffunction>
You probably should be doing this in two separate functions, but I will attempt to answer your question.
My code will return a struct of queries (you can change to an array if you prefer) that returns a past survey and the survey questions
Note: In your example code, you have a few bad practices.
You are checking the length of the survey value rather than checking the value itself.
If you want to ensure that survey always has a value regardless of if it is passed or not, set requried=true and give it a default value.
Use cfqueryparam to prevent sql injection attacks
Any variables created in the function need to be var scoped to prevent them from leaking to other cffunctions in the same cfcomponent. I always do this at the top. Yes, even the name you give a cfquery needs to be var scoped.
Since you are doing a return after your first query, if the survey value is greater than 0 it will never get to the second query where it has the date check.
I see the following problems you need to address.
First, your survey argument has a default value of 0 and you are doing conditional logic on the length of it. The length of "0" is 1, so that condition will always return true.
Next, you state that you want the 2nd query to run whether the first one runs or not, but you refer to a value from the 1st query in the 2nd one. That means if the 1st query does not run, the 2nd one will crash due to an undefined variable.
Next, dateformat returns a string. Applying it the way you do in the 2nd query is at best unnecessary, and at worse, and indication that you are storing the start and end dates in pool_questions as strings. If you are attempting to strip out the time portion of the datefield in the first query, ColdFusion has a cast() function for that.
Also, scope your variables. ie - instead of <cfif len(survey), do this <cfif len(arguments.survey).
Also, var your local variables. In this case, it's the names of your two queries.
That should get you started.

Building a query param dynamically

Hi I am trying to build a query parameter dynamically, and am getting an error, i am using the code below,
<cfset featQuery="">
<cfloop list="#arguments.uid_features#" index="x">
<cfif x neq "0">
<cfif Len(featQuery) gt 0>
<cfset featQuery = featQuery& " AND ">
</cfif>
<cfset featQuery = featQuery & 'uid_prodf_featid = <cfqueryparam cfsqltype="CF_SQL_INTEGER" value="' & x & '">'>
</cfif>
</cfloop>
I get this error message from coldfusion;
[Macromedia][SQLServer JDBC Driver][SQLServer]Incorrect syntax near '<'.
If i look at the output, it looks correct, but normaly using cfquerypram, you just get (param1), uid_prodf_featid=(param1) in the error message it displays the following;
uid_prodf_featid = <cfqueryparam cfsqltype="CF_SQL_INTEGER" value="5">
Jason
You can't really build and execute CFML dynamically like you're attempting to do. It looks to me like you're trying to build a SQL query outside of a cfquery tag context; this would be fine, except for your need to parameterize it. If possible, change your code to run within a cfquery tag pair:
<cfquery...>
SELECT * FROM tableFoo
<cfif ListLen(arguments.uid_features)>
WHERE uid_prodf_featid IN (<cfqueryparam value="#arguments.uid_features#" list="true" cfsqltype="CF_SQL_INTEGER">)
</cfif>
</cfquery>
Also, as you can see I've changed your query structure a bit - you had a lot of code to do something that is much more easily accomplished as I show above.
edit
I see that you actually are doing AND operations with each item in your uid_features list... I have a hard time imagining there being a valid logical reason for that (rather than OR), but if so, my example won't work for that - instead change it back to a series of AND conditions within the loop.

coldfusion struct syntax and query data

I’ve mostly only used coldfusion for queries before never needed structs or any object notation until now. The server I am working on doesn’t have debugging turned on just a “500- internal server error.” so I am unable to see why my code is not working and sadly I do not have the ability to turn debugging on.
By trial and error with commenting blocks out I’ve noticed the errors are occurring in my struct line, and adding the struct to my array. From what I’ve read of the CF documentation I do not see any syntax errors but any help would be much appreciated as to if I have any bad logic or what could be wrong.
<cfset dataArray = []>
<cfset i = 0>
<cfloop query="getMembers">
<cfquery name="getmaps" datasource=“a" dbtype="odbc">
SELECT member_id, mlong, mlat
FROM maps
WHERE member_id = '#getMembers.MemberID#'
</cfquery>
<cfif getmaps.recordcount eq 1>
<!--- temp structure to insert into array --->
<cfset dataTemp = {
memberID = getMemebers.memberID,
name = getMemebers.MemberName,
long = getmaps.mlong,
lat = getmaps.mlat
}>
<cfset dataArray[i] = dataTemp>
<cfset i++>
</cfif>
</cfloop>
I addition to Shawn's comment, I believe you'll have a problem with starting your array index at 0, rather than 1. Coldfusion begins array indices at 1.
edit Some more suggestions:
<cfset dataArray = []>
<cfloop query="getMembers">
<!--- Not usually a good idea to query each time through a loop - should be able to do a single query outside it --->
<cfquery name="getmaps" datasource=“a" dbtype="odbc">
SELECT member_id, mlong, mlat
FROM maps
WHERE member_id = <cfqueryparam value='#getMembers.MemberID#' cfsqltype="cf_sql_varchar"><!--- assuming varchar since you had quotes around it --->
</cfquery>
<cfif getmaps.recordcount eq 1>
<!--- temp structure to insert into array --->
<cfset dataTemp = {
memberID = getMembers.memberID,
name = getMembers.MemberName,
long = getmaps.mlong,
lat = getmaps.mlat
}>
<cfset ArrayAppend(dataArray,dataTemp)>
</cfif>
</cfloop>
You should consider combining the two queries into one query.
<cfquery name="qryMemberMaps" datasource="a" dbtype="ODBC">
SELECT
members.memberID, members.MemberName,
maps.mlong, maps.mlat
FROM
[members_database].dbo.members JOIN [maps_database].dbo.maps ON members.memberID = maps.member_id
</cfquery>
The current method could potentially generate thousands of queries when you only need one!
Anytime you find yourself looping over a query and calling other queries, it is a good idea to revise the original query and save hammering your database server.
For putting the data into an array of structs, Jake's answer works well.
If you are joining multiple DB's make sure that you create a non-clustered index on the column(s) that will act as the primary/foreign keys.