Displaying results from Pivot query in ColdFusion - coldfusion

I have two tables like this:
BloodTest
testid, testname
Sample
sampleid, testid, testresult, testdate
My query using a Pivot is:
SELECT * FROM (SELECT testdate, testname, testresult
FROM BloodTest
NATURAL JOIN Sample
PIVOT (MAX(testresult) FOR testname IN ('Na', 'K')));
This produces the correct output like:
testdate 'Na' 'K'
2015-01-01 140 4.1
2015-01-02 137 3.8
I can't figure out how to display this in ColdFusion though - I get results saying that testresult is undefined. I'm also not sure how to get the testresults to display horizontally in the CF table.
Here is the CF code:
<cfquery name="get_records"
datasource="#Request.DSN#" username="#Request.usrname#" password="#Request.pwd#">
SELECT * FROM (SELECT testdate, testname, testresult FROM BloodTest NATURAL JOIN Sample) PIVOT (MAX(testresult) FOR testname IN ('Na', 'K'))
</cfquery>
<table>
<tr>
<th>Date</th>
<th>Na</th>
<th>K</th>
</tr>
<cfoutput query="get_records">
<tr>
<td>#testdate#</td>
<td>#testresult#</td>
<td><!-- how to get 2nd testresult here --></td>
</tr>
</cfoutput>
The error I get is:
Variable TESTRESULT is undefined.
The error occurred in /data/coldfusion11/cfusion/wwwroot/blood.cfm: line 37
35 : <tr>
36 : <td>#testdate#</td>
37 : <td>#testresult#</td>
38 : </tr>
39 : </cfoutput>

Ironically, this morning I showed the following technique to a co-worker who is learning CF.
<cfquery name="pivotQueryData">
sql goes here
</cfquery>
Now we'll output this to an html table.
<cfoutput>
<table>
<tr>
<cfloop array="#pivotQueryData.getcolumnlist()#" index="header">
<th>#Header#</th>
</cfloop>
</tr>
<cfloop query="pivotQueryData">
<tr>
<cfloop array="#pivotQueryData.getcolumnlist()#" index="field">
<td>#pivotQueryData[field][currentrow]#</td>
</cfloop>
</tr>
</cfloop>
</table>
</cfoutput>

Related

CF SQL Creating a Table with different results

I am trying to create a table using coldfusion and sql. The table I am trying to create looks like this:
<cfquery datasource="#application.dsn#" name="someprocessTable">
SELECT *
FROM checklists
</cfquery>
<table id="Checklist_Stats">
<thead>
<th><b>Associate Name</b></th>
<th><b>Location</b></th>
<th><b>Checklists Generated by Associate</b></th>
<th><b>Checklists Generated by Selected Location(s)</b></th>
<th><b>Associate Percentage of Location Total</b></th>
</thead>
<tbody>
<cfoutput query="someprocessTable">
<tr>
<td>#associate#</td>
<td>#location_code#</td>
<td>#associate.recordcount#</td>
<!---<td>##</td>
<td>##</td>--->
</tr>
</cfoutput>
</tbody>
</table>
The part I am unsure about is how do I loop all of this information under one table? Because you would not want to have the same persons name keep reoccurring on the table and then how do you show how many was generated by them since I could not do something like #associate.recordcount#
There seems more than one way to do what you want to achieve like doing a query with joins and groups then dump in table; manage your output with a single CFoutput or use nested CFOutput and/or CFloop.
Following show third approach:
<table border="1" id="Checklist_Stats">
<thead>
<th><b>Associate Name</b></th>
<th><b>Location</b></th>
<th><b>Checklists Generated by Associate</b></th>
<th><b>Checklists Generated by Selected Location(s)</b></th>
<th><b>Associate Percentage of Location Total</b></th>
</thead>
<tbody>
<cfquery name="allAssociatesQry" dbtype="query">
SELECT DISTINCT associate, COUNT(*) AS associateCount FROM someprocessTable GROUP BY associate ORDER BY associate
</cfquery>
<cfloop query="allAssociatesQry">
<cfquery name="allLocCodeForAssociateQry" dbtype="query">
SELECT * FROM someprocessTable WHERE associate='#associate#' ORDER BY location_code
</cfquery>
<tr><td><cfoutput>#allLocCodeForAssociateQry.associate#</cfoutput></td>
<cfoutput query="allLocCodeForAssociateQry" group="location_code">
<cfset locCntr = 0 />
<cfoutput>
<cfset locCntr = locCntr + 1 />
</cfoutput>
<cfif allLocCodeForAssociateQry.currentRow NEQ 1>
<tr><td> </td>
</cfif>
<td>#allLocCodeForAssociateQry.location_code#</td>
<td>#allAssociatesQry.associateCount#</td>
<td>#locCntr#</td>
<td>#Round((locCntr/allAssociatesQry.associateCount) * 100)#%</td>
</tr>
</cfoutput>
</cfloop>
</tbody>
</table>
Please note that CF QoQ is case sensitive so if need be then convert associate name and location to lower/upper/title case before hand
A slightly modified code for the CFloop may be like below:
<cfloop query="allAssociatesQry">
<cfset thisAssociateName = trim(allAssociatesQry.associate) />
<cfquery name="allLocCodeForAssociateQry" dbtype="query">
SELECT location_code,count(location_code) AS locCntr FROM someprocessTable WHERE associate='#thisAssociateName#' GROUP BY location_code ORDER BY location_code
</cfquery>
<cfoutput query="allLocCodeForAssociateQry">
<tr>
<td>#thisAssociateName#</td>
<td>#allLocCodeForAssociateQry.location_code#</td>
<td>#allAssociatesQry.associateCount#</td>
<td>#allLocCodeForAssociateQry.locCntr#</td>
<td>#Round((allLocCodeForAssociateQry.locCntr/allAssociatesQry.associateCount) * 100)#%</td>
</tr>
<cfset thisAssociateName = "" />
</cfoutput>
</cfloop>

How can I leave the loop if no records are part of the if statement?

