CFDump of query column does not display all values - coldfusion

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)...

Related

Stripping CGI.HTTP_REFERER and CGI.SCRIPT_NAME in Coldfusion

I have the block of code below which runs a query and checks for an existing record and runs a second insert query if no record is found.
<cffunction name="EndRequestFunc" access="public" returnType="string">
<!---Queries Table To Get Requested Record--->
<cfquery name="qryGetPageRecord" datasource="First_Main_Dev"
dbname="First_Services_Dev">
SELECT pageName
FROM tblCFMPageRequest
WHERE pageName = '#CGI.HTTP_REFERER#' AND scriptName =
'#CGI.SCRIPT_NAME#'
</cfquery>
<!---Conditional Check for record count equal to 0--->
<cfif qryGetPageRecord.recordCount eq 0>
<!---If record count equal to 0, recordset query executed--->
<cfquery name="setNewRecord" datasource="First_Main_Dev"
dbname="First_Services_Dev">
INSERT INTO tblCFMPageRequest
VALUES ('#CGI.HTTP_REFERER#', '#CGI.SCRIPT_NAME#')
</cfquery>
</cfif>
</cffunction>
What I need to do is strip the values of the two CGI variables of all formatting so that a value like this "example.com/portal/mypage.cfm" will be stripped of http and everything else down everything to just mypage.cfm before its inserted by the query. Any guidance would be appreciated.
Update: Thank to the advice given, I was able to eliminate the http://example.com/ portion of the URL using the ListLast function.
I was short sighted in not remembering my urls have characters that need to be eliminated after the "cfm" point. Here is one of my actual results from ListLast: client_modify.cfm?uid=248&al=1&a_trigger=1.
I've tried using some other List functions in Coldfusion to no avail as of yet. Any advice on how to eliminate the bold portion of:
client_modify.cfm ?uid=248&al=1&a_trigger=1 so I'm just left with a clean client_modify.cfm
Use ListLast() function with / as a delimiter. Also, always try to use cfqueryparam to put values in queries. Like this.
<cfquery name="setNewRecord" datasource="First_Main_Dev" bname="First_Services_Dev">
INSERT INTO tblCFMPageRequest
VALUES (<cfqueryparam cfsqltype="cf_sql_varchar" value="#ListLast(CGI.HTTP_REFERER,'/')#">, <cfqueryparam cfsqltype="cf_sql_varchar" value="#ListLast(CGI.SCRIPT_NAME,'/')#">)
</cfquery>
CGI variables shouldn't have any "formatting", so your question is a bit confusing.
If you're just looking to get the filename at the end of the string, you can use the list functions.
fileIwant = ListLast(CGI.SCRIPT_NAME,"/");
If CGI.SCRIPT_NAME is /wwwroot/example/index.cfm, fileIwant will result in index.cfm.
Have a care with the referrer, as it may not be defined and parsing it out will throw an error.

ColdFusion 11 DateFormat

I am moving one of our applications from ColdFusion 9.01 to ColdFusion 11 and encountered a situation where I cannot get the date formatted the way I want it using "DateFormat". I read through the docs since things have changed in CF versions, but I honestly can't figure out why this isn't working. It worked beautifully in CF 9. I know it's probably something very easy, but I am just not seeing it.
The query (Oracle DB) provides me a list of the last 30 days and the loop is simply to reformat the date output from "2014-07-01 00:00:00.0" to a more friendly looking display of 01-Jul-2014 except that I cannot get it to format as "dd-mmm-yyyy" it just spits back the original output from the query. I hard coded the date where normally there would be a cfquerparam. Any ideas?
<cfquery name="qryDateArray" datasource="#request.db#">
select trunc(to_date('07/01/2014', 'mm/dd/yyyy') + 1 - rownum) as ref_date
from dual connect by rownum <= 30
</cfquery>
<cfloop from="1" to="#qryDateArray.recordcount#" index="j">
<cfset qryDateArray.ref_date[j] = DateFormat(qryDateArray.ref_date[j], "dd-mmm-yyyy")>
</cfloop>
<cfoutput>
<cfdump var="#qryDateArray#">
</cfoutput>
I could not test this on CF11 since I do not have it handy. I did verify that your code though returns results as you explained when I ran it on my CF10 environment here. So what you can do is add a column to the query object and define it as a varchar and add your formatted data to that. This in turn dumped out the formatted dates.
<cfquery name="qryDateArray" datasource="#request.db#">
select trunc(to_date('07/01/2014', 'mm/dd/yyyy') + 1 - rownum) as ref_date
from dual connect by rownum <= 30
</cfquery>
<cfset aryData = [] />
<cfloop from="1" to="#qryDateArray.recordcount#" index="j">
<cfset ArrayAppend(aryData, DateFormat(qryDateArray.ref_date[j], "dd-mmm-yyyy")) />
</cfloop>
<cfset QueryAddColumn(qryDateArray, "STRDATE", "VarChar", aryData) />
<cfoutput>
<cfdump var="#qryDateArray#">
</cfoutput>
If dependent on the query column names then could use something like Ben's method explained here to do some renaming of the columns: http://www.bennadel.com/blog/357-ask-ben-changing-coldfusion-query-column-names.htm
It'd be great if you'd given us a portable test case rather than one that relies on your database, but I suspect it is because ColdFusion has become more rigid with its type management of query columns.
So CF considers your ref_date column to be of type date, so when you try to put the formatted string back into the query column, CF tries (and succeeds) to convert the string back into a date.
Aside:
I have to wonder why you don't format the data string in the DB from the outset, and just return it the way you need it, rather than returning something else, then looping over the thing to adjust it..?

