I'm running the following query and after running the QoQ for SECONDCONN , I am not getting the desired output in my cfchart.
<!--- QoQ for FIRSTCONN --->
<!--- Master Query --->
<cfquery datasource = "XX.XX.X.XX" name="master1">
SELECT STR_TO_DATE(date_format(Timedetail,'%m-%d-%Y'),'%m-%d-%Y') as FIRSTCONN
, COUNT(Timedetail) as FIRSTOccurances
, EVENTS
FROM MyDatabase
WHERE EVENTS = "FIRST"
GROUP BY FIRSTCONN ;
</cfquery>
<!--- Detail Query --->
<!--- <cfdump var = "#master#"> --->
<cfquery dbtype="query" name="detail1">
SELECT *
FROM master1
WHERE FIRSTCONN >= <cfqueryparam value="#form.startdate#" cfsqltype="cf_sql_varchar">
AND FIRSTCONN < <cfqueryparam value="#dateAdd('d', 1,form.enddate)#" cfsqltype="cf_sql_varchar">;
</cfquery>
<!--- QoQ for SECONDCONN --->
<!--- Master Query --->
<cfquery datasource = "XX.XX.X.XX" name="master2">
SELECT STR_TO_DATE(date_format(Timedetail,'%m-%d-%Y'),'%m-%d-%Y') as SECONDCONN
, COUNT(Timedetail) as SECONDOccurances
, EVENTS
FROM MyDatabase
WHERE EVENTS = "SECOND"
GROUP BY SECONDCONN ;
</cfquery>
<!--- Detail Query --->
<!--- <cfdump var = "#master#"> --->
<cfquery dbtype="query" name="detail2">
SELECT *
FROM master2
WHERE SECONDCONN >= <cfqueryparam value="#form.startdate#" cfsqltype="cf_sql_varchar">
AND SECONDCONN < <cfqueryparam value="#dateAdd('d', 1,form.enddate)#" cfsqltype="cf_sql_varchar">;
</cfquery>
<cfchart format="flash" chartwidth="1000" chartheight="500" scalefrom="0" scaleto="50000" xAxisTitle="Dates" yaxistitle="Number of Connections">
<cfchartseries query="detail1" type="line" itemColumn="FIRSTCONN" valueColumn="FIRSTOccurances" >
<cfchartseries query="detail2" type="line" itemColumn="SECONDCONN" valueColumn="SECONDOccurances" >
</cfchartseries>
</cfchart>
On X Axis, the chart is displaying the correct startdate but it stops displaying the dates after middle point somewhere and rest of the line chart is displayed without any dates mentioned on the x-axis. What could be the reason? The dates are displaying properly when I ran just one query, that is QoQ for FIRSTCONN.
attached shows the output with only one query , that is QoQ for FIRSTCONN
is for the both and showing undesirable output.
Another point I noticed is that when I run the query for only SECONDCONN, I see an output without any dates mentioned on the x-axis. What could be th reason? I have attached below for the reference.there is no change in the query.
The cfchart code I'm using is as follows:
<cfchart format="flash"
chartwidth="1000"
chartheight="500"
scalefrom="0"
scaleto="50000"
xAxisTitle="Date"
yaxistitle="Number of Connections"
showLegend = "yes"
showMarkers = "yes"
sortXAxis= "yes"
tipStyle="MouseDown"
>
<cfchartseries query="detail2" type="line" itemColumn="SECONDCONN " valueColumn="SECONDOccurances" >
</cfchartseries>
</cfchart>
The cfdump of second query is as follows:
query
RESULTSET
query
SECONDCONN SECONDOCCURANCES EVENTS
1 {ts '2013-06-24 00:00:00'} 556 SECOND
2 {ts '2013-06-25 00:00:00'} 2710 SECOND
3 {ts '2013-06-26 00:00:00'} 2854 SECOND
4 {ts '2013-06-27 00:00:00'} 6348 SECOND
5 {ts '2013-06-28 00:00:00'} 4285 SECOND
6 {ts '2013-06-29 00:00:00'} 2843 SECOND
7 {ts '2013-06-30 00:00:00'} 875 SECOND
8 {ts '2013-07-01 00:00:00'} 4033 SECOND
9 {ts '2013-07-02 00:00:00'} 3211 SECOND
10 {ts '2013-07-03 00:00:00'} 2882 SECOND
11 {ts '2013-07-04 00:00:00'} 978 SECOND
12 {ts '2013-07-05 00:00:00'} 1727 SECOND
13 {ts '2013-07-06 00:00:00'} 811 SECOND
14 {ts '2013-07-07 00:00:00'} 522 SECOND
15 {ts '2013-07-08 00:00:00'} 2556 SECOND
16 {ts '2013-07-09 00:00:00'} 1160 SECOND
17 {ts '2013-07-10 00:00:00'} 8580 SECOND
18 {ts '2013-07-11 00:00:00'} 2630 SECOND
19 {ts '2013-07-16 00:00:00'} 12 SECOND
Please let me know if I can answer more questions.
Without seeing a dump of the query data, my guess is the charting engine may have decided there are too many values to reasonably display on the x-axis. (I tested your code and it works fine with CF9). Try it with a smaller date range and see if the date labels reappear. If so, you may need to customize the chart settings to get a better fit. Here are some of the pertinent style settings.
isHideOverlapped - hide/show labels that overlap
skipLabels - adjust to display every n labels instead of all
orientation - label orientation (horizontal or vertical)
Test Code
<cfset detail1 = queryNew("")>
<cfset queryAddColumn(detail1, "FIRSTCONN", "date", listToArray("2013-07-31,2013-08-15,2013-08-17"))>
<cfset queryAddColumn(detail1, "FIRSTOccurances", listToArray("3,5,6"))>
<cfset detail2 = queryNew("")>
<cfset queryAddColumn(detail2, "SECONDCONN", "date", listToArray("2013-08-10,2013-08-18,2013-08-20"))>
<cfset queryAddColumn(detail2, "SECONDOccurances", listToArray("4,10,8"))>
<cfchart format="flash" xAxisTitle="Dates" yaxistitle="Number of Connections">
<cfchartseries query="detail1" type="line" itemColumn="FIRSTCONN" valueColumn="FIRSTOccurances" />
<cfchartseries query="detail2" type="line" itemColumn="SECONDCONN" valueColumn="SECONDOccurances" />
</cfchart>
QoQ is faster and that's why I'm using it.
Honestly, that is not a good approach for handling a slow running queries. The best place to optimize a db query is in the database. Take the time to examine the query plan and find the bottleneck, add the appropriate indexes, etcetera. By using QoQ's you incur a lot of extra network o/h by pulling back a lot of extra data that is ultimately discarded. Not to mention, the memory required to build a new resultset. It is a lot of wasted resources and will not scale well.
(That said, I believe you have already opened a separate thread regarding the query speed. So rather than mixing questions again, I will leave that conversation for your other thread.)
The problem was resolved when I changed the order of displaying line chart. I mean I was displaying in increasing order fashion in the following manner:
<cfchartseries query="detail1" type="line" itemColumn="FIRSTCONN" valueColumn="FIRSTOccurances" >
<cfchartseries query="detail2" type="line" itemColumn="SECONDCONN" valueColumn="SECONDOccurances" > and so on till seventh connection.
When I started displaying it in decreasing like the following :
<cfchartseries query="detail7" type="line" itemColumn="SEVENTHCONN" valueColumn="SEVENTHOccurances" >
<cfchartseries query="detail6" type="line" itemColumn="SIXTHCONN" valueColumn="SIXTHOccurances" > and so on till FIRST CONNECTION
The problem was resolved but I'm not sure what was the reason behind it.
Related
I’m trying to do a query simliar to:
<CFQUERY Name=GetResults Database=Rent> SELECT * FROM Units, Tenants
WHERE Units.UnitID=Tenants.UnitID</CFQUERY>
<CFOUTPUT Query=GetRetults>
#UnitName# #TenantID#<BR>
</CFOUTPUT>
This is what the results look like
101 57
101 199
101 204
101 590
102 85
102 97
103 44
I only want one result for each unit for the TenantID, and I would like it to be the highest Tenant ID. In other words I’d like the results to look like:
101 590
102 97
103 44
I’m at a loss. I’ve tried creating a Loop within the Query, but have not been successful. I know this must be simple but I can’t figure it out. I'd appreciate any suggestions
Group your query results on the database and use an aggregate function. Something like this should work:
<CFQUERY Name="GetResults" Database="Rent">
SELECT u.unitID, u.unitName, max( t.tenantID ) as maxTenantID
FROM Units u
INNER JOIN Tenants t ON u.UnitID = t.UnitID
GROUP BY u.unitID, u.unitName
</CFQUERY>
If changing the SQL is not an option, you can employ a query of queries to do the same thing once the database returns the full result set to ColdFusion. Note, the SQL below runs in memory and not on the database.
<CFQUERY Name="groupedResults" dbtype="query">
SELECT unitID, unitName, max( tenantID ) as maxTenantID
FROM GetResults
GROUP BY unitID, unitName
</CFQUERY>
And finally, there is a group attribute to the cfoutput tag as well that you can use. The inner cfoutput is run once for each tenant. (I consider this the ugliest approach)
<CFOUTPUT Query="GetRetults" group="unitID">
#UnitName#
<!--- Reset every time --->
<cfset maxTenantID = 0>
<cfoutput>
<cfset maxTenantID = max( maxTenantID, TenantID )>
</cfoutput>
#maxTenantID#<BR>
</CFOUTPUT>
We religiously use cfqueryparam in our SQL queries.
Some of my predecessors seem to have been a little overzealous when using it with direct values rather than variables.
Isn't
record_is_deleted_bt = <cfqueryparam cfsqltype="cf_sql_bit" value="0">
overkill? I mean, there's no chance for SQL injection and I don't think that using a bind variable here does anything helpful vis-à-vis improving performance in the database. Wouldn't it be just as reasonable to do
record_is_deleted_bt = 0
?
Is there any advantage to using cfqueryparam in such an instance, besides ingraining the habit of using it? Is there a disadvantage?
No, this is not overkill. cfqueryparam's first job is data binding. It helps in sql injection prevention is just the add-on bonus. The prepared statements through data binding execute faster. You are wrong to assume that it is there to help on sql attack prevention only.
Important Note:
I am adding Test case provided by #Dan Bracuk on an oracle db.
<cfquery name="without" datasource="burns">
select count(*)
from burns_patient
where patientid = 1
</cfquery>
<cfquery name="with" datasource="burns">
select count(*)
from burns_patient
where patientid = <cfqueryparam cfsqltype="cf_sql_integer" value="1">
</cfquery>
<cfscript>
TotalWithout = 0;
TotalWith = 0;
</cfscript>
<cfloop from="1" to="1000" index="i" step="1">
<cfquery name="without" datasource="burns" result="resultwithout">
select count(*)
from burns_patient
where patientid = 1
</cfquery>
<cfquery name="with" datasource="burns" result="resultwith">
select count(*)
from burns_patient
where patientid = <cfqueryparam cfsqltype="cf_sql_integer" value="1">
</cfquery>
<cfscript>
TotalWithout += resultwithout.executiontime;
TotalWith += resultwith.executiontime;
</cfscript>
</cfloop>
<cfdump var="With total is #TotalWith# and without total is #TotalWithout#.">
The with total ranges from 700 to 900 total milliseconds. The without total ranges from 1800 to 4500 milliseconds. The without total is always at least double the with total.
I'm having some trouble with the CreateDate() function, it's just erroring and I have no idea why!
I am running this query to get all of the dates from news stories so that I can create a news archive monthly.
<cfquery name="selectNews" datasource="#Request.dsn#">
SELECT Month(NewsDate) AS theCount
FROM news
GROUP BY Month(NewsDate)
</cfquery>
Then when I output it, I'm trying to output it in the following format
Aug 2012
Sept 2012
Oct 2012
So I'm using the following code to try to output this list
<ul>
<cfloop query="selectNews">
<cfoutput>
<cfset theDay = DateFormat(Now(), 'dd')>
<cfset theMon = theCount>
<cfset theYear = DateFormat(Now(), 'yyyy')>
<li>#CreateDate(theYear, theMon, theDay)#</li>
</cfoutput>
</cfloop>
</ul>
It works fine for the first item, it will output Aug 2012, however it will then error, saying this
Error Occurred While Processing Request
MONTH
Which to me, at least, is useless!
My guess is that the SQL Month() function is returning a 0 for January and CreateDate expects a 1 for January.
Edit
<ul>
<cfloop query="selectNews">
<cfset theDay = Day(Now())>
<cfset theMon = #theCount#>
<cfset theYear = Year(Now())>
<cfoutput><li>#DateFormat(CreateDate(theYear, theMon, theDay), "mmm yyyy")#</li></cfoutput>
</cfloop>
</ul>
Edit
This seems to be working but only with odd numbered months
<cfset months = [1,3,5] />
<ul>
<cfloop array="#months#" index="currentmonth">
<cfoutput><li>#DateFormat(CreateDate(Year(Now()), currentmonth, Day(Now())), "mmm yyyy")#</li></cfoutput>
</cfloop>
</ul>
This was me being an idiot. I was using DateFormat(Now(), 'dd'), which is a huge stupid mistake, seeing as there is only 30 days in September. It was running CreateDate(2012, 09, 31), which obviously won't work!
I am working on a tax project. Taxes are broken down into quarters. the months the taxes are run are March, June, Sept, and December. once run my website displays when the taxes will run again. my problem is that in my results page when the next run date is December instead of displaying 12-2012 i get something that looks like 0-2012.
Here is my code:
<td style="white-space: nowrap;"> #stec_mysql_search_results.cover_date# </td>
<td style="white-space: nowrap;"> <cfif "" neq stec_mysql_search_results.next_run>0<cfset temp_next_run = stec_mysql_search_results.next_run MOD 4><cfswitch expression="#temp_next_run#">
<cfcase value="1">3</cfcase>
<cfcase value="2">6</cfcase>
<cfcase value="3">9</cfcase>
<cfcase value="4">12</cfcase>
</cfswitch>-<cfif 4 lt stec_mysql_search_results.next_run>#year(now())+1#<cfelse>#year(now())#</cfif></cfif> </td>
Here is the output when you view source:
<td style="white-space: nowrap;"> 07-16-2012 </td>
<td style="white-space: nowrap;"> 0-2012 </td>
The key to the problem is your code is expecting 12 mod 4 to give 4, when it gives 0.
The code you've provided has been formatted with hardly any line-breaks in, which is a stupid way of writing code because it makes it very difficult to maintain (in terms of readability, modification, and even simple revision comparisons), especially when later developers have to come along and understand what's going on.
Make sure you use newlines - particularly if that means fixing code written by others. If the output of whitespace is an issue then the ideal solution is generally to put the logic in a function (and use output=false), though you can also use <cfsilent>..</cfsilent> blocks, appropriately placed comments <!--- --->, and other means.
Here is the relevant part of your code translated to something actually readable:
<cfif "" neq stec_mysql_search_results.next_run>
0
<cfset temp_next_run = stec_mysql_search_results.next_run MOD 4>
<cfswitch expression="#temp_next_run#">
<cfcase value="1">3</cfcase>
<cfcase value="2">6</cfcase>
<cfcase value="3">9</cfcase>
<cfcase value="4">12</cfcase>
</cfswitch>
-
<cfif 4 lt stec_mysql_search_results.next_run>
#year(now())+1#
<cfelse>
#year(now())#
</cfif>
</cfif>
The 0 you are seeing in your results is the hard-coded one just inside the cfif.
Because the switch doesn't have a case for 0 it is not outputting anything.
To make the existing code work, just change the cfcase for 4 to 0.
However, since this is dealing with quarters, I don't think you're calculating what you mean to be.
Here is what simply changing the cfcase from 4 to 0 would result in...
January = January
February = February
March = March
April = December
May = January
June = February
July = March
August = December
September = January
October = February
November = March
December = December
When what you probably want is this:
January = March
February = March
March = March
April = June
May = June
June = June
July = September
August = September
September = September
October = December
November = December
December = December
Which can be done really simply with 3*ceiling(next_run/3).
If this assumption is correct, there's a significantly better way to write your code:
<td>#calculateNextRunQuarter(stec_mysql_search_results.next_run)#</td>
<cffunction name="calculateNextRunQuarter()" returntype="String" output=false>
<cfargument name="NextRunMonth" type="Numeric" required />
<cfset var Quarter = 3*ceiling(Arguments.NextRunMonth/3) />
<cfset var TheYear = Year(Now()) />
<cfif Arguments.NextRunMonth GTE 4 >
<cfset TheYear = TheYear + 1 />
</cfif>
<cfreturn Right('0'&Quarter,2) & '-' & TheYear />
</cffunction>
And because the logic is all inside a function with output=false there's no stray whitespace and the code is still perfectly readable
cfcase will accept a list, maybe you're over complicating it, why not do this:
<cfswitch expression="#stec_mysql_search_results.next_run#">
<cfcase value="1,2,3">3</cfcase>
<cfcase value="4,5,6">6</cfcase>
<cfcase value="7,8,9">9</cfcase>
<cfcase value="10,11,12">12</cfcase>
</cfswitch>
What is the quickest way in ColdFusion to get first and last day of quarter?
There doesn't seem to be a built in function for this.
First day of quarter:
FirstDayOfQuarter = CreateDate(year, (quarter-1)*3 + 1, 1)
Last day of quarter:
LastDayOfQuarter = DateAdd("d", -1, DateAdd("m", 3, FirstDayOfQuarter))
I have a feeling that your question might be more complex that it appears... for most purposes these values are a known set - no need to calculate:
Quarters:
January 1 - March 31
April 1 - June 30
July 1 - September 30
October 1 - December 31
Since the set is known in advance there's no real need for a function for this - determine in which date a quarter falls is a simple series of "if" statements (psuedocode):
if date > Oct 1 then Q4 else
if date > Jul 1 then Q3 else
if date > Apr 1 then Q2 else
if date > Jan 1 then Q1
(You do the check backwards in this case to check for the most restrictive match first. Although, as Kimvais points out, there is a function to do exactly that already in CFML.)
It should be essentilly the same for other "quarter" systems unless those dates are calculated in some way.
If I've missed the mark feel free to add comment to clarify.
The problem is that "quarter" is a relative term, while many organizations follow the default quarter breakdown of a year starting Jan 1 through Dec 31, many other organizations follow other quarters.
For example most retail organizations. Particularly those that depend on Christmas, don't want to be spending time doing end of quarter/year financials in december. They also want the entire holiday season (including the 2 weeks afterwards) on the same books as the rest of the season. So for them the "year" begins Feb 1.
The U.S. federal government and most of the states begin their financial year Oct 1 because of the way the legislature, elections and budgets work.
So a single function that always worked off of just one quarter layout would never work. Any of the functions listed in the other answers are fine I'm sure as long as your program is only dealing with one set. But if your coding a general use application then you may want to make it configurable.
Looks like there is a function for finding out the Quarter, based on this you could hardcode these?
I don't think there are built in functions for this - it's not clear whether you're looking for the numeric day of month or the string day of month (e.g. Monday). Anyway, this may be a little over-the-top - two functions which require an integer quarter value, and return the first and last dates of the quarter for further manipulation:
<cffunction name="QuarterFirstDate" returnType="date">
<cfargument name="quarternumber" required="yes" type="numeric">
<cfargument name="yr" type="numeric" default="2009">
<cfargument name="startmonth" type="numeric" default="1">
<cfset firstDate = DateAdd("m",startmonth-1,CreateDate(yr, ((quarternumber-1)*3)+1, "1"))>
<cfreturn firstDate>
</cffunction>
<cffunction name="QuarterLastDate" returnType="date">
<cfargument name="quarternumber" required="yes" type="numeric">
<cfargument name="yr" type="numeric" default="2009">
<cfargument name="startmonth" type="numeric" default="1">
<cfset lastDate = DateAdd("m",startmonth-1,CreateDate(yr, quarternumber*3, DaysInMonth(CreateDate(yr, quarternumber*3, "1"))))>
<cfreturn lastDate>
</cffunction>
<cfset year = "2009">
<cfset startmonth = "1">
<cfloop index="quarter" from="1" to="4">
<cfoutput>
<h2>Quarter #quarter#</h2>
#DateFormat(QuarterFirstDate(quarter, year, startmonth))#, day #DayOfYear(QuarterFirstDate(quarter, year, startmonth))#, #DayOfWeekAsString(DayOfWeek(QuarterFirstDate(quarter, year, startmonth)))#<br />
#DateFormat(QuarterLastDate(quarter, year, startmonth))#, day #DayOfYear(QuarterLastDate(quarter, year, startmonth))#, #DayOfWeekAsString(DayOfWeek(QuarterLastDate(quarter, year, startmonth)))#<br />
</cfoutput>
</cfloop>
edit: updated to allow a quarter start month to be specified
How about?
<cfset dt = now()>
<cfset DateLastQuarter = DateAdd("m",-3,dt)> <!--- Any date three months ago falls in previous quarter --->
<cfset quarterNumber = (month(DateLastQuarter)-1)\3+1> <!--- range from quarter 1-4 --->
<cfset StartQuarterMonth = (quarterNumber-1)*3+1> <!--- start of quarter month-number where Jan=1 (Mathematical magic) --->
<cfset LastQuarterFrom = CreateDate(year(DateLastQuarter),StartQuarterMonth,1)>
<cfset LastQuarterTo = DateAdd("d",-1,DateAdd("m",3,LastQuarterFrom))> <!--- the day before three months later --->
this above returns the first date in the previous quarter in LastQuarterFrom
and the last date in the previous quarter in LastQuarterTo