ColdFusion Query Maintains Current Row Even When Passed By Reference

Posted February 28, 2007 at 6:31 PM by Ben Nadel

Tags: ColdFusion

I thought about this in the shower this morning (I take showers in the dark - it helps me think). I know that a ColdFusion query object knows what row it is in while being used in a CFLoop, that's obvious. But what happens if a ColdFusion query object is passed to another function in the middle of a CFLoop. Does it maintain the current row? After some quick testing, I can say that's a BIG 10-4, buddy!

I can't believe I never tested this before. This is something that would have been good to know. Why pass around a row index if the Query object is keeping track of it for you?!? To test this, I set up a little function that outputs the data for the current row of the passed in Query object:

  • <cffunction
  • name="OutputQueryRow"
  • access="public"
  • returntype="void"
  • output="true"
  • hint="Outputs the current row of the passed in query.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="Query"
  • type="query"
  • required="true"
  • hint="The query whose row data we are outputting."
  • />
  •  
  • <cfargument
  • name="Row"
  • type="numeric"
  • required="false"
  • default="#ARGUMENTS.Query.CurrentRow#"
  • hint="The row we are going to output (defaults to current row of the passed in query)."
  • />
  •  
  • <!--- Set up local scope. --->
  • <cfset var LOCAL = StructNew() />
  •  
  • <!---
  • Loop over each query column and output both the
  • column name and cell value (in this row only).
  • --->
  • <cfloop
  • index="LOCAL.ColumnName"
  • list="#ARGUMENTS.Query.ColumnList#"
  • delimiters=",">
  •  
  • #LOCAL.ColumnName# :
  • #ARGUMENTS.Query[ LOCAL.ColumnName ][ ARGUMENTS.Row ]#<br />
  •  
  • </cfloop>
  •  
  • <!--- Return out. --->
  • <cfreturn />
  • </cffunction>
  •  
  •  
  •  
  • <!--- Create the test query. --->
  • <cfset qHottie = QueryNew( "" ) />
  •  
  • <!---
  • Now that we have the query, which is currently very blank,
  • we are going to add the test columns to it.
  • --->
  • <cfset QueryAddColumn(
  • qHottie,
  • "name",
  • "CF_SQL_VARCHAR",
  • ListToArray(
  • "Kit,Izzy,Laura,Samantha"
  • )
  • ) />
  •  
  • <cfset QueryAddColumn(
  • qHottie,
  • "best_asset",
  • "CF_SQL_VARCHAR",
  • ListToArray(
  • "Arms,Smile,Legs,Personality"
  • )
  • ) />
  •  
  •  
  • <!--- Loop over the hottie query. --->
  • <cfloop query="qHottie">
  •  
  • <h4>
  • Iteration #qHottie.CurrentRow#
  • </h4>
  •  
  • <p>
  • <!---
  • Output the row values. Notice that we are
  • passing in the query ONLY and not telling
  • it what row to use.
  • --->
  • <cfset OutputQueryRow( qHottie ) />
  • </p>
  •  
  • </cfloop>

You will notice that the ColdFusion user defined function (UDF) takes the query object as well as an optional row index argument. But also notice that I am NOT passing in this row index when invoking the method. Now, take a look at the row index default value; it's defaulting to the CurrentRow value of the passed in query argument. Very slick.

Running the above code gives us:

Iteration 1

BEST_ASSET : Arms
NAME : Kit

Iteration 2

BEST_ASSET : Smile
NAME : Izzy

Iteration 3

BEST_ASSET : Legs
NAME : Laura

Iteration 4

BEST_ASSET : Personality
NAME : Samantha

I love ColdFusion. It's too freakin' cool!

Now, this won't work with a CFScript / FOR loop. The FOR loop inside a script tag does not alter the ColdFusion query object - it merely accesses it by index. This will only work with a CFLoop tag that alters the state of the query object itself. Of course, using the UDF above, you could just pass in the alternate second row index argument if it is being called from within CFScript tags.



Reader Comments

Feb 28, 2007 at 10:11 PM // reply »
27 Comments

Sounds like a solution for nested query loops as well. Access the outter loop row from the inner loop with array notation using outterQuery.currentrow as row number.


Mar 1, 2007 at 7:21 AM // reply »
11,238 Comments

@Daniel,

Exactly!


May 29, 2007 at 9:29 PM // reply »
2 Comments

