Conditional CF Record Count - coldfusion

I'm trying to save my database server a few requests by querying a large number of items from several categories all at once, then using <cfif ... > statements to filter those results into unique tables I'm showing for each category. I'm looking to find record counts for each of the categories returned, not just the record count of the overall query.
The basic code is:
<cfinvoke component="..." method="..." returnvariable="session.queryList">
...
</cfinvoke>
<cfoutput #session.queryList#>
<cfif #category# eq "A">
[Table for A things]
</cfif>
<cfif #category# eq "B">
[Table for B things]
</cfif>
<cfif #category# eq "C">
[Table for C things]
</cfif>
</cfoutput>
I don't want to use "ORDER BY category" here because the tables are actually on different divs we're hiding and showing, so we need separate tables.
The problem I'm running into is that I want the "Table for A Things" to say "No results" if there is no records returned where category="A", but RecordCount seems to apply to the entire query. Is there any way to say something along the lines of <cfif #queryList.RecordCount# WHERE #category# eq "A" GT "0">?

QoQ can help.
<cfinvoke component="..." method="..." returnvariable="session.queryList">
...
</cfinvoke>
<!---then run QoQ on it--->
<cfquery name="catA" dbtype="query">
select * from session.queryList where category ="A"
</query>
<cfquery name="catB" dbtype="query">
select * from session.queryList where category ="B"
</query>
<cfif catA.recordcount>
<cfoutput query="catA">
[Table for A things]
</cfoutput>
<cfelse>
No Records for A things
</cfif>
<cfif catB.recordcount>
<cfoutput query="catB">
[Table for B things]
</cfoutput>
<cfelse>
No Records for B things
</cfif>

I believe you are trying to do the following. <cfoutput> has a feature that helps you group the query results given the query is ordered by the grouping item.
<cfoutput query="#session.queryList#" group="category">
<h3>Category #category#</h3>
<table>
<tr><th>...</th><th>...</th></tr>
<cfoutput><!--- This cfoutput loops through the each record in the group. --->
---rows---
</cfoutput>
<table>
</cfoutput>

QofQ is slow. You can accomplish this with a single round trip to mySQL:
SELECT someColumn, category, count(*) AS categoryCount
FROM theTable
GROUP BY category
ORDER BY category, someColumn
Grouping will give you a count per category which you can use in CFML.
<cfoutput query="session.queryList" group="category">
<cfif categoryCount eq 0>
No Records for #category#. =(
</cfif>
<cfoutput>
#someColumn#<br>
</cfoutput>
</cfoutput>

Related

Why is cfoutput being ignored?

I have a very simple CFML page as follows:
<cfquery name="qry" datasource="#application.db.source#" username="#application.db.user#" password="#application.db.pass#">
SELECT * FROM changemgmt.rfc WHERE rfc_id = <cfqueryparam cfsqltype="CF_SQL_INTEGER" value="0">;
</cfquery>
<cfoutput query="qry">
#qry.RecordCount#
</cfoutput>
My <cfoutput> tag is not working as I would expect. If you were to look at the source code of this page, it would be entirely composed of empty lines. It's as if the <cfoutput> tag is being parsed out by the server. However if I change the code to:
<cfoutput>
#qry.RecordCount#
</cfoutput>
I am using Lucee as my backend CFML engine. Can anyone explain to my why there is a difference?
<cfoutput query="qry"> this is used to loop throw all the rows in the query. If your query result have no rows, the execution will never reach the login with in the <cfoutput query="qry">. But if there are 1+n rows in the result, your code will print the recordcount 1+n times.
In this case if all you want is to print recordcount of the result, then you just need to use <cfoutput>#qry#</cfoutput>
But if you want to print values each row of the query then you can use <cfoutput query="qry">
<cfoutput query="qry">
<div>
<span>#qry.rfc_id#</span>
<span>#qry.name#</span>
...
</div>
</cfoutput>

ColdFusion - Output Grouping From a Query

