Query of Queries failing in Coldfusion 10 - coldfusion

I'm getting and error when I tried to do a query of query.
Table named allData was not found in memory. The name is misspelled or the table is not defined.
I have an excel document and I'm outputting to a coldfusion var called allData, then I'm doing a query on that var. but I'm getting an error:
What am I doing wrong? The first dump shows the table appropriately.
function name="validateExcel" access="public" output="yes" returnType="void"
hint="search for dogs">
<cfspreadsheet
action="read"
src="#SESSION.theExcelFile#"
headerrow= "1"
excludeHeaderRow = "true"
query = "allData"
rows = "1-25"/>
<cfdump var = "#allData#"/>
<cfset rotCheck = new Query(
sql = "SELECT * FROM allData where dogType like '%rot'",
dbtype = "query"
) />
<cfset dogResult = rotCheck.execute().getResult() />
<cfdump
var = "#dogResult#" />
</cffunction>

(From comments ...)
I have to run, but short answer - the query variable from the spreadsheet is not in scope within the Query.cfc. (The documentation on Query.cfc is somewhat lacking IMO. ) Either pass in the query object as a parameter ie new Query(...., allData=allData) or use a <cfquery> instead.

Given that the dump works, the allData variable exists. A cfquery tag with the appropriate attributes will solve your problem for you.

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.

Getting CLOB data from ColdFusion 8