Below code works, but I would like to show 'no records' message if
<cfif GetResults2.csedept_id eq aFieldValue> has no records for that value. I have tried to put a counter on, but I just can't get it to show 'no records' and not show the
<thead> <th>Name</th> <th>Positive Comment</th> <th>Negative Comment</th></thead> heading of the table if there are no records.
How can I show "No Records" and hide the table head if the results come back empty
Right now if the result comes back empty it will say "no results"(correct) and display the header(incorrect).
<cfset counter3= 0>
<table cellpadding="0" cellspacing="0" class="tablecolors">
<h2> Comments </h2>
<thead> <th>Name</th> <th>Positive Comment</th> <th>Negative Comment</th></thead>
<cfloop query="GetResults2">
<cfif GetResults2.csedept_id eq aFieldValue>
<tr>
<td nowrap="nowrap">#emp_namefirst# #Left(emp_namelast, 1)# </td>
<td>#Replace(commentpositive, emp_namefirst, "<B>" & emp_namefirst & "</B>")#</td>
<td>#Replace(commentnegative, emp_namefirst, "<B>" & emp_namefirst & "</B>")#</td>
</tr>
<cfelse><p>no records</p>
</cfif>
</cfloop>
</table>
UPDATE: Just to add I do have another query above like #FRANK said that does pretty much the same things for example:
'<cfloop query="GetEmployeeTotals3">
<cfif GetEmployeeTotals3.csedept_id eq aFieldValue> '
here is the query:
select GetResults.* , GetEmployees.emp_namefirst, GetEmployees.emp_namelast
from GetResults, GetEmployees
where employee = emp_id
order by csedept_id
so all the solutions above that I tried won't work.
I would recommend using a query of queries to whittle the result set down to just the values you care about first. Then you can easily check, the recordcount before outputting the table at all.
Alternatively, loop first and build up the results with cfsavecontent, then check to see if you found any prior to getting to the table bits.
Something like this should work. You'll have to set a flag of showRecords that will determine if you should show the headers.
<cfset showRecords = false>
<cfloop query="GetResults2">
<cfif GetResults2.csedept_id eq aFieldValue>
<cfset showRecords = true>
<cfbreak>
</cfif>
</cfloop>
<h2> Comments </h2>
<cfif showRecords>
<table cellpadding="0" cellspacing="0" class="tablecolors">
<thead> <th>Name</th> <th>Positive Comment</th> <th>Negative Comment</th></thead>
<cfloop query="GetResults2">
<cfif GetResults2.csedept_id eq aFieldValue>
<tr>
<td nowrap="nowrap">#emp_namefirst# #Left(emp_namelast, 1)# </td>
<td>#Replace(commentpositive, emp_namefirst, "<B>" & emp_namefirst & "</B>")# </td>
<td>#Replace(commentnegative, emp_namefirst, "<B>" & emp_namefirst & "</B>")#</td>
</tr>
</cfif>
</cfloop>
</table>
<cfelse>
<p>no records</p>
</cfif>
EDIT: Updated answer after question was clarified
You'll need to move your cfif to include your table head when checking for records. If the check comes back with a record count, then output the table head as well as the results, otherwise output "no results". I've written two versions below, one is utilizing the cfoutput instead of a loop (just personal preference) and one with your loop if you wish to keep it.
I added Dan's listfind() valuelist() combo...so give him credit for that.
Edit Edit so this is the super-strength/ultra-correct awesome solution with the 'I-am-tired-of-editing-this-answer-50-times-to-get-OP-an-answer', with bonus shameless theft from Dan's answer above/below. Or where ever we ending up order-wise.
<table>
<cfif getresults2.recordcount AND ListFind(ValueList(GetResults2.csedept_id), aFieldValue)>
<tr>
<th>name</th>
<th>positive comment</th>
<th>negative comment</th>
</tr>
<cfoutput query="getresults2">
<tr>
<td nowrap="nowrap">#emp_namefirst# #left(emp_namelast, 1)# </td>
<td>#replace(commentpositive, emp_namefirst, "<b>" & emp_namefirst & "</b>")#</td>
<td>#replace(commentnegative, emp_namefirst, "<b>" & emp_namefirst & "</b>")#</td>
</tr>
</cfoutput>
<cfelse>
<tr colspan="3">
<td><p>no records</p></td>
</tr>
</cfif>
</table>
If you have your cfoutput somewhere in your code (where we cannot see), then here is your cfloop back, simply replace this where I have the cfoutput in the snippet above.
<cfloop query="getresults2">
<tr>
<td nowrap="nowrap">#emp_namefirst# #left(emp_namelast, 1)# </td>
<td>#replace(commentpositive, emp_namefirst, "<b>" & emp_namefirst & "</b>")#</td>
<td>#replace(commentnegative, emp_namefirst, "<b>" & emp_namefirst & "</b>")#</td>
</tr>
</cfloop>
While your question is still unclear, this might be what you want.
<cfif ListFind(ValueList(GetResults2.csedept_id), aFieldValue)>
your existing code to display results in a table
<cfelse>
<p>No Records Found</p>
Note that this:
ListFind(ValueList(GetResults2.csedept_id), aFieldValue)
will execute and return false even if GetResults2 has no records at all.
Edit starts here
Based on this comment, "well if it only appears on some then display does but to those who do not match then ignore" change your existing code to something like:
<cfquery name = "q3" dbtype = "query">
select * from GetResults2
where csedept_id = #aFieldValue#
<cfquery>
<table>
column header row
<cfoutput query="q3">
data rows
</cfoutput>
<table>
The initial construct at the start of this answer still applies.

ColdFusion cfoutput query group

