SELECT TOP And ColdFusion Query Of Queries

Posted November 28, 2006 at 5:00 PM by Ben Nadel

Tags: ColdFusion, SQL

NOTE: Please disregard the following post. It is solved using a CFQuery Attribute, MAXROWS, that I didn't know about. (Thanks Joe!)... you think you know a language and them BLAM! You don't.

Using the SELECT TOP directive of a SQL statement is a nice way to limit the number of records that are returned from the database. Unfortunately (as far as I can see), ColdFusion Query of Queries (QoQ) do NOT support the SELECT TOP directive. There is, however, a fairly easy way to mimic this using the Java methods of the ColdFusion query record set. This is not officially supported:

  • <!--- Create movie query. --->
  • <cfset qMovie = QueryNew(
  • "name",
  • "CF_SQL_VARCHAR"
  • ) />
  •  
  • <!--- Add movie rows. --->
  • <cfset QueryAddRow( qMovie, 10 ) />
  •  
  • <!--- Set query data. --->
  • <cfset qMovie[ "name" ][ 1 ] = "Terminator" />
  • <cfset qMovie[ "name" ][ 2 ] = "Terminator 2" />
  • <cfset qMovie[ "name" ][ 3 ] = "Terminator 3" />
  • <cfset qMovie[ "name" ][ 4 ] = "Predator" />
  • <cfset qMovie[ "name" ][ 5 ] = "Twins" />
  • <cfset qMovie[ "name" ][ 6 ] = "Read Head" />
  • <cfset qMovie[ "name" ][ 7 ] = "True Lies" />
  • <cfset qMovie[ "name" ][ 8 ] = "Eraser" />
  • <cfset qMovie[ "name" ][ 9 ] = "Kindergarten Cop" />
  • <cfset qMovie[ "name" ][ 10 ] = "Pumping Iron" />
  •  
  • <!--- Select the movies. --->
  • <cfquery name="qSubMovie" dbtype="query">
  • SELECT
  • name
  • FROM
  • qMovie
  • ORDER BY
  • name ASC
  • </cfquery>
  •  
  •  
  • <!---
  • Get the TOP 3 movies. We only need to do this if the
  • record set is GREATER than 3 records long.
  • --->
  • <cfif (qSubMovie.RecordCount GT 3)>
  •  
  • <!---
  • Remove all rows beyond 3 (index 3 and
  • greater from the Java stand point).
  • --->
  • <cfset qSubMovie.RemoveRows(
  • JavaCast( "int", 3 ),
  • JavaCast( "int", qSubMovie.RecordCount - 3 )
  • ) />
  •  
  • </cfif>

If you are not comfortable with this, you could manually build the second query and then add the rows, but that is pain. And, to get that to work, you have to run a Query of Queries anyway in order to get any WHERE or ORDER criteria to work. At that point, why go through the hassle of doing any more manual work than in necessary.

If you do go this way, you might want to hide the implementation into a user defined function such as QueryTrim():

  • <cffunction
  • name="QueryTrim"
  • access="public"
  • returntype="query"
  • output="false"
  • hint="Trims a query to the number of rows requested.">
  •  
  • <!--- Define arguments. --->
  • <cfargument name="Query" type="query" required="true" />
  • <cfargument name="RecordCount" type="numeric" required="true" />
  •  
  • <!--- Check to see if we have rows to remove. --->
  • <cfif (ARGUMENTS.Query.RecordCount GT ARGUMENTS.RecordCount)>
  •  
  • <!--- Trim the recordset. --->
  • <cfset ARGUMENTS.Query.RemoveRows(
  • JavaCast( "int", ARGUMENTS.RecordCount ),
  • JavaCast( "int", (ARGUMENTS.Query.RecordCount - ARGUMENTS.RecordCount) )
  • ) />
  •  
  • </cfif>
  •  
  • <!---
  • Return the updated query. This is NOT required as
  • the query object is passed by reference, not by value.
  • However, this would be useful to do as it allows for
  • method chaining.
  • --->
  • <cfreturn ARGUMENTS.Query />
  • </cffunction>

You would then call this as follows:

  • <!--- Trim query. --->
  • <cfset QueryTrim(
  • qSubMovie,
  • 3
  • ) />

Not only is this perhaps easier to read and less work, it allows you to change the implementation of the way the SELECT TOP mimicry works. Personally, I think it would be great for them to just build SELECT TOP into the ColdFusion query of queries (how hard could it be?). But, until then, this has worked very nicely for me.



Reader Comments

Nov 28, 2006 at 6:01 PM // reply »
9 Comments

Hey Ben,

Is there a reason why you'd do this and not use MAXROWS on the QoQ, such as:

# <cfquery name="qSubMovie" dbtype="query" maxrows="10">
# SELECT
# name
# FROM
# qMovie
# ORDER BY
# name ASC
# </cfquery>

-Joe


Nov 28, 2006 at 6:03 PM // reply »
11,238 Comments

Yeah, cause I don't think I even knew there was a MAXROWS attribute ;)

Thanks Joe! Man, I wish knew all the ins an outs of the tags.


Nov 28, 2006 at 9:28 PM // reply »
9 Comments

Heheh...no worries! I can't tell you how long I used replaceNoCase(someList, ",", "','", "all") before I realized ListQualify() existed.

My rule of thumb for CF: if there's a common task that you'd like to implement code to accomplish, it's probably in the library.

-Joe


Nov 29, 2006 at 7:30 AM // reply »
11,238 Comments

Yeah, ColdFusion is so freakin' cool. I just never needed to use MAXROWS before (that I can remember) for standard queries as I could always just use TOP. This gives me something nice to bring up in next week's Staff Meeting (yeah, I like to share the knowledge).

