Coldfusion Undefined Variables - but they're not - coldfusion

I hope I'm missing something really obvious here, because for the life of me I can't figure this one out at all!
I have a cfquery with some joins as follows;
SELECT f.*, p.ID AS prID, p.product_name, p.shortname, i.newthumb,
(SELECT AVG(reviewrating) FROM product_reviews AS pr WHERE pr.productid=p.id) AS reviewrating,
(SELECT description FROM product_descriptions AS d WHERE d.productid=p.id LIMIT 1) AS description
FROM followers_p f
LEFT JOIN products p
ON f.productID=p.ID
LEFT JOIN product_images i
ON i.productid=p.ID
WHERE f.wUserID='#getuser.wUserID#'
ORDER BY f.cID DESC
That executes fine and a cfdump of the query shows data is returned as it should be.
Further down the page, I'm running the cfoutput query. However, it's giving me an error 'Variable NEWTHUMB is undefined. '
I've tried grabbing the image as a subquery with Limit 1 and a few other things, but the result is always the same - cfdump shows the correct data, cfoutput gives an undefined error.
Anything else I can try to figure this one out? I've noticed a similar issue occurring on another page too.
Edit - the cfoutput code;
<cfoutput query="getproductfollow">
<img alt="#product_name#" src="#newthumb#">
#product_name#</span>
</cfoutput>

The name of your query isn't in your code, so I can't guarantee this is correct. It seems to be that your error is in your reference to your newthumb variable.
Your query should look like this:
<cfquery name="getproductfollow">
// SQL GOES HERE
</cfquery>
Your output should look like this:
<cfoutput query="getproductfollow">
<img alt="#product_name#" src="#newthumb#">
#product_name#</span>
</cfoutput>
You should show your ENTIRE query, wrapped in the as well as your . That would be really helpful.

Related

cfml and resorting part of a query

Just wondering, given a query and output like so:
<cfoutput query="someItems" group="someColumnName">
... doing some stuff here ..
<cfoutput> doing stuff with some sub items </cfoutput>
</cfoutput>
if there's a way to change the order of elements in the 'inner' cfoutput ?
Can the query be both grouped and sorted by?
You will need to add ORDER BY clauses in your query for this to work, but you can nest cfoutput tags that use the group attribute.
<cfoutput query="someItems" group="someColumnName">
... doing some stuff here ..
<cfoutput group="someOtherColumnName> doing stuff with some sub items </cfoutput>
</cfoutput>
This assumes that in your query you have something that looks like:
ORDER BY someColumnName, someOtherColumnName
Keep in mind that the group attribute of cfquery is not the same as the GROUP BY clause in a SQL statement. You can use the group attribute of cfoutput for ANY column that is in the ORDER BY clause in your query.
One solution is to restructure your code to use the query-of-queries approach. Here is a good example of doing so:
http://www.bennadel.com/blog/2211-ColdFusion-Query-Of-Queries-vs-The-Group-Attribute-In-CFOutput.htm
Basically, you pull out all the data you care about in one master query (probably the query you have already written). You add a second query (against your first query, not against the database) that does the group by and aggregation of data that you need at the top level loop. Inside the loop driven by your second query, you use the row data in the group as a parameter to yet another query (against your first query again, not against the database) to pull out all the data relating to the current row ordered however you desire.
This idea of querying your query seems odd at first, but I have not had performance problems with it and it gives you a lot of flexibility to do what you want in your inner loop. Good luck!

CFDump of query column does not display all values