I have a great question that is probably bone-head simple. I have the following query:
<cfquery name="getempareview" dbtype="query">
SELECT firstname,lastname,deptname,supcode
FROM getreviews
WHERE supcode IN (#preserveSingleQuotes(setsupcode)#)
</cfquery>
What I need to do is output so that the supcode has the other data under it in a list. So, if I have 100 rows of data and the supcode is the same on 25 of the records, just have the following:
supcode
firstname lastname - deptname (all 25 records would be listed out here)
Any help would be greatly appreciated.
Nested outputs. Try this.
<cfoutput query="YourQueryName" group="SupCode">
<h2>#SupCode#</h2>
<cfoutput>
#FirstName# #LastName# <br/>
</cfoutput>
</cfoutput>
You need to use nested and grouped output. And add an ORDER BY to your query.
<cfset setsupcode = "1,3,5">
<cfquery name="getempareview" dbtype="query">
SELECT firstname,lastname,deptname,supcode
FROM getreviews
WHERE supcode IN (<cfqueryparam value="#setsupcode#" cfsqltype="numeric" list="yes">)
ORDER BY supcode, deptname, lastname, firstname
</cfquery>
<cfoutput query="getempareview" group="supcode">
<h2>#supcode#</h2>
<cfoutput group="deptname">
#firstname# #lastname# (#deptname#) <br>
</cfoutput>
</cfoutput>
https://trycf.com/gist/763ede5485b0978504250f7f5baf9deb/acf11?theme=solarized_dark
Also, since this is apparently a Query of Query, you may be able to better organize your data in your initial query, rather than having to come back to reprocess the data.

Check if Category already exist within database in coldfusion

I want to use a bind to another cfm page to check if the database.
The top portion is a query I wrote that i think would work. If the count of Tag is Greater than 0 then the if statement should trigger stating that the Tag has been taken.
I can write the query, but I do not know how to implement it into the logic below it.
This is my bind page:
<cfquery name="TagCheck" datasource="PostBlog">
select Count(Category)
from Categories
where Category = #URL.Category#
</cfquery>
<cfif URL.Category NEQ "">
<cfif Compare(URL.Category, "2") EQ 0>
<span style="color: red;">The Category <cfoutput>#URL.Category#</cfoutput> already exist within the database.</span>
<cfelse>
<cfoutput><span style="color: Green;">#URL.Category# is available</cfoutput>
</cfif>
</cfif>
Firstly, use cfqueryparam when passing dynamic values to your queries, especially so if it's something the users can specify.
Secondly, when using an aggregate function like Count() you need to then specify an alias if you want to use that value later on.
<cfquery name="TagCheck" datasource="PostBlog">
select Count(Category) AS CategoryCount
from Categories
where Category = <cfqueryparam value="#URL.Category#" CFSQLType="CF_SQL_INTEGER">
</cfquery>
Finally, in your logic you should just need to then do:
<cfif URL.Category NEQ "">
<cfif TagCheck.CategoryCount GT 0>
<span style="color: red;">The Category <cfoutput>#URL.Category#</cfoutput> already exist within the database.</span>
<cfelse>
<cfoutput><span style="color: Green;">#URL.Category# is available</cfoutput>
</cfif>
</cfif>

How to Break out of Cfoutput

I am looping through the results of a query, and I need to limit the number of rows displayed. I need to use cfoutput because I'm using the group attribute, and I cannot use the maxrows because not all rows will be displayed.
I tried to use <cfbreak> inside the <cfoutput>, but that throws an error.
How can I break out of the <cfoutput> loop?
If your group by is only there to remove duplicates from your results I would suggest using your query to cut them down then you can cfloop (select distinct and reducing your returned column list).
If you are using your group by to "group" your results You could run a counter within your loop and a cfif statement inside your first loop to omit later results.
You could fake the group by option in your cfloop by matching value from previous row if you need cfbreak
<cfloop query="queryname">
<cfif queryname.column[currentrow-1] neq queryname.column[currentrow]>
#queryname.column#
</cfif>
</cfloop>
Random note: you can maxrows on any/all levels of your grouped cfoutput
<cfset tmp = querynew('id,dd')>
<cfloop from="1" to="20" index="i">
<cfset queryaddrow(tmp,1)>
<cfset querysetcell(tmp,'id',rand(),i)>
<cfset querysetcell(tmp,'dd',(i mod 4),i)>
</cfloop>
<cfquery dbtype="query" name="tmp">select * from tmp order by dd</cfquery>
<cfoutput query="tmp" group="dd" maxrows="2">#dd#<br
<ul>
<cfoutput maxrows="2" group="id"><li>#id#</li></cfoutput>
</ul>
</cfoutput>
You could use the cfthrow tag to trigger an exception that will allow you to break out of the loop using cfcatch you can then ignore the exception and continue processing. That will give you what you want.
<cftry>
<cfset i = 0>
<cfoutput query="qMyQuery" group="someGroup">
<cfset i = i + 1>
Parent
<cfoutput>
Child
</cfoutput>
<cfif i GTE 10>
<cfthrow type="break">
</cfif>
</cfoutput>
<cfcatch type="break">
<!--- DO NOTHING - THIS IS A HACK FOR NOT BEING ABLE TO USE CFBREAK inside cfoutput. --->
</cfcatch>
</cftry>

Evaluate List of ColdFusion Variables

i created a table using coldfusion lists system, rows are months and the columns are cities, and the variable is the sales, now i need to add to every evaluated sale variable, the list of companies that made these sales, so far there is no problem with writting the sql of this table and the sales, but i cant define-#evaluate# the list of these companies that belongs to each sale in the table, since it is the LIST of companies, not one variable like sale, i hope i made myself clear :) here is my code:
The query with some sets:
<cfset month_list_name = "#message13#,#message2#,#message3#,#message4#,#message5#,#message6#,#message7#,#message8#,#message9#,#message10#,#message11#,#message12#">
<cfset type_index = 'NETTOTAL'>
<cfquery name="GET_CITY" datasource="#DSN#">
SELECT CITY_ID,CITY_NAME FROM SETUP_CITY ORDER BY CITY_NAME
</cfquery>
<cfquery name="GET_COMPANY" datasource="#DSN#">
SELECT COMPANY_ID,FULLNAME FROM COMPANY ORDER BY COMPANY_ID
</cfquery>
<cfset c_index = 'COMPANY_ID'>
<cfset no_cities = 0 />
<cfset cities_list = ''>
<cfset cities_list_name = ''>
<cfset month_list = ''>
<cfoutput query="get_city"><cfset cities_list = listappend(cities_list,city_id)><cfset no_cities ++ /></cfoutput>
<cfoutput query="get_city"><cfset cities_list_name = listappend(cities_list,city_name)></cfoutput>
<cfloop from="1" to="12" index="i"><cfset month_list=listappend(month_list,i)></cfloop>
<cfquery name="GET_SALES_TOTAL" datasource="#dsn#">
SELECT
SUM(NETTOTAL) NETTOTAL,
SC.CITY_ID,
DATEPART(MM,INVOICE_DATE) AY,
C.FULLNAME,
C.COMPANY_ID AS COMPANY_ID
FROM
#DSN2_ALIAS#.INVOICE I,
SETUP_CITY SC,
COMPANY C
WHERE
MONTH(INVOICE_DATE) >= 1
AND MONTH(INVOICE_DATE) < 12
AND C.COMPANY_ID=I.COMPANY_ID
AND SC.CITY_ID=C.CITY
AND PURCHASE_SALES=1
GROUP BY
DATEPART(MM,INVOICE_DATE),
SC.CITY_ID,
C.FULLNAME,
C.COMPANY_ID
</cfquery>
here is the definitions for lists:
<cfloop list="#month_list#" index="month_index">
<cfloop list="#cities_list#" index="city_index">
<cfoutput query="GET_SALES_TOTAL">
<cfif city_id eq city_index and AY eq month_index>
<cfloop list="#type_index#" index="tt_index">
<cfset 'alan_#tt_index#_#city_index#_#month_index#' = evaluate(tt_index)>
<cfset 'alan2_#city_index#_#tt_index#_#month_index#' = evaluate(tt_index)>
</cfloop>
<cfloop list="#c_index#" index="cc_index">
<cfif cc_index eq company_id>
<cfset 'company_#cc_index#_#city_index#_#month_index#' = evaluate(cc_index)>
</cfif>
</cfloop>
</cfif>
</cfoutput>
</cfloop>
</cfloop>
and here's the table:
<cfloop list="#month_list#" index="m_index">
<tr class="color-row" height="20">
<td width="150" nowrap><b><cfoutput>#left(listgetat(month_list_name,listfind(month_list,m_index)),20)#</cfoutput></b></td>
<cfloop list="#cities_list#" index="ddd_other">
<cfloop list="#type_index#" index="ii_index">
<td align="center">
<cfif isdefined('alan_#ii_index#_#ddd_other#_#m_index#') and len(evaluate('alan_#ii_index#_#ddd_other#_#m_index#'))>
<cfset all_toplam=evaluate('alan_#ii_index#_#ddd_other#_#m_index#')+all_toplam>
<cfset 'total_#ii_index#_#m_index#'=evaluate('total_#ii_index#_#m_index#') + #evaluate('alan_#ii_index#_#ddd_other#_#m_index#')#>
<cfset 'total2_#ddd_other#'=evaluate('total2_#ddd_other#') + #evaluate('alan2_#ddd_other#_#ii_index#_#m_index#')#>
<cfif listfindnocase('NETTOTAL',ii_index)>
<cfif isdefined('attributes.money') and attributes.money is 2>
<cfoutput>#TLFormat((evaluate('alan_#ii_index#_#ddd_other#_#m_index#')/get_money.rate2),2)#</cfoutput>
<cfelse>
<cfoutput>#TLFormat(evaluate('alan_#ii_index#_#ddd_other#_#m_index#'),2)#</cfoutput>
</cfif>
<cfelse>
<cfif isdefined('attributes.money') and attributes.money is 2>
<cfoutput>#TLFormat((evaluate('alan_#ii_index#_#ddd_other#_#m_index#')/get_money.rate2),2)#</cfoutput>
<cfelse>
<cfoutput>#TLFormat(evaluate('alan_#ii_index#_#ddd_other#_#m_index#'),2)#</cfoutput>
</cfif>
</cfif>
<cfelse>
0
</cfif>
<cfloop list="#c_index#" index="co_index">
<cfif listfindnocase('COMPANY_ID',co_index)>
<cfoutput>#evaluate('company_#co_index#_#ddd_other#_#m_index#')#</cfoutput>
</cfif>
</cfloop>
</td>
</cfloop>
</cfloop>
<cfloop list="#type_index#" index="kk_ind">
<td align="center" class="txtbold">
<cfif isdefined('attributes.money') and attributes.money is 2>
<cfoutput>#TLFormat((evaluate('total_#kk_ind#_#m_index#')/get_money.rate2),2)#</cfoutput>
<cfelse>
<cfoutput>#TLFormat(evaluate('total_#kk_ind#_#m_index#'),2)#</cfoutput>
</cfif>
</td>
</cfloop>
</tr>
</cfloop>
it says: Variable company_COMPANY_ID_1_1 is undefined. where is my mistake?
i cant evaluate the LIST of company_idies in the same way i evaluated the NETTOTAL, since net total is not the list, but only one value... And thank you all for the help and attention! ;)
There are a lot of things you can improve in this code.
Incrementing the number of cities inside a loop is unnecessary. You can get the count directly from SQL (select count(*) from setup_city) or from CF after building your list (listlen(cities_list).
For that matter, it's unnecessary to loop through the list manually when you can simply use ValueList to have CF do the work for you:
cities_list = ValueList( get_city.city_id );
cities_list_name = ValueList( get_city.city_name );
There's no reason to build a list of months if all you're ever going to do is loop from 1 to 12. Use the 1-to-12 loop instead.
type_index doesn't need to be a list if you only have one item. Use the variable instead. Replace it with a list only when you actually need a list; this will also remove the need to use evaluate, which is making your code hard to read and difficult for people to follow. Same thing for cc_index.
Because scopes can be accessed as if they were structs, it's generally better (and can be significantly faster) to use structkeyexists( attributes, "money" ) rather than isdefined( "attributes.money" ). Specifying the scope for isdefined does help, of course ... isdefined( "money" ) is not only slow, but could return a completely different variable if you're not careful.
Speaking of structs, I would definitely recommend that you use them rather than concatenated variable names. It's extremely difficult to parse what you have written in order to understand what you are trying to do: using structs would make it easier to follow.
Finally, it looks to me like you're doing a ton of work in ColdFusion to do something that your database could do for you much more easily. If you need grand totals for companies by city, why not just do this?
<cfquery name="GET_SALES_GRAND_TOTAL" datasource="#dsn#">
SELECT
SUM(NETTOTAL) NETTOTAL,
SC.CITY_ID,
C.FULLNAME,
C.COMPANY_ID AS COMPANY_ID
FROM
#DSN2_ALIAS#.INVOICE I,
SETUP_CITY SC,
COMPANY C
WHERE
MONTH(INVOICE_DATE) >= 1
AND MONTH(INVOICE_DATE) < 12
AND C.COMPANY_ID=I.COMPANY_ID
AND SC.CITY_ID=C.CITY
AND PURCHASE_SALES=1
GROUP BY
SC.CITY_ID,
C.FULLNAME,
C.COMPANY_ID
</cfquery>
Is there a need to check that the month is between 1 and 12? If INVOICE_DATE exists, then it has to have a month between 1 and 12. I would either remove those lines from the query entirely or replace them with INVOICE_DATE IS NOT NULL.
You should then be able to get your table of results with something that looks roughly like this:
<cfoutput query="GET_SALES_TOTAL" group="AY">
<!--- months first --->
<tr>
<!--- month-specific stuff goes here --->
<td>month_header</td>
<cfoutput group="city_id">
<!--- city-specific stuff --->
<td><!--- format NETTOTAL however you want here ---></td>
</cfoutput>
</tr>
</cfoutput>
<tr>
<td>grand_total_header</td>
<cfoutput query="GET_SALES_GRAND_TOTAL" group="city_id">
<td><!--- format NETTOTAL here ---></td>
</cfoutput>
</tr>
Hopefully this is of some help to you. I would strongly encourage you to read up on arrays and structs; someone using evaluate is typically doing it the hard way when there is a much easier way of managing things, and there are plenty of examples both on SO and elsewhere of CF code that you should be able to learn from.