Compare mysql query to sql query - coldfusion

I am a lot more at home manipulating arrays and objects in php or javascript, and do next to no work with coldfusion.
I have one query pulling data from mysql. I would like to store results list or array ( or simpler approach)
WHile looping over a second query from msql that generates html output I need to see if one value is contained in prior mysql array or list.
Have tried playing with varierty of cf array/list methods and really not sure what best approach is to resolve following if.
CF version is 9
<cfquery datasource="Mysql" name="premium_submitters">
SELECT submitter_id from table
</cfquery>
<!--- Need loop to store to array or list??--->
<cfquery datasource="Sql" name="main_data">
SELECT * from table
</cfquery>
<cfoutput query="main_data">
<cfif #submiiter_id# <!---is in Mysql array/list return boolean---> >
</cfif>
</cfoutput>

Use ValueList to get the value of one column of a query into a list.
<cfquery datasource="Mysql" name="premium_submitters">
SELECT submitter_id from table
</cfquery>
<cfset submittersList = ValueList(premium_submitters.submitter_id)>
<cfquery datasource="Sql" name="main_data">
SELECT * from table
</cfquery>
<cfoutput query="main_data">
<cfif ListFind(submittersList, main_data.submitter_id) gt 0>
<!--- is in list, do whatever --->
</cfif>
</cfoutput>

Related

conditional query in 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.

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

How can we add a new row in middle of a cfquery result?

I have a query result set from cfquery. I just want to add a new after a particular row number. But When tried each time it inserts the row at the end.
Is there any way I can insert row at the middle of the query?
<cfquery datasource="cse" name="abc">
select * from grade
</cfquery>
<cfset i = 0>
<cfloop query="abc">
<cfset i = i+1>
<cfif i eq 2>
<cfset queryAddRow(abc)>
</cfif>
</cfloop>
You cannot, easily. You have a coupla options.
<cfquery name="resultSet" dbtype="query">
SELECT col1, col2, etc
FROM yourQuery
WHERE [somecondition matching the "top" rows]
UNION
SELECT 'value' AS col1, 'value' AS col2, etc
UNION
SELECT col1, col2, etc
FROM yourQuery
WHERE [somecondition matching the "bottom" rows]
</cfquery>
Or you could simply loop over the original query, building a new query, using queryNew(), queryAddRow() and querySetCell(). At the appropriate point in the loop... add the row you want to insert, then continue adding the rest of them.
There's no elegant way I can think of.
Not knowing the goal you are trying to accomplish, my first advice would be along the lines of the other answers. Add rows that you can subsequently sort using Order By. However, if you really just want to inject a row at a specific position in the existing query, this should do it for you. Note you'll need to define the columns in the QueryNew(), so I've provided a sample case.
<cfquery datasource="cse" name="abc">
select student, teacher from grade
</cfquery>
<cfset abc_new = QueryNew("student,teacher","varchar,varchar")>
<cfloop query="abc">
<!--- ADD NEW DATA TO QUERY AT ROW 2 --->
<cfif CURRENTROW eq 2>
<cfset QueryAddRow(abc_new) />
<cfset QuerySetCell(abc_new,"STUDENT","Tommy Oliver") />
<cfset QuerySetCell(abc_new,"TEACHER","Ms. Appleby") />
</cfif>
<!--- COPY ORIGINAL DATA TO QUERY, ROW NUMBERS NOT PRESERVED --->
<cfset QueryAddRow(abc_new) />
<cfset QuerySetCell(abc_new,"STUDENT",abc.STUDENT) />
<cfset QuerySetCell(abc_new,"TEACHER",abc.TEACHER) />
</cfloop>
<cfdump var="#abc_new#">
The best way would be to create a new query, copying each row from the original but adding the new row at the required point.
Use QueryNew( ) to create the new query.
A bit like copying text files line-by-line and inserting a new line in the middle!
Again, not quite sure you'd need to do this - you could simply add a sortorder column, incrementing in 10s for each row. The new row would then have a sortorder in between the row before and the row after. eg sortorder would be 15 to insert between 10 and 20.
Hope this helps!
I assume row positions in your recordset are based on what you ORDER BY'd in your initial CFQUERY.
Therefore, I'd add the row to the recordset, then do a query of that recordset (query of query) using the same ORDER BY as the initial query, which should then return all rows including your new one, in the (presumed) proper order, in a new recordset.

Using array data to drill a query

I am learning about arrays and structs, and putting together a shopping cart as a project. I am currently creating a recently viewed products module for the cart. When a user views a product i collect the product id into an array,
What is the best way to use this info to query my database, my query would be
<cfquery name="getRecent" datasource="#application.dsn#">
SELECT uid_product,txt_product_name
FROM tbl_products
</cfquery>
I thought of outputting the array as a list and using the IN operator, but not sure if that is the right way of doing it, seems a bit cumbersome? Can I use a query of queries using the array data? If so any pointers?
If you just maintain a list of productIDs then you don't need to use arrays or structs, you can just store them as a simple list and query them as follows:
<cfset recentProducts = "4,5" />
<cfquery name="getRecent" datasource="#application.dsn#">
SELECT uid_product,txt_product_name
FROM tbl_products
where productID IN (<cfqueryparam cfsqltype="cf_sql_integer" value="#recentProducts#" list="true" />)
</cfquery>
Firstly, unless you're going to put additional things into the struct, I'd say having a struct just to hold ProductID seems excessive. I'd just have the Array with the productID as each element, no struct.
So your array is structured like:
[
{ ProductID= 4 },
{ ProductID= 5 },
...
]
I'd suggest you just do:
[4,5]
This will make the next step easier. Right now I'd say you have to loop over your array, adding each productID into a list that you can then use in your query. Then modify your original query to use that list (remember and use cfqueryparam).
<cfset lstIDs = "">
<cfloop index="productStruct" array="#productsArray#">
<cfset lstIDs = listAppend(lstIDs, productStruct.ProductID)>
</cfloop>
<cfquery name="getRecent" datasource="#application.dsn#">
SELECT uid_product,txt_product_name
FROM tbl_products
WHERE productID IN <cfqueryparam value="#lstIDs#" cfsqltype="CF_SQL_INTEGER" list="yes">
</cfquery>
Or, if you simplify your array, just do ArrayToList to achieve the same thing.
<cfquery name="getRecent" datasource="#application.dsn#">
SELECT uid_product,txt_product_name
FROM tbl_products
WHERE productID IN <cfqueryparam value="#ArrayToList(productsArray)#" cfsqltype="CF_SQL_INTEGER" list="yes">
</cfquery>

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.