I am trying to calculate the total of a column using ColdFusion and MS Sql.
Will someone please tell me what I am overlooking? My total for the location total is not doing the sum of the column but for somereason just taking the last number in that column. Where am I going wrong?
<cfset result = {} />
<cftry>
<cfquery datasource="#application.dsn#" name="GetLocationInfo">
SELECT *
FROM cl_checklists
</cfquery>
<cfcatch type="any">
<cfset result.error = CFCATCH.message >
<cfset result.detail = CFCATCH.detail >
</cfcatch>
</cftry>
<table border="1" id="Checklist_Stats">
<thead>
<th><strong>Location</strong></th>
<th><strong>Percent of Total Checklists</strong></th>
<th><strong>Location Total</strong></th>
</thead>
<tbody>
<cfquery name="allLocCode" dbtype="query">
SELECT DISTINCT trans_location, COUNT(*) AS locationCount FROM GetLocationInfo GROUP BY trans_location ORDER BY trans_location
</cfquery>
<cfloop query="allLocCode">
<cfset thisLocationName = trim(allLocCode.trans_location) />
<cfquery name="allLocCodeForLocationQry" dbtype="query">
SELECT trans_location,count(trans_location) AS locCntr FROM GetLocationInfo WHERE trans_location='#thisLocationName#' GROUP BY trans_location ORDER BY trans_location
</cfquery>
<cfset columnSum = ArraySum(allLocCodeForLocationQry['locCntr'])>
<cfoutput query="allLocCodeForLocationQry">
<tr>
<td><strong>#thisLocationName#</strong></td>
<td>#NumberFormat((allLocCodeForLocationQry.locCntr/allLocCode.locationCount) * 100, '9.99')#%</td>
<td>#allLocCodeForLocationQry.locCntr#</td>
</tr>
</cfoutput>
</cfloop>
<tr>
<td><strong>Total</strong></td>
<td></td>
<td><cfoutput>#numberFormat(columnSum)#</cfoutput></td>
</tr>
</tbody>
<!--- Total of All Sum of each column --->
</table>
Your columnSum variable is inside your cfloop. Put the <cfset columnSum = ArraySum(allLocCodeForLocationQry['locCntr'])> line outside of the cfloop (either before or after), and you should get your grand total of 334.
Try this.
Each time you loop through the query, append a value (the count of locations) to a list.
Something like this:
<cfset myList = "">
<cfloop query="allLocCode">
<cfset myList = ListAppend(myList, locationCount, ',')>
<!---your other logic--->
</cfloop>
At the end of your loop you should have a list of numbers as long as your query's recordcount.
You can add up all those numbers using this old function I found on CFLib.
<cfscript>
function listSum(listStr)
{
var delim = ",";
if(ArrayLen(Arguments) GTE 2)
delim = Arguments[2];
return ArraySum(ListToArray(listStr, delim));
}
</cfscript>
So, for example, if your final list was called myList and had values such as 14, 100, 7 - you would write out:
<cfoutput>#listSum(myList)#</cfoutput>
And get your final answer of 121.
Since this is sql server, why not take advantage of its ability to use the with keyword? The general idea is this:
with totalRecords as
(select count(*) records
from etc),
groupedRecords as
(select someField, count(*) recordsForField
from etc
group by someField)
select whatevever
, (groupedRecords.recordsForField / totalRecords.records) * 100 percentage
from someTables
join groupedRecords on groupedRecords.someField = someTable.someField
where totalRecords.records > 0
Then you simply output your query results.
Related
How do you create something to notify a user if there are no matching records found with the queries you run?
I have a queries.cfm that I run like this:
<cfset result = {} />
<cftry>
<cfset date1 = CREATEODBCDATETIME(form.StartDate & '00:00:00')>
<cfset date2 = CREATEODBCDATETIME(form.EndDate & '23:59:59')>
<cfquery datasource="#application.dsn#" name="GetEmployeeInfo">
SELECT trans_location, date, associate
FROM cl_checklists
WHERE date >= <cfqueryparam value="#date1#" cfsqltype="cf_sql_timestamp" />
AND date <= <cfqueryparam value="#date2#" cfsqltype="cf_sql_timestamp" />
AND trans_location IN ( <cfqueryparam value="#FORM.location#" cfsqltype="cf_sql_varchar" list="true" /> )
AND associate IN ( <cfqueryparam value="#FORM.EmployeeName#" cfsqltype="cf_sql_varchar" list="true" /> )
</cfquery>
<cfquery datasource="#application.dsn#" name="GetLocationInfo">
SELECT trans_location, date, associate
FROM cl_checklists
WHERE date >= <cfqueryparam value="#date1#" cfsqltype="cf_sql_timestamp" />
AND date <= <cfqueryparam value="#date2#" cfsqltype="cf_sql_timestamp" />
AND trans_location IN ( <cfqueryparam value="#FORM.location#" cfsqltype="cf_sql_varchar" list="true" /> )
</cfquery>
<cffunction name="getop_id" access="public" returntype="string">
<cfargument name="associate" >
<cfquery name="spitOutop_id" datasource="#application.userinfo_dsn#">
SELECT assoc_name
FROM dbo.tco_associates
WHERE assoc_id= #arguments.associate#
</cfquery>
<cfreturn spitOutop_id.assoc_name >
</cffunction>
<cfquery name="allAssociatesQry" dbtype="query">
SELECT DISTINCT associate, COUNT(*) AS associateCount FROM GetEmployeeInfo GROUP BY associate ORDER BY associate
</cfquery>
<table border="1" id="Checklist_Stats">
<thead>
<th><strong>Associate Name</strong></th>
<th><strong>Location</strong></th>
<th><strong>Checklists Generated by Associate</strong></th>
<th><strong>Checklists Generated by Selected Location(s)</strong></th>
<th><strong>Associate Percentage of Location Total</strong></th>
</thead>
<tbody>
<!--- aggregate variables --->
<cfset aggrAssociateChecklist = 0>
<cfset aggrLocationChecklist = 0>
<cfloop query="allAssociatesQry">
<!--- get Associate's name --->
<cfset thisAssociateCode = trim(allAssociatesQry.associate)>
<cfset thisAssociateName = getop_id(thisAssociateCode) />
<!--- 1.1 get all trans_location code and total counts for the current Associate --->
<cfquery name="allLocCodeForAssociateQry" dbtype="query">
SELECT trans_location,count(trans_location) AS locCntr FROM GetEmployeeInfo WHERE associate='#thisAssociateCode#' GROUP BY trans_location ORDER BY trans_location
</cfquery>
<!--- 1.2 get the aggregate of checklist count generated by the current Associate for each location --->
<cfquery name="qTotalChecklistCountForAssociate" dbtype="query">
SELECT SUM(locCntr) AS totalAssocChecklist FROM allLocCodeForAssociateQry
</cfquery>
<!--- 2.1 get the total location checklist for each location available for the current Associate --->
<cfquery name="allLocChecklistForAssociateQry" dbtype="query">
SELECT trans_location,count(trans_location) AS totalLocCount FROM GetLocationInfo WHERE trans_location IN (#QuotedValueList(allLocCodeForAssociateQry.trans_location)#) GROUP BY trans_location ORDER BY trans_location
</cfquery>
<!--- 2.2 get the aggregate of location checklist generated by the current Associate --->
<cfquery name="qTotalLocChecklistForAssociate" dbtype="query">
SELECT SUM(totalLocCount) AS totalLocChecklist FROM allLocChecklistForAssociateQry
</cfquery>
<!--- display record for the current Associate --->
<cfoutput query="allLocCodeForAssociateQry">
<tr>
<!---<td><strong>#thisAssociateCode#</strong></td>--->
<td><strong>#thisAssociateName#</strong></td>
<td>#allLocCodeForAssociateQry.trans_location#</td>
<td>#allLocCodeForAssociateQry.locCntr#</td>
<td>#allLocChecklistForAssociateQry['totalLocCount'][CurrentRow]#</td>
<td>#NumberFormat((allLocCodeForAssociateQry.locCntr/allLocChecklistForAssociateQry['totalLocCount'][CurrentRow]) * 100, '9.99')#%</td>
</tr>
<cfset thisAssociateName = "" />
</cfoutput>
<!--- 3.1 get sub total for each Associate group --->
<cfset totalAssocChecklist = qTotalChecklistCountForAssociate.totalAssocChecklist>
<cfset totalLocChecklist = qTotalLocChecklistForAssociate.totalLocChecklist>
<!--- 3.2 add to the aggregate --->
<cfset aggrAssociateChecklist += totalAssocChecklist>
<cfset aggrLocationChecklist += totalLocChecklist>
<!--- display sub total for each Associate group --->
<cfoutput>
<tr>
<td>Associate Total</td>
<td></td>
<td>#totalAssocChecklist#</td>
<td>#totalLocChecklist#</td>
<td>#NumberFormat((totalAssocChecklist/totalLocChecklist) * 100, '9.99')#%</td>
</tr>
</cfoutput>
</cfloop>
<!--- display calculated aggregate at the end of the result --->
<!--- <cfoutput>
<tr>
<td><strong>Total</strong></td>
<td></td>
<td>#aggrAssociateChecklist#</td>
<td>#aggrLocationChecklist#</td>
<td>#NumberFormat((aggrAssociateChecklist/aggrLocationChecklist) * 100, '9.99')#%</td>
</tr>
</cfoutput>--->
</tbody>
</table>
<cfcatch type="any">
<cfset result.error = CFCATCH.message >
<cfset result.detail = CFCATCH.detail >
</cfcatch>
</cftry>
But I am trying to notify the user when no results come back based on there search.
I was trying to do a catch for the results if there 0 do something but have been unsuccessful. Would any Cold Fusion gurus like to assist me in how you alert your users when there query came back empty.
I tried:
<cfif #allAssociatesQry# is 0>
<cfif #allAssociatesQry# is null>
<cfif #allAssociatesQry# is "">
<cfif allAssociatesQry is 0>
<cfif allAssociatesQry is null>
<cfif allAssociatesQry is "">
Don't use try/catch. That's for code that doesn't run successfully. All you need is this:
<cfquery name="q">
sql
</cfquery>
<cfif q.recordcount is 0>
code for no records
<cfelse>
display records
</cfif>
I am having lots of trouble creating the sum of my percentage column which seems like it would be easy since its 100% when all branches are being shown. But I need to figure out the equation for the times that all branches are not shown. In the picture below each branches percentage is calculated by the number of that locations processed checklists divided by the total number of checklists. Unfortunately I can not figure out how to just "write" just adding the sum of the percentage column and displaying in into the total column. Any help would be greatly appreciated.
<cfset result = {} />
<cftry>
<cfquery datasource="#application.dsn#" name="GetLocationInfo">
SELECT *
FROM cl_checklists
</cfquery>
<cfquery name="allLocCode" dbtype="query">
SELECT DISTINCT trans_location, COUNT(*) AS locationCount FROM GetLocationInfo Where trans_location is not null GROUP BY trans_location ORDER BY trans_location
</cfquery>
<cfcatch type="any">
<cfset result.error = CFCATCH.message >
<cfset result.detail = CFCATCH.detail >
</cfcatch>
</cftry>
<cfset columnSum = ArraySum(allLocCode['locationCount'])>
<table border="1" id="Checklist_Stats">
<thead>
<th><strong>Location</strong></th>
<th><strong>Percent of Total Checklists</strong></th>
<th><strong>Location Total</strong></th>
</thead>
<tbody>
<cfloop query="allLocCode">
<cfset thisLocationName = trim(allLocCode.trans_location) />
<cfquery name="allLocCodeForLocationQry" dbtype="query">
SELECT trans_location,count(*) AS locCntr FROM GetLocationInfo WHERE trans_location='#thisLocationName#' GROUP BY trans_location ORDER BY trans_location
</cfquery>
<cfoutput query="allLocCodeForLocationQry">
<tr>
<td><strong>#thisLocationName#</strong></td>
<td>#NumberFormat((allLocCodeForLocationQry.locCntr/columnSum) * 100, '9.99')#%</td>
<td>#allLocCodeForLocationQry.locCntr#</td>
</tr>
</cfoutput>
</cfloop>
<cfdump var="#allLocCodeForLocationQry.locCntr#">
<tr>
<td><strong>Total</strong></td>
<td></td>
<td><cfoutput>#columnSum#</cfoutput></td>
</tr>
</tbody>
</table>
Unsure of how I can get the sum of this: <td>#NumberFormat((allLocCodeForLocationQry.locCntr/columnSum) * 100, '9.99')#%</td>
You can simply push the calculated percentage to an array and from there you can get the sum like this:
<!--- Define Array -->
<cfset checkListPercentage = arrayNew(1)>
<cfoutput query="allLocCodeForLocationQry">
<cfset currentPercentage = allLocCodeForLocationQry.locCntr / columnSum * 100)>
<cfset arrayAppend(checkListPercentage, currentPercentage)>
<tr>
<td><strong>#thisLocationName#</strong></td>
<td>#numberFormat(currentPercentage, '9.99')#%</td>
<td>#allLocCodeForLocationQry.locCntr#</td>
</tr>
</cfoutput>
<!--- Get Total --->
<cfoutput>#arraySum(checkListPercentage)#</cfoutput>
I've posted a somewhat similar answer before to one of these questions. This'll get you where you need to be:
Every time you get a percentage, you should set it as a variable and add it to a list or array. As an example for this chunk of code:
<cfloop query="allLocCode">
<cfset thisLocationName = trim(allLocCode.trans_location) />
<cfquery name="allLocCodeForLocationQry" dbtype="query">
SELECT trans_location,count(*) AS locCntr FROM GetLocationInfo WHERE trans_location='#thisLocationName#' GROUP BY trans_location ORDER BY trans_location
</cfquery>
<cfset PercentageList = "">
<cfset thisPercentage = #NumberFormat((allLocCodeForLocationQry.locCntr/columnSum) * 100, '9.99')#>
<cfset PercentageList = ListAppend(PercentageList, thisPercentage, ',')>
<cfoutput query="allLocCodeForLocationQry">
<tr>
<td><strong>#thisLocationName#</strong></td>
<td>#thisPercentage#%</td>
<td>#allLocCodeForLocationQry.locCntr#</td>
</tr>
</cfoutput>
</cfloop>
At the end of all your calculations, you should have a list of percentages. You can include this function to add the list together.
<cfscript>
function listSum(listStr)
{
var delim = ",";
if(ArrayLen(Arguments) GTE 2)
delim = Arguments[2];
return ArraySum(ListToArray(listStr, delim));
}
</cfscript>
So your last row would be:
<tr>
<td><strong>Total</strong></td>
<td>#listSum(PercentageList)#%</td>
<td><cfoutput>#columnSum#</cfoutput></td>
</tr>
Worth mentioning: Previously, it was pointed out to me that using Arrays and then converting to a List at the end of your calculations results in better performance, so that's something to keep in mind.
ArraySum is the relevant function for this.
With all the loops and queries inside other loops and queries, I just figured creating a list was a little easier.
E - unexplained downvotes are not nice.
I am trying to fix my query so that my total sum column will equal the correct number. I tried changing this line <cfset columnSum = ArraySum(allLocCode['locationCount'])> to <cfset columnSum = ArraySum(trim(allLocCode['locationCount']))> But it through an error. I want the empty string like in the picture below to not be counted for the total just like it does not show in the table. Is there another way to pull off this trim for my total column?
<cfset result = {} />
<cftry>
<cfquery datasource="#application.dsn#" name="GetLocationInfo">
SELECT *
FROM cl_checklists
</cfquery>
<cfcatch type="any">
<cfset result.error = CFCATCH.message >
<cfset result.detail = CFCATCH.detail >
</cfcatch>
</cftry>
<table border="1" id="Checklist_Stats">
<thead>
<th><strong>Location</strong></th>
<th><strong>Percent of Total Checklists</strong></th>
<th><strong>Location Total</strong></th>
</thead>
<tbody>
<cfquery name="allLocCode" dbtype="query">
SELECT DISTINCT trans_location, COUNT(*) AS locationCount FROM GetLocationInfo GROUP BY trans_location ORDER BY trans_location
</cfquery>
<cfloop query="allLocCode">
<cfset thisLocationName = trim(allLocCode.trans_location) />
<cfquery name="allLocCodeForLocationQry" dbtype="query">
SELECT trans_location,count(*) AS locCntr FROM GetLocationInfo WHERE trans_location='#thisLocationName#' GROUP BY trans_location ORDER BY trans_location
</cfquery>
<cfoutput query="allLocCodeForLocationQry">
<tr>
<td><strong>#thisLocationName#</strong></td>
<td>#NumberFormat((allLocCodeForLocationQry.locCntr/allLocCode.locationCount) * 100, '9.99')#%</td>
<td>#allLocCodeForLocationQry.locCntr#</td>
</tr>
</cfoutput>
</cfloop>
<cfset columnSum = ArraySum(allLocCode['locationCount'])>
<tr>
<td><strong>Total</strong></td>
<td></td>
<td><cfoutput>#columnSum#</cfoutput></td>
<cfdump var="#allLocCode#">
<cfdump var="#allLocCodeForLocationQry#">
<cfdump var="#thisLocationName#">
</tr>
</tbody>
<!--- Total of All Sum of each column --->
</table>
The correct answer should reflect 334 not 340
As requested, here's an answer with the relevant code isolated:
<cfquery name="allLocCode" dbtype="query">
SELECT DISTINCT trans_location, COUNT(*) AS locationCount
FROM GetLocationInfo
WHERE trans_location is not null
GROUP BY trans_location
ORDER BY trans_location
</cfquery>
If you need more help with the percentage stuff I'd recommend starting a new post. I see from your history you already have several threads kind of related to this feature, and as it gets more complicated it'll help to separate everything.
I am trying to figure out how to run queries through a MS sql database using ColdFusion in order to make a table that keeps track of Location Name, Percent of Total Checklists, and Location Total.
I seem to be failing on calculating each branch locations percentage of checklists. I am trying to get the percent of each branch location and then create a sum total line that will add the total of all branches together.
This is what I have but for some reason I continue to get 100% for every location instead of showing each branches percentage and then show the total on the bottom.
Any help with this would be greatly appreciated!
<cfset result = {} />
<cftry>
<cfquery datasource="#application.dsn#" name="GetLocationInfo">
SELECT *
FROM cl_checklists
</cfquery>
<cfcatch type="any">
<cfset result.error = CFCATCH.message >
<cfset result.detail = CFCATCH.detail >
</cfcatch>
</cftry>
<table border="1" id="Checklist_Stats">
<thead>
<th><strong>Location</strong></th>
<th><strong>Percent of Total Checklists</strong></th>
<th><strong>Location Total</strong></th>
</thead>
<tbody>
<cfquery name="allLocCode" dbtype="query">
SELECT DISTINCT trans_location, COUNT(*) AS locationCount FROM GetLocationInfo GROUP BY trans_location ORDER BY trans_location
</cfquery>
<cfloop query="allLocCode">
<cfset thisLocationName = trim(allLocCode.trans_location) />
<cfquery name="allLocCodeForLocationQry" dbtype="query">
SELECT trans_location,count(trans_location) AS locCntr FROM GetLocationInfo WHERE trans_location='#thisLocationName#' GROUP BY trans_location ORDER BY trans_location
</cfquery>
<cfoutput query="allLocCodeForLocationQry">
<tr>
<td><strong>#thisLocationName#</strong></td>
<td>#NumberFormat((allLocCodeForLocationQry.locCntr/allLocCode.locationCount) * 100, '9.99')#%</td>
<td>#allLocCodeForLocationQry.locCntr#</td>
</tr>
</cfoutput>
</cfloop>
</tbody>
<!--- Total of All Sum of each column --->
<tr>
<td><strong>Total</strong></td>
<td></td>
<td></td>
</tr>
</table>
Regarding I am trying to get the percent of each branch location and then create a sum total line that will add the total of all branches together., array functions work on query columns. The syntax, is:
columnSum = ArraySum(queryName['columnName']
Hi am doing dynamic TR and TD in coldfusion, but apparently i am trying this kind of screen. here is my try with colfusion
<cfif variables.newrow EQ true>
<tr align="center">
</cfif>
<cfoutput query="gResults">
<cfquery datasource="#request.dsn#" name="nextqueries">
Query
</cfquery>
<td height="30" valign="middle"><strong>
<a href="viewdir.cfm?catID=#val(pic_id)#
<cfif isDefined('url.l') and url.l neq ''>&l=#url.l#</cfif>">
#pic_cat_name#</a></strong><br>
<cfloop query="nextqueries">
<cfquery datasource="#request.dsn#" name="showanother">
select * from
mytable as grlist
where pic_cid =
<cfqueryparam cfsqltype="cf_sql_numeric" value="#Trim(nextqueries.pic_id)">
</cfquery>
»
<a href="viewdir.cfm?catID=#val(pic_id)#
<cfif isDefined('url.l') and url.l neq ''>&l=#url.l#</cfif>">#pic_cat_name#
</a> </cfloop></td>
<cfif gResults.currentRow MOD 4 EQ 0>
</tr>
<cfset variables.newrow = true>
<cfelse>
<cfset variables.newrow = false>
</cfif>
</cfoutput>
trying to do like this:
http://screencast.com/t/oso4jkhBm3
There are a lot of potential improvements, but this answer will only deal with table rows. You start with:
<cfif variables.newrow EQ true>
<tr align="center">
</cfif>
Now I'm going to look for the closing tag. The only one I see is here:
<cfif gResults.currentRow MOD 4 EQ 0></tr></cfif>
and that line is inside a query loop. What this means is that you might have more than one closing tag, or you might not have any. You need exactly one. To solve this specific problem, you have to do this:
<cfif variables.newrow EQ true>
<tr align="center">
code to populate this table row
</cfif>
When you get that part sorted out, we can look at what goes into the details.
To get data to display in an html table from top to bottom then left to right like in the image linked in your question, you can do something similar to the following.
<!--- Get query results --->
<cfset arrayOFValues = arraynew(1)>
<cfset queryResults = querynew("Col1,Col2,Col3")>
<!--- Fill query with example data --->
<cfloop from="1" to="25" index="i">
<cfset queryaddrow(queryResults)>
<cfset querySetCell(queryResults, "Col1", "Col1 Row " & i)>
<cfset querySetCell(queryResults, "Col2", "Col1 Row " & i)>
<cfset querySetCell(queryResults, "Col3", "Col1 Row " & i)>
</cfloop>
<!--- Now have a query named queryResults with 25 rows --->
<!--- Set the number of columns and calculate the number of rows needed --->
<cfset numberOfColumns = 3>
<cfset rowsNeeded = ceiling(queryResults.recordcount / numberOfColumns)>
<cfoutput>
<table>
<cfloop from="1" to="#rowsNeeded#" index="curRow">
<tr>
<cfloop from="0" to="#numberOfColumns-1#" index="curCol">
<td>
#queryResults.Col1[(rowsNeeded * curCol) + curRow]#
</td>
</cfloop>
</tr>
</cfloop>
</table>
</cfoutput>
The first part is just creating a query result. I then find the number of rows that is needed to display the records by dividing the number of results returned in the query by the number of columns to be displayed. The ceiling is required for when the result is not a whole number.
We have to loop each column record with in the row to get the desired index. To find the required index of the field we have to take the row that’s being displayed + the column were on times the the number of rows that will be displayed.
If you know the number of columns you can hard code for them in the following manner and eliminate the inner loop.
<tr>
<td>#queryResults.Col1[3 * rowsNeeded]#</td>
<td>#queryResults.Col1[3 + 1*rowsNeeded]#</td>
<td>#queryResults.Col1[3 + 2*rowsNeeded]#</td>
</tr>