I am trying to retrieve CLOB data from our Oracle database. the code is the following:
<cfstoredproc datasource="#request.site.datasource#" procedure="GETPAGESWITHMETADATA" result="myResults">
<cfprocparam cfsqltype="CF_SQL_VARCHAR" type="in" value="News">
<cfprocparam cfsqltype="CF_SQL_VARCHAR" type="in" value="News Pages">
<cfprocparam cfsqltype="CF_SQL_CLOB" type="out" variable="XML">
<cfprocresult name="rs1">
</cfstoredproc>
<cfdump var="#myResults#">
<cfoutput>#XML#</cfoutput>
<cfcatch type="any">
<cfdump var="#cfcatch#">
</cfcatch>
</cftry>
Basically, the output of the stored procedure is:
select dbms_xmlquery.getxml(queryCtx) INTO XML from dual;
I checked the data sources on the server and the "Enable long text retrieval (CLOB)." option is checked for every data source.
Surprisingly, instead of getting the XML result on screen, I get a very short string:
[C#74897f5e
It looks like a handle id instead of the content itself.
How can I retrieve the complete content of the XML?
For reference, the data source is using macromedia drivers with TNS name:
Driver class: macromedia.jdbc.MacromediaDriver
As #MarkAKruger suggested, returning a table from the procedure solved the issue.
The following PL/SQL code did the trick:
create or replace
PACKAGE PCK_Commonspot
AS
type t_clob IS record (metadata CLOB) ;
type t_clob_tab IS TABLE OF t_clob;
FUNCTION GetPagesWithMetadataAsRS(FormName varchar2, CategoryName varchar2)
RETURN t_clob_tab pipelined;
END PCK_Commonspot;
The package body contains the following code:
FUNCTION GetPagesWithMetadataAsRS(FormName varchar2, CategoryName varchar2)
RETURN t_clob_tab pipelined
IS
r t_clob;
BEGIN
GETPAGESWITHMETADATA(FormName, CategoryName, r.metadata) ;
pipe row(r) ;
RETURN;
END;
The function GETPAGESWITHMETADATA is the one returning a CLOB into r.metadata
Here, the trick is around returning a piped table.
It becomes super nice on the ColdFusion side because the call is really simple:
<cfquery name="Test" datasource="myDS" maxrows="1">
SELECT * FROM TABLE(PCK_Commonspot.GetPagesWithMetadataAsRS('abc','def'))
</cfquery>
<cfset XML = Xmlparse(Test.Metadata)>
Thanks Mark!
Check your datasource settings in the CF Administrator. Under the advanced settings, there are check boxes to allow BLOB and CLOB data to be returned. If they are unchecked you potentially could get truncated data returned in your queries
Even though Jaepetto has already answered his question, I thought I'd contribute another answer for posterity.
I was having similar problems returning CLOB data into CF8 from Oracle 11g. The original solution (that wasn't working) was roughly:
<cfquery name="GetDoc" DATASOURCE=myDS>
SELECT CLOBDATA FROM FILES WHERE FILES.FILEID = #FileID#
</cfquery>
This query would complete successfully, but GetDoc.CLOBDATA would always be an empty string. It turned out that retrieving CLOB data using cfquery would always do this, but if I wrapped it up in a stored proc then it worked. I assume this is some quirk of the JDBC drivers we're using.
Anyway, the CF guts of my solution was as follows. Note the use of CF_SQL_LONGVARCHAR instead of CF_SQL_CLOB - using CF_SQL_CLOB gave me the weird handle ID value that Jaepetto was seeing.
<cfstoredproc PROCEDURE="GETCLOB" DATASOURCE=myDS >
<CFPROCPARAM TYPE="IN" CFSQLTYPE="CF_SQL_INTEGER" DBVARNAME="pFileID" value="#fileID#"/>
<CFPROCPARAM TYPE="OUT" CFSQLTYPE="CF_SQL_LONGVARCHAR" DBVARNAME="pClob" VARIABLE="vClob" />
</cfstoredproc>
<!--- Dump the clob to the local filesystem --->
<cfscript>
fstream = CreateObject("java", "java.io.FileOutputStream").init(filepath, JavaCast("boolean","true"));
outStream = CreateObject("java", "java.io.BufferedOutputStream").init(fstream);
outStream.write(#toBinary(vClob)#);
outStream.flush();
outStream.close();
</cfscript>

how to store query data in variables in ColdFusion for use later?

I am trying to retrieve and store ID's for each item retrieved from my table, so I can use these ID's later. I tried nesting the queries, but this didn't, work. Here is my first query:
<CFQUERY datasource="MyDSN" name="MAIN2"> SELECT * from order_items where orderID= #orderID#</CFQUERY>
Now, if I output this query it displays, 1 and 117 which are the two ID's I need.
My next query is:
<CFQUERY datasource="MyDSN" name="MAIN3">select c.catalogueID,
c.product_name,
c.product_price,
c.description,
p.productID
from products p
join product_catalogue c on c.catalogueid = p.catalogueid
where p.productid = "#productID#"</CFQUERY>
But it is telling me that productID is not defined, it is obviously empty. I am just getting started using ColdFusion, so I am not sure the best way to store the values I need so I use them again. I also need to loop the second query to run for each ID 1 and 117, so twice.
Any suggestions on how to accomplish this would be greatly appreciated.
Thanks
My basic rule is that if I find myself using queries to create other queries or looping over a query to execute other queries; it is time to consider combining the queries.
I'm not sure what field you are using in the MAIN2 query to feed the MAIN3 query. So, I put in "productID" in the query below. You may have to change it to fit your field name.
<CFQUERY datasource="MyDSN" name="MAIN3">select c.catalogueID,
c.product_name,
c.product_price,
c.description,
p.productID
from products p
join product_catalogue c on c.catalogueid = p.catalogueid
where p.productid IN (SELECT DISTINCT productID from order_items where orderID= <cfqueryparam value="#orderID#" cfsqltype="CF_SQL_INTEGER">)
</CFQUERY>
You could also change this query to utilize a "join" to connect [order_items] to the query.
Lastly, you should use the <cfqueryparam> tag for the where clauses; this helps protect your query from sql injection attacks.
Whenever I'm caching data for use later, I tend to ask myself how I'll be using that data, and whether it belongs in another data type rather than query.
For instance, if I'm wanting a bunch of data that I'm likely to access via ID, I can create a structure where the key is the ID, and the data is another structure of a dataset. Then I'll save this structure in application scope and only refresh it when it needs to be. This is zippy fast and so much easier to grab with
rather than querying for it every time. This is especially useful when the query that creates the original data set is kind of a resource hog with lots of joins, sub-queries, magical cross-db stored procedures, but the datasets returns are actually fairly small.
So creating your products structure would look something like this:
<CFQUERY datasource="MyDSN" name="MAIN3">
SELECT
c.catalogueID,
c.product_name,
c.product_price,
c.description,
p.productID
FROM products p
JOIN product_catalogue c
ON c.catalogueid = p.catalogueid
WHERE p.productid = <cfqueryparam value="#ProductID#" cfsqltype="cf_sql_integer">
</CFQUERY>
<cfset products = structNew() />
<cfset item = structNew() />
<cfloop query="MAIN3">
<cfif NOT structKeyExists(products, productID)>
<cfset item = structNew() />
<cfset item.catalogueID = catalogueID />
<cfset item.product_name = product_name />
<cfset item.product_price = product_price />
<cfset item.description = description />
<cfset products[productID] = structCopy(item) />
</cfif>
</cfloop>
<cfset application.products = structCopy(products) />

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.

Can I get a query row by index in ColdFusion?

I want to get a specific row in a ColdFusion Query object without looping over it.
I'd like to do something like this:
<cfquery name="QueryName" datasource="ds">
SELECT *
FROM tablename
</cfquery>
<cfset x = QueryName[5]>
But it's giving me an error saying that the query isn't indexable by "5". I know for a fact that there are more than 5 records in this query.
You can't get a row in CF <= 10. You have to get a specific column.
<cfset x = QueryName.columnName[5]>
It's been 8 years since I posted this answer, however. Apparently CF11 finally implemented that feature. See this answer.
This can now be accomplished in coldfusion 11 via QueryGetRow
<cfquery name="myQuery" result="myresult" datasource="artGallery" fetchclientinfo="yes" >
select * from art where ARTID >
<cfqueryparam value="2" cfsqltype="CF_SQL_INTEGER">
</cfquery>
<cfdump var="#myQuery#" >
<cfset data = QueryGetRow(myQuery, 1) >
<cfdump var="#data#" >
I think there is a simpler solution...
I am guessing you know your column names and only want this column or that one. Then you don't need to put the whole row in a struct. You can reference the query by row number (remember its 1 based not 0).
yourQueryName["yourColumnName"][rowNumber]
<cfoutput>
#mycontacts["Name"][13]#
#mycontacts["HomePhone"][13]#
</cfoutput>
You have to convert the query to a struct first:
<cfscript>
function GetQueryRow(query, rowNumber) {
var i = 0;
var rowData = StructNew();
var cols = ListToArray(query.columnList);
for (i = 1; i lte ArrayLen(cols); i = i + 1) {
rowData[cols[i]] = query[cols[i]][rowNumber];
}
return rowData;
}
</cfscript>
<cfoutput query="yourQuery">
<cfset theCurrentRow = GetQueryRow(yourQuery, currentRow)>
<cfdump var="#theCurrentRow#">
</cfoutput>
Hope this points you in the right direction.
I know I come back to this thread any time I Google "cfquery bracket notation". Here's a function I wrote to handle this case using bracket notation. Hopefully this can help someone else too:
<cffunction name="QueryGetRow" access="public" returntype="array" hint="I return the specified row's data as an array in the correct order">
<cfargument name="query" required="true" type="query" hint="I am the query whose row data you want">
<cfargument name="rowNumber" required="true" hint="This is the row number of the row whose data you want">
<cfset returnArray = []>
<cfset valueArray = []>
<cfset cList = ListToArray(query.ColumnList)>
<cfloop from="1" to="#ArrayLen(cList)#" index="i">
<cfset row = query["#cList[i]#"][rowNumber]>
<cfset row = REReplace(row, "(,)", " ")>
<cfset returnArray[i] = row>
<cfset i++>
</cfloop>
<cfreturn returnArray>
</cffunction>
The REReplace is optional, I have it in there to cleanse commas so that it doesn't screw up the arrayToList function later on if you have to use it.
I wanted to extract a single row from a query, and keeping the column names (of course). This is how I solved it:
<cffunction name="getQueryRow" returntype="query" output="no">
<cfargument name="qry" type="query" required="yes">
<cfargument name="row" type="numeric" required="yes">
<cfset arguments.qryRow=QueryNew(arguments.qry.columnlist)>
<cfset QueryAddRow(arguments.qryRow)>
<cfloop list="#arguments.qry.columnlist#" index="arguments.column">
<cfset QuerySetCell(arguments.qryRow,arguments.column,Evaluate("arguments.qry.#arguments.column#[arguments.row]"))>
</cfloop>
<cfreturn arguments.qryRow>
</cffunction>
Methods previously described for obtaining query data by column name and row number (variables.myquery["columnName"][rowNumber]) are correct, but not convenient for getting a full row of query data.
I'm running Railo 4.1. And this is a cool solution. Too bad this can't be done the way we would want outright to get a full row of data, but the following method allows us to get what we want through a few hoops.
When you serializeJSON(variables.myquery) it changes the query to a JSON formatted cfml struct object with two items: "Columns" and "Data". Both of these are arrays of data. The "data" array is a two-dimensional array for rows and then columnar data.
The issue is that now we have an unusable string. Then if we re-serialize it it's NOT a query, but rather usable regular struct in the format described above.
Assume we already have a query variable named 'variables.myquery'. Then look at the following code:
<cfset variables.myqueryobj = deserializeJSON(serializeJSON(variables.myquery)) />
Now you get the two dimensional array by getting this:
<cfset variables.allrowsarray = variables.myqueryobj.data />
And you get one query row array by getting this:
<cfset variables.allrowsarray = variables.myqueryobj.data[1] />
OR the last row this way:
<cfset variables.allrowsarray = variables.myqueryobj.data[variables.myquery.recordCount] />
And you can get individual column values by column order number iteration:
<cfset variables.allrowsarray = variables.myqueryobj.data[1][1] />
Now this might be slow and possibly unwise with large query results, but this is a cool solution nonetheless.
Check out the documentation for queryGetRow. It accepts a query object and an index of the row with the first row being referenced with the index of 1 (NOT 0) The index used this way is required to be a positive integer.
<cfquery name="QueryName" datasource="ds">
SELECT *
FROM tablename
</cfquery>
<!---
This would retrieve the first record of the query
and store the record in a struct format in the variable 'x'.
--->
<cfset x = queryGetRow(QueryName, 1) />
<!---
This is an alternative using the member method form of queryGetRow
--->
<cfset x = QueryName.getRow(1) />