The dumping results for the following QoQ are perfectly fine:
<cfquery datasource = "XX.XX.X.XX" name="master2">
SELECT DATE(Timedetail) as FIRSTCONN
, count(Timedetail) as FIRSTOccurances
, EVENTS
FROM MyDatabase
WHERE EVENTS = "FIRST" GROUP BY FIRSTCONN
<!--- LIMIT 0,10 --->;
</cfquery>
<cfdump var="#master2#">
<cfquery dbtype="query" name="detail2">
SELECT *
FROM master2
WHERE FIRSTCONN >= <cfqueryparam value="#startdate#" cfsqltype="cf_sql_date">
AND FIRSTCONN < <cfqueryparam value="#enddate#" cfsqltype="cf_sql_date">;
</cfquery>
Dumping Result: <cfdump var="#detail2#"><cfabort>
However, when I try to use the following check on the QoQ:
Dumping Result: <cfdump var="#detail2.FIRSTCONN#"><cfabort>
I don't see the full list of FIRSTCONN values. Instead I just see one line:
Dumping Result: {ts '2013-06-29 00:00:00'}
Ideally I should see the list of all the FIRSTCONN in my browser, shouldn't I?
You are looking at the default behaviour of coldfusion. When you output or dump queryname.fieldname, and don't specify a row number, you get the value from the first row. If you want to see all the rows, your choices are:
Look at the value list
Output/dump the entire query
Do another q of q for just that column and cfdump it.
Use cfoutput with a query attribute and just output that field
If you are looking to produce the same structured output that cfdump produces when dumping a query, I have two suggestions:
My First Inclination:
<cfdump var="#ListToArray(ValueList(queryName.columnName))#" />
That one is obviously a, very, minor continuation on Dan's suggestion.
The second is available for CF 8+ and it is
Exactly What You Wanted:
<cfdump var="#queryName#" show="columnName"/>
You may specify either columns to display in the output via the show attributes or you can hide specific columns by assigning a value to the hide attribute.
CFAbort in CF Docs
Granted, this post is almost 18 months old but maybe this will help someone that stumbles onto this page.
This is a little off topic, but I'd like to point out that in my instance of CF2016 the cfdump function suppresses the output of columns (and makes them appear empty) that have lots of text in them (or have the option to have lots of text). I'm not sure if it's the nVarChar(max) setting of the table field or what, but in order to see the content of these big fields, I actually have to make a separate query that selects only this one field, and use a separate cfdump in order to see its contents. This is only for debugging purposes, but it will keep you from going crazy and rewriting your update and insert statements over and over (because they appear to not be working all the way)...

CF QoQ is throwing runtime error. "Column reference is not a column in any of the tables of the FROM table list."

