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.
Related
I am reading a spreadsheet any trying to then run it in a query or Queries
<cfspreadsheet action="read"
src="#request.dropfolder##arguments.DSN#"
name="qryFromFile"
excludeHeaderRow="true"
headerrow="true">
<cfquery name="qryResult" dbtype="query">
SELECT EID
, CAST(#arguments.Config[2]# AS Decimal) AS [Value]
, 0 AS Invalid
, '<li><span><b>Comments:</b></span>' + Comments + ' on <time>' + [Date] + '</time></li>' AS Skyhook
FROM qryFromFile
ORDER BY EID
</cfquery>
Do I have to beild the table piece by piece?
To get CF to stuff the contents into a query, you need to use the "query" attribute, not the "name" attribute
<cfspreadsheet action="read"
src="#request.dropfolder##arguments.DSN#"
query="qryFromFile"
excludeHeaderRow="true"
... >
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>
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.
I have 2 Query object in Coldfusion now I want to create a small report on account of these 2 queries
queries may look like
Q1
ID CODE NAME ACTIVE
and
Q2
CODE PRICE BOOKABLE
The code CODE
field is common key between these 2 queries. Now I want to get records are that are in Q1 but not in Q2 and vice versa, how many recodes are common in both queries where CODE is unique.
<cfquery name="Q1" datasource="test">
select * from users where code not in (select code from system)
</cfquery>
<cfquery name="Q2" datasource="test">
select * from system where code not in (select code from users)
</cfquery>
you can use QoQ to solve this.
<cfquery name="Q1" datasource="test">
select * from table1
</cfquery>
<cfquery name="Q2" datasource="test">
select * from table2
</cfquery>
<cfset q1code = valuelist(q2.code,"," )>
<cfset q2code = valuelist(q1.code,"," )>
<cfquery name="q3" dbtype="query" >
select * from q1 where code Not in(#q1code#)
</cfquery>
<cfquery name="q4" dbtype="query" >
select * from q2 where code Not in(#q2code#)
</cfquery>
<cfquery name="q5" dbtype="query" >
select * from q1,q2 where q1.code = q2.code
</cfquery>
Agree with other people, make the DB do the work. If these are in the same db, then you do this to get the records common to both tables:
SELECT Q1.ID
,Q1.CODE
,Q1.NAME
,Q1.ACTIVE
,Q2.PRICE
,Q2.BOOKABLE
FROM Q1, Q2
WHERE Q1.CODE = Q2.CODE
In order to do the first part of your question .. get the records that are in Q1 but not in Q2, you can do that with an outer_join if I am understanding you correctly. Syntax is different for all db's on doing outer joins. I always have to go look it up, so I'm not going to write it here.
another option is to union the two tables, and let cold fusion pull the reports on column_name = ''
select * from Q1 UNION SELECT * FROM Q2
-- you can't actually do this (select *) because of duplicate 'code' column in both dbs.
you'll have to specify the columns explicitly and rename the first one to Q1Code, then Q2Code.
then in CF you do
<cfif q2Code EQ ''> print Q1: #Q1CODE# <cfelse> print Q2: #Q2CODE# </cfif>
or maybe you want:
<cfif q1code EQ Q2code> yay they match</cfif>
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!