Please refer to this page:
http://allblacks.01dev.co.nz/templates/super14/textobjects/SRMatchDayList.cfm
Query dump is included there. I've inherited this code and would prefer to work with it if possible.
The following code outputs fixtures by week.
<table cellspacing="0" cellpadding="0" border="0" align="center" width="530">
<tr bgcolor="#797979">
<th align="left"><p> <b>Date</b></p></td>
<th align="left"><p><b>Game</b></p></td>
<th align="left"><p><b>Venue</b></p></td>
<th align="left"><p><b>Time (NZ)</b></p></td>
<th align="center"><p><b>Result</b> </p></td>
</tr>
<cfset iWeekCounter = 0>
<cfif not attributes.useSegmentTitle and attributes.sortDirection is "desc">
<cfset qSegments = oSeries.getSegmentInfo(seriesID=attributes.seriesID)>
<cfset iWeekCounter = qSegments.recordcount + 1>
</cfif>
<cfoutput query="qSeriesEvents" group="segmentID">
<cfif attributes.sortDirection is "desc">
<cfset iWeekCounter = iWeekCounter-1>
<cfelse>
<cfset iWeekCounter = iWeekCounter+1>
</cfif>
<tr>
<td colspan="5"><p><br><strong>
<cfif attributes.useSegmentTitle>
#qSeriesEvents.segment#
<cfelse>
Week #iWeekCounter#
</cfif>
</strong></p></td>
</tr>
<cfoutput>
<cfif textObjectCount gt 0>
<tr>
<td><p> #DateFormat(eventDateTime, "dd mmm")#</p></td>
<td><p>#event#</p></td>
<td><p>#location#</p></td>
<td><p><cfif showTimeField is 1>#lcase(timeFormat(dateadd('h',iTimeOffset,eventDateTime),"h:mm tt"))#</cfif></p></td>
<td align="center" valign="top"><p><cfif isDate(eventDateTime) AND dateDiff("n",eventDateTime, now())>#oEvent.getTeamResult(eventID, homeTeamID)#-#oEvent.getTeamResult(eventID, awayTeamID)#</cfif> </p></td>
</tr>
<tr><td colspan="5"><div style="height:1px; padding:0px; margin0px; font-size:0; border-bottom: 1px solid ##999"></div></td></tr>
</cfif>
</cfoutput>
</cfoutput>
</table>
However, note weeks 3 - 18 in the above URL, which don't have any data. I don't want to display week lines if there is no data. How can I accomplish this using this query output "group=" setup if possible?
SQL from the website
SELECT tObj.textObjectCount, events.*, venues.venue, venues.location, DATENAME(wk, events.eventDateTime - 1) AS EventWeek, s.segment
FROM events join segments s on s.segmentID = events.segmentID
LEFT OUTER JOIN (
SELECT LUTextObjectEvent.eventID, COUNT(*) AS textObjectCount
FROM LUTextObjectEvent
INNER JOIN textObjects ON LUTextObjectEvent.textObjectID = textObjects.textObjectID
GROUP BY LUTextObjectEvent.eventID
) tObj
ON events.eventID = tObj.eventID
LEFT OUTER JOIN venues ON events.venueID = venues.venueID
WHERE (events.eventID IN (
SELECT eventID
FROM events
WHERE segmentID IN (
SELECT segmentID
FROM segments
WHERE seriesID IN (?))
)
)
ORDER BY s.segmentID asc
You're using a LEFT OUTER JOIN which means you'll have one record for every event/segment. Change those to inner joins and you should have your desired results
SELECT tObj.textObjectCount, events.*, venues.venue, venues.location, DATENAME(wk, events.eventDateTime - 1) AS EventWeek, s.segment
FROM events join segments s on s.segmentID = events.segmentID
INNER JOIN (
SELECT LUTextObjectEvent.eventID, COUNT(*) AS textObjectCount
FROM LUTextObjectEvent
INNER JOIN textObjects ON LUTextObjectEvent.textObjectID = textObjects.textObjectID
GROUP BY LUTextObjectEvent.eventID
) tObj
ON events.eventID = tObj.eventID
INNER JOIN JOIN venues ON events.venueID = venues.venueID
WHERE (events.eventID IN (
SELECT eventID
FROM events
WHERE segmentID IN (
SELECT segmentID
FROM segments
WHERE seriesID IN (?))))
ORDER BY s.segmentID asc