Handling CFSELECT

I'm totally unused to Cold Fusion, I'd like to know how to handle a multiple CFSELECT, in particular how to know how many rows I've selected and taking them one by one.
Actually I've managed to see all the rows togheter:
<!--- page_a.cfm --->
<cfform name="fooform" ........>
<cfselect query="myquery" name="fornitori" multiple="yes"></cfselect>
<!--- page_b.cfm --->
<cfoutput>#form.fornitori#</cfoutput>
And, if it's not too much, I'd like to know why it's not correct to write:
<!--- page_b.cfm --->
<cfoutput>#fooform.fornitori#</cfoutput>
Since it is a multiple selection list, the options you select will be submitted to page_b.cfm as a comma delimited list. This means you can use list functions to calculate the total items selected and cfloop to iterate through the selections individually. Note, when using "multiple" select lists, if you select nothing the form field will not exist.
<cfparam name="form.fornitori" default="">
<cfoutput>
Total Items Selected = <cfoutput>#listLen(form.fornitori)#</cfoutput>
Individual Selections:<br>
<cfloop list="#form.fornitori#" index="theSelection">
#theSelection#<br>
</cfloop>
</cfoutput>
why it's not correct to write ..
Because FORM refers to a special system structure, not the name of your html form (ie fooform). FORM contains any form fields submitted via method=POST.
#myquery.recordcount#
btw, use cfdump to display anything. you see some really interesting stuff (I'm not sure whether recordcount is in there though)
getting to the elements:
<cfoutput query="queryname">#title#<br />#content#</cfoutput>
inside the cfoutput you have access to the variables of an element.
coldfusion 9 help

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.

Session Variables, welcome messages

Why does this not work? My welcome message, it just doesn't show up:
<p>Welcome <cfoutput>#Recordset1.UserID#</cfoutput>.</p>
The session variable on the login page I created is:
<cflock timeout=999 scope="Session" type="Exclusive">
<cfset Session.IDUsers =''>
</cflock>
is this incorrect? On the index page where I'm trying to display my welcome message I have:
<cfquery name="Recordset1" datasource="cfGossip">
SELECT *
FROM users
WHERE users.IDUsers = <cfqueryparam value="#Session.IDUsers#">
</cfquery>
I'm not sure if this works, or is necessary?
If you set the userid stored in the session to be the empty string, when you query on it, you will only get users for whom the id is the empty string, which shouldn't be any of them. Therefore, the query is returning an empty set, and your page is (correctly) not displaying a user id.
How are you initially identifying the user? Are you querying against a database when they log in? Are you storing a cookie? Reading Tarot cards? For this to work, at some point, you have to store the correct userid, probably in the session. To do that, you need to first identify who the user is.
Also, if you are using CF6+, you probably do not need the cflock. It is now used to prevent race conditions, as CF is now thread-safe.
Looks like you're just starting with CF, welcome to the community.
My understanding of your code makes the structure look like the following, if I'm understanding you correctly:
<cfset session.idUsers = '' />
<cfquery datasource = "cfgossip" name = "recordset1">
SELECT * FROM USERS WHERE USERS.ID_USERS = <cfqueryparam cfsqltype = "cf_sql_integer" value = "#session.idUsers# />
</cfquery>
<cfoutput>Welcome #recordset1.userID#</cfoutput>
The reason this doesn't work is because your session.idUsers value is blank. Assuming you have a user in your database with an ID_USERS value of 1, you could change the CFSET to look like and it should return results.
Additionally, while it's great to see you using CFQUERYPARAM, I'd recommend including a CFSQLTYPE attribute in the tag whenever possible to provide an added line of defense against injection attacks. You can check out http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=Tags_p-q_18.html to see the list of available types.
Is there anywhere in your code where you set your session.IDUsers? You initialize it as a blank ''. Coldfusion does not populate it for you. The session scope is a place that will remember things for that user that you put there for a specified period of time inactivity, usually 20 minutes. So hopefully, somewhere before you run your query you have additional logic that fills that in, otherwise you are asking the database for a user named, ''.
This is just a point of style, but the following may work better for you:
<cfset Session.IDUsers =''>
<!--- Do something here to populate Session.IDUsers --->
<!--- Creates a blank query - not necessary, but can reduce errors later --->
<cfset Recordset1 = queryNew("UserID")>
<!--- Populate the query from the database --->
<cfquery name="Recordset1" datasource="cfGossip">
SELECT *
FROM users
WHERE users.IDUsers = <cfqueryparam value="#Session.IDUsers#">
</cfquery>
<!--- If the query has data, use it, otherwise show generic message --->
<cfoutput>
<cfif Recordset1.recordcount>
<p>Welcome #Recordset1.UserID#.</p>
<cfelse>
<p>Welcome new user!</p>
</cfif>
</cfoutput>
<!--- OR since we used queryNew("userID"), we can simplify without throwing an error. ---->
<cfoutput>
<p>Welcome <cfif len(Recordset1.userID)>#Recordset1.userID#.<cfelse>new user!</cfif></p>
</cfoutput>
Putting the cfoutput outside the paragraph block will make it easier if you have additional variables to insert into the text. (but will work either way)
Regardless of all that, unless you forgot to share a bit more of the code, I think the issue is that the session.IDUsers is blank and needs to be populated before the query. I hope this helps!