In my code, I first create the Query Object:
<cfset memberData = QueryNew('slug,pos,firstname,lastname,email') />
<cfset temp = QueryAddRow(memberData, #numMembers#) />
<!--- LOOP POPULATES QUERY OBJECT --->
<cfloop...</cfloop>
I can then verify that it has been populated by running the following (which outputs as expected):
<cfoutput query="memberData">
#slug# - #pos#<br>
</cfoutput>
I then try to query the memberData Query Object and all hell breaks loose. If I run:
<cfquery name="members" dbtype="query">
SELECT slug,pos,firstname,lastname
FROM memberData
WHERE slug = #slug#
</cfquery>
I get this error:
Query Of Queries runtime error.
The select column reference [university] is not a column in any of the tables of the FROM table list.
In the output test mentioned above, I can verify that "university" is one of the values in the slug column. Clearly I'm missing something in my approach, but I'm baffled as to what it might be. Any help would be greatly appreciated!
Query Of Queries runtime error.
The select column reference
[university] is not a column in any of the tables of the FROM table
list
Your error was caused by absence of quotes in where clause and nothing else:
This expression find rows where the value in slug column equals the value in CF slug variable (String):
WHERE slug = '#slug#'
On the other hand this expression means find rows where value in the slug column equals the value contained in the column named in the CF slug variable (String):
WHERE slug = #slug#
The most likely cause of why you needed to change to SELECT * is CF query caching. So changing it back now should solve the problem. And always use <cfqueryparam .../> as suggested by "Al Everett"
Well, it's not quite answering the question asked, but it's close enough for what I needed:
<cfquery name="members" dbtype="query">
SELECT *
FROM memberData
WHERE slug = '#slug#'
</cfquery>
I had tried the wrapping #slug# in single quotes prior to posting with no success, but doing that plus changing the query to SELECT * fixed the issue. For my content, * only adds one more value retrieved, so not really a problem in slowing down the process.

Is there a way to escape and use ColdFusion query reserved words as column names in a query of query?

I'm working with a query that has a column named "Date."
The original query returns okay from the database. You can output the original query, paginate the original query, get a ValueList of the Date column, etc.
Query of Query
<cfquery name= "Query" dbtype= "query">
select
[Query].[Date]
from [Query]
</cfquery>
Response from ColdFusion
Query Of Queries syntax error. Encountered "Date. Incorrect Select
List,
Typically, I use descriptive names so I haven't run across this issue previously.
In this case, I'm working with a stored procedure that someone else wrote. I ended up modifying the stored procedure to use a more descriptive column name.
I have a service I use for transforming, searching and sorting queries with ColdFusion. I'm curious to know the answer to my original question, so that I can modify my service to either throw a better error or handle reserved words.
Is there a way to escape and use ColdFusion query reserved words as column names in a query of query?
The following code works fine for me:
<cfset query = queryNew("date")>
<cfdump var="#query#">
<cfquery name= "Query" dbtype= "query">
select
[Query].[Date]
from [Query]
</cfquery>
<cfdump var="#query#">
In standard mysql you'd "escape" the fields by using the ` character.
So for example:
select `query`.`date` from `query`
Try that and see if it works?

Combining query rows in a loop

I have the following ColdFusion 9 code:
<cfloop from="1" to="#arrayLen(tagArray)#" index="i">
<cfquery name="qryGetSPFAQs" datasource="#application.datasource#">
EXEC searchFAQ '#tagArray[i]#'
</cfquery>
</cfloop>
The EXEC executes a stored procedure on the database server, which returns rows of data, depending on what the parameter is. What I am trying to do is combine the queries into one query object. In other words, if it loops 3 times and each loop returns 4 rows, I want a query object that has all 12 rows in one object. How do I acheive this?
You might want to take a different approach (modify your stored procedure to accept multiple arguments or use a list and fnSplit) and return the dataset all at once. However, to directly answer your question, this is how you could combine the queries as you're asking to:
You can use UNION in a Query of Queries to combine all of the datasets.
<cfloop from="1" to="#arrayLen(tagArray)#" index="i">
<cfquery name="qryGetSPFAQs#i#" datasource="#application.datasource#">
EXEC searchFAQ '#tagArray[i]#'
</cfquery>
</cfloop>
<cfquery name="combined" dbtype="query">
<cfloop from="1" to="#arrayLen(tagArray)#" index="i">
select * from qryGetSPFAQs#i#
<cfif i lt arrayLen(tagArray)>UNION</cfif>
</cfloop>
</cfquery>
A more direct way might be something like this:
<cfset bigQ = queryNew("column")>
<cfloop from="1" to="#arrayLen(tagArray)#" index="i">
<cfquery name="qryGetSPFAQs" datasource="#application.datasource#">
EXEC searchFAQ '#tagArray[i]#'
</cfquery>
<cfset queryAddRow(bigQ)>
<cfset querySetCell(bigQ, "column". qryGetSPFAQs)>
</cfloop>
You will need a querySetCell() assignment for each column. Check out the query functions in the live docs for more information.
Here is an out of the box solution, abandoning the StoredProc for a SQL View (I'll explain).
Disclaimer: without seeing the SP source code, I can't tell if my solution fits. I'm assuming that the SP is fairly basic, and I admit I usually prefer the compiled execution of an SP over a view, but the one-time execution of a SQL View should outperform the looping of the SP x times.
First make a view that looks like the SELECT statement in the SP (minus the parameterization, of course -- you'll cover that in a WHERE clause within the CFQUERY of your new view.
Second, set up your loop to do no more than build a data set we're going to use for the WHERE clause. You'll need to use ArrayToList and a little bit of string manipulation to tidy it up, with the end product being a string stored in a single CF variable looking like this:
('ValueOfArrayElement1','ValueOfArrayElement2','Value_And_So_On')
Building the string is pretty easy, using the delimeter attribute of ArrayToList, and after the loop is complete, append a Left Parenthesis & Single Quote to the Left most position of the string; and append a Single Quote & Right Parenthesis to the Right most position in the string.
Now, write the CFQUERY statement to SELECT the columns you need from your view (instead of executing your SP). And instead of passing a parameter to the SP, you're going to put a WHERE clause in the CFQUERY.
Oh, BTW, I am stating you need a SQL View, but the entire SELECT could be built in CFQUERY. Personally, when I have a multi-table JOIN, I like to define that in a SQL View where it's executed more quickly than a JOIN in CFQUERY. Ultimately a StoredProc is even faster, but our WHERE clause is much friendlier to code and read like this than it would be to send into StoredProc without looping in and out of SQL.
It's a good goal to make only one trip out to the database and back if possible. That's why we looped through the array to write a string equating to all the values in the dataset. This way, we'll only execute one query, one time.
SELECT Col1, Col2, Col_etc
FROM SQL_View_Name
WHERE ColumnName in #BigStringWeMadeFromArrayToList#
when our CFQUERY is rendered, the clause will look just like this in SQL:
WHERE ColumnName in
('ValueOfArrayElement1','ValueOfArrayElement2','Value_And_So_On')
So there you have it. Like I said, this is nice because it makes only one trip to the DB, and since we are building a view, the performance will still be pretty good -- better than running a StoredProc 4+ times. (no offense)
I'll must repeat... without having seen the SP code, I'm not sure if this is do-able. Plus, it's kind of odd to abandon a StoredProc for a SQL View, a "lesser" entity in the RDBMS, but I'm sure we will achieve greater performance and I think it's pretty readable, too.