how to loop through Query Columns in ColdFusion

I have a query in a my CFC. The function contains a simple query as such.
<cfquery name="qrySE" datasource=#mydatasource#>
SELECT
NAMES,SALARY
FROM tblTest
</cfquery>
I want to display my resultset as such (horizontally):
NAME1 NAME2 NAME3 NAME4
10 20 45 62
Is there a way to loop through the columns of my query and create a virtual query for this purpose?
If anyone has done this, please let me know.
Just wanted to add Al Everett's solution returns the columns back in alphabetical order. If you would like to get the column names back in the same order as the query you can use:
ArrayToList( qrySE.getColumnNames() )
which I found here: http://www.richarddavies.us/archives/2009/07/cf_columnlist.php
you can use this to create a function to output queries to a table like this:
<cffunction name="displayQueryAsTable" output="true">
<cfargument name="rawQueryObject" type="query" required="true">
<table >
<tr>
<cfloop list="#ArrayToList(rawQueryObject.getColumnNames())#" index="col" >
<th>#col#</th>
</cfloop>
</tr>
<cfloop query="rawQueryObject">
<tr>
<cfloop list="#ArrayToList(rawQueryObject.getColumnNames())#" index="col">
<td>#rawQueryObject[col][currentrow]#</td>
</cfloop>
</tr>
</cfloop>
</table>
</cffunction>
You could use the built-in query.columnList that is returned with each query. (It's metadata of the query, like recordCount.)
You could do something like this:
<table>
<cfloop list="#qrySE.columnList#" index="col">
<tr>
<cfloop query="qrySE">
<td>#qrySE[col][currentRow]#</td>
</cfloop>
</tr>
</cfloop>
</table>
Not tested, but that should give you the idea.

cfloop empty query condition?

I have the following ColdFusion code that is getting information from a database and displaying the results on the homepage. Here's the cfquery code:
<cfquery name="getSchedule" datasource="#APPLICATION.datasource#" dbtype="odbc">
SELECT * FROM SCHEDULE_Days SD
LEFT JOIN SCHEDULE_ScheduledClasses SSC ON SD.day_id = SSC.day_id
LEFT JOIN SCHEDULE_Classes SC ON SSC.class_id = SC.class_id
WHERE SD.day_date = #createODBCDate(now())# AND SSC.schedule_cancelled = 0
ORDER BY SSC.start_time
</cfquery>
and the output code:
<cfoutput>
<cfloop query="getSchedule">
<tr>
<td width="40"> </td>
<td width="74">#lcase(timeFormat(start_time,"h:mm tt"))#</td>
<td width="158">#class_name#</td>
</tr>
</cfloop>
</cfoutput>
The issue is, if there is no data contained within getSchedule (i.e., there are no ScheduledClasses), it displays nothing.
I'm looking for a way to change this so that, in the event that there is no data to display, I can specify a message and code to be shown in its absence.
First just a quick CF tip you can make you code better by doing it this way:
<cfif getSchedule.recordcount GT 0>
<cfoutput query="getSchedule">
<tr>
<td width="40"> </td>
<td width="74">#lcase(timeFormat(getSchedule.start_time,"h:mm tt"))#</td>
<td width="158">#getSchedule.class_name#</td>
</tr>
</cfoutput>
<cfelse>
<p>Empty record message here</p>
</cfif>
The reason I put the query output first is most likely this will happen more than with your empty set message.
<cfif getSchedule.recordcount>
.... do something
</cfif>
Will work just aswell there is no need for gt 0
Use the recordCount to detect whether the query has any record
<cfif getSchedule.recordcount gt 0>
.... do something
</cfif>
<cfif getSchedule.RecordCount>
<table>
<cfoutput query="getSchedule">
<tr>
<td width="40"> </td>
<td width="74">#lcase(timeFormat(start_time,"h:mm tt"))#</td>
<td width="158">#class_name#</td>
</tr>
</cfoutput>
</table>
<cfelse>
<p>There are currently no records</p>
</cfif>