Hmmm (;
Yamato


Apr 8, 2008 at 8:01 AM // reply »
6 Comments

I've often wanted to work on query rows in custom tags, but today I needed to use a function. I just finished writing out <cfargument name="row"... when I found this post :)

One reason you might want to pass in the row is if you're doing odd/even logic or something that doesn't run in order (for whatever reason), then maybe you'd be better off with myFunction(query, row).

Thanks.


Apr 8, 2008 at 9:32 AM // reply »
11,238 Comments

@Adrian,

Agreed. I think that's why its a good compromise to allow an optional Row argument, but default it to the CurrentRow. Best of both worlds.


Sep 15, 2008 at 12:02 PM // reply »
1 Comments

It seems that currentRow is not being carried over if you pass a query to a function in a different object.


Sep 15, 2008 at 12:30 PM // reply »
11,238 Comments

@Shawn,

That's interesting. I wonder why that would be.


Feb 10, 2010 at 3:14 PM // reply »
8 Comments

Sweet, worked perfectly! Thanks again for doing all the dirty work, Ben :P


Feb 10, 2010 at 10:05 PM // reply »
11,238 Comments

@Jon,

Always glad to help :)


Oct 8, 2010 at 12:55 PM // reply »
1 Comments

This worked great, thanks for the info.


Oct 10, 2010 at 3:48 PM // reply »
11,238 Comments

@Gerry,

Thanks my man. And actually, your comment prompted me to try something else along these same lines. In the example, I'm using a .currentRow property; however, the current row state of the query is maintained implicitly. Take a look at this:

  • <!--- Build a query. --->
  • <cfset girls = queryNew( "" ) />
  •  
  • <!--- Add a column with some default values. --->
  • <cfset queryAddColumn(
  • girls,
  • "name",
  • "cf_sql_varchar",
  • [ "Sarah", "Tricia", "Joanna" ]
  • ) />
  •  
  •  
  • <!---
  • A function that returns the NAME of the query
  • using the implicit row.
  • --->
  • <cffunction name="getName">
  • <cfreturn arguments[ 1 ].name />
  • </cffunction>
  •  
  •  
  • <!--- Try to output each name using the proxy function. --->
  • <cfoutput>
  •  
  • <cfloop query="girls">
  •  
  • #getName( girls )#<br />
  •  
  • </cfloop>
  •  
  • </cfoutput>

When I run this, I get the following output:

Sarah
Tricia
Joanna

As you can see, not only is .currentRow maintained, so is the implicit iterator that allows us to reference column values without any row number.


Nov 17, 2010 at 11:21 AM // reply »
1 Comments

This is beautiful.

But I'm having trouble with the syntax for calling the function if it's in a external cfc.

Wouldn't it be something like
<cfset createObject("cfc.NAME").OutputQueryRow(query_name)>
????


Jan
Aug 10, 2011 at 4:41 AM // reply »
3 Comments

Great post !

I've tried this with with a query-loop in cfscript:

  •  
  • //myQuery has 2 rows. column 'id' is 1 in row 1, and 2 in row 2
  •  
  • while(myQuery.next())
  • {
  • writeOutput("<br />#myQuery.currentRow#: ");
  • outputCurrentRow(myQuery);
  • }
  •  
  • public void function outputCurrentRow(Query myQuery){
  • writeOutput(arguments.myQuery.id);
  • }

this outputs:
1: 1
2: 1

In this case the current row remained the first row of the query. The output for each row was the id of row 1.


Jan 11, 2012 at 10:59 AM // reply »
1 Comments

Thanks Ben! Great post. I've been making this process way too complicated... thank you for simplifying!



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 21, 2013 at 7:46 PM
Using Plupload For Drag & Drop File Uploads In ColdFusion
No luck. At least I have uncovered the cause, URLScan 3.1. Here is what I see in the IIS log when a file is over 30mb. 2013-05-21 23:29:05 10.105.45.128 GET /plupload/assets/jquery/jquery-1.8. ... read »
May 21, 2013 at 6:12 PM
Using Plupload For Drag & Drop File Uploads In ColdFusion
Ben, I did not see you after Pete Freitag's Lockdown session at cfObjective but he said that IIS sets file size limits at 30MB by default which just happened to be the threshold for file size when ... read »
May 21, 2013 at 11:51 AM
Ask Ben: Parsing Very Large XML Documents In ColdFusion
Looking at my first ever XML document that I have to parse and put into MS SQL 2000 with CF8. I get it to list the desired Field name, many times over, and have a long list of this field name displa ... read »
May 21, 2013 at 9:25 AM
Turning Off and On Identity Column in SQL Server
you are awesome..i am lucky to get this blog between such a garbage one....Thanks, Prashant ... read »
May 20, 2013 at 4:38 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, Your confusion is well founded, since this is a very confusing features. In fact, it ONLY works if you use array notation. Meaning, that this: arrayToList( query[ "columnName" ] ) ... read »
May 20, 2013 at 4:34 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I was thinking chicken and the egg, I wouldn't have expected it to work in the valuelist going in I guess. Maybe I just need a beer, long day :) ... read »
May 20, 2013 at 4:29 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, That's if you're trying to reference a specific row. In this case, we're trying to reference the entire query column as one cohesive value. So, you are correct that if you wanted to output a ... read »
May 20, 2013 at 4:24 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I thought when you used array notation to reference queries you always had to have the row or it would throw a similar error as well? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools