CF sum of percentage column - coldfusion

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.

Related

CF Getting the sum of a column on a database query

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.

CF query remove empty string results for total sum

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.

CF Location queries looping issue

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, Percent of Total Checklists, and Location Total.
I am having trouble looping to show my locations only once and to run the totals for each location. I am not sure why my table is adding all of these lines like the picture below, 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 locCntr FROM GetLocationInfo GROUP BY trans_location ORDER BY trans_location
</cfquery>
<cfloop query="allLocCode">
<cfset thisLocationName = trim(allLocCode.trans_location) />
<cfoutput query="allLocCode">
<tr>
<td><strong>#thisLocationName#</strong></td>
<td></td>
<td></td>
</tr>
<cfset thisLocationName = "" />
</cfoutput>
</cfloop>
</tbody>
<!--- Total of All Sum of each column --->
<tr>
<td><strong>Total</strong></td>
<td></td>
<td></td>
</tr>
</table>
You only need to loop through the query once. Remove the additional cfoutput
<cfoutput query="allLocCode">
<cfset thisLocationName = trim(allLocCode.trans_location) />
<tr>
<td><strong>#thisLocationName#</strong></td>
<td></td>
<td></td>
</tr>
</cfoutput>
Your code creates a nested loop.
<cfloop query="allLocCode"> // loop over all items in the query
<cfset thisLocationName = trim(allLocCode.trans_location) />
<cfoutput query="allLocCode"> // loop again over all items in the query
<tr>
<td><strong>#thisLocationName#</strong></td> // print the string
<td></td>
<td></td>
</tr>
<cfset thisLocationName = "" /> // empties the string, hence next rows will be empty
</cfoutput>
</cfloop>
Change the line <cfoutput query="allLocCode"> to <cfoutput>.

CF Queries Calculating Percentages and adding the sum for a total line

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']

Need advice.. dynamic td tr

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>