On an unrelated topic, I am reading your article on Model-Glue Fundamentals in the Fushion Authority Quarterly. Very nice. So was the article on Mach-ii by Matt Woodward. The both of you have made these frameworks much clearer. I have looked at them before online, but for some reason never could bridge some knowledge gap. These articles, somehow, got me there. I get it now :) Not that I understand it all, but some things finally clicked. Maybe its the pressure of having to have it ALL in one small article or something... I don't know what it is, but the examples and explanations are just really nice. So, thanks.


Jan 24, 2007 at 2:33 PM // reply »
2 Comments

Ben:

Although it might be unnecessary for what you had in mind, this worked perfectly for something I was working on today! I am taking several similar queries and joining them using a ColdFusion query of queries UNION. But since I cannot do a TOP in the SELECT statement, I used the querytrim() function to remove excess rows from the query before running it through the QoQ.

Thanks!!


Jan 24, 2007 at 2:55 PM // reply »
11,238 Comments

Mark, good stuff!


Cat
May 5, 2008 at 11:11 AM // reply »
2 Comments

Thank you for the post - and the answer! I was encountering the exact same issue, and didn't even think to look at maxrows!

Danke, dahling!

Best wishes,
Cat


Sep 18, 2008 at 11:45 AM // reply »
1 Comments

Why don't you use your SQL statement, this is much more flexible

SQL:
select TOP [3] {*} from tbl_name

The number in the brackets [ ] can be any number, and you can either select { * } or replace it with specific column names and other SQL.


Sep 18, 2008 at 11:48 AM // reply »
11,238 Comments

@Eric,

Agreed! However, this would be useful (MAXROWS) when you have working with an existing queries (ex. one that comes back from a service object).


Jan 20, 2009 at 6:24 PM // reply »
9 Comments

I would like to see TOP added to QoQ. Today I am working on getting at least 5 search results in a search query. If we return less than that, I remove some of the users criteria and search again. But I want to hang on to the 2 (or however many) results that DID come back with too-restictive search criteria.

My plan was to use QoQ to UNION it all together, but since I can't say TOP 3 in the second, less restrictive query (to equal 5 total), I don't think this will work.

I could put them all together and THEN limit it using maxrows, but I'm not sure if the ordering will be correct.


Jan 20, 2009 at 9:36 PM // reply »
11,238 Comments

@Ryan,

I would suggest the MaxRows technique with the UNION. I cannot be certain, but I would bet that the order you are looking for will be retained. I would give it a test before you discount it.


Oct 1, 2009 at 12:35 PM // reply »
2 Comments

Just wanted to say thanks for the website. This is probably the one hundredth time it has saved me hours of searching.


Oct 1, 2009 at 1:31 PM // reply »
11,238 Comments

@Brian,

Always glad to help, or at least to provide a platform for some great conversation.


Dec 23, 2009 at 9:12 AM // reply »
39 Comments

Oh yeah! MAXROWS!
Now why didn't I think of that?


Jul 13, 2011 at 7:13 AM // reply »
4 Comments

Pretty old post, just wanted to point out that the maxrows attribute should never ever be used except in QoQ as it causes a *huge* overhead (as coldfusion is known to be one huge mess on the back-end).


Aug 16, 2011 at 2:12 PM // reply »
1 Comments

I have a repetitive task that will crash without scoping everything. How can I change the starting row? For instance, if I could use limit in a QoQ it would look like this:

  • <cfloop from="0" to="#n-1#" index="i">
  • <cfquery name="get_500_at_a_time" dbtype="query">
  • SELECT * FROM table LIMIT (#i#*500), 500
  • </cfquery>
  • </cfloop>


May 6, 2012 at 12:13 PM // reply »
4 Comments

The following works as I wanted. But only for the FIRST OrgID (the CFOUTPUT proves there are 2).

Any ideas?

best, paul

<!--- Create arrays. --->
<cfset ID_Array2 = ArrayNew(1)>

<!--- Make a query. --->
<cfset GetListingsInOneClass2 = QueryNew("")>

<cfset IDD="0">
<cfloop LIST="#ValueList(GetDistinctOrgIDsInOneClass.OrgID)#" INDEX="IJK">
<cfset IDD=IDD+1>

<cfset IJKL = GetDistinctOrgIDsInOneClass.OrgID[#IDD#] >

<cfoutput>#IJKL#</cfoutput><br><br>

<cfquery name="qSub" dbtype="query" maxrows="1" >
SELECT ID
FROM GetListingsInOneClass
WHERE OrgID = #IJKL#
ORDER BY DateOfData DESC
</cfquery>

<cfset ID_Array2[#IDD#] = qSub.ID[IDD] >

</cfloop>

<cfset nColumnNumber1 = QueryAddColumn(GetListingsInOneClass2, "ID",
"Integer", ID_Array2)>


May 6, 2012 at 7:03 PM // reply »
4 Comments

The above app is for Admin purposes only, not for the general public. So it doesn't have to be efficient.

I'm thinking the easy way, code-wise, might be to put the data in a SQL Server Table.

Then one query could do the job.

best, paul


May 6, 2012 at 10:01 PM // reply »
4 Comments

I found the problem in the above.

<cfset ID_Array2[#IDD#] = qSub.ID[IDD] >

should have been:

<cfset ID_Array2[#IDD#] = qSub.ID >

best, paul



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 19, 2013 at 2:31 PM
My Experience With AngularJS - The Super-heroic JavaScript MVW Framework
It's funny really just how well that image describes the way I would imagine most people that go with angular for some project is. I have had a similar roller-coaster ride with it as well, but not qu ... read »
May 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools