This content has been marked as final. Show 11 replies
From a syntax perspective, when you loop through a query using cfloop (as opposed to cfoutput), you have to specfify the rownumber. The syntax is queryname.fieldname[rownumber]
Given your ultimate goal, your approach seems way too complicated. The fact that you need 3 queries seems suspicious, but, if they really are necessary, you could alway use Q of Q to combine them into one query. Then you probably would not need an array of structures.
The loop that is causing me problems is over an array (of structs), not a query.
I using a single query to retrieve the data, but ran into problems with that approach, too. I tried to compare the EventInfo.EventType elements with know valid constants, but could never get the results I expected. I figured that the table type I'm using (DBase IV) added some null characters, but haven't been able to prove it.
Dan's right that a query of queries seems like it might be more logical here, but in any event, you're overwriting your array values for each CFLOOP tag. In other words, if you want output from EventQuery2 to append to the array (rather than to overwrite values just set by EventQuery1), you need to ensure that you're dynamically generating a new index position for each iteration, of each CFLOOP occurence in the code block. Ditto for output from EventQuery3 overwriting values set by EventQuery2 (which explains why you can only output values set by EventQuery3).
I thought the lines:
at the end of each loop would be enough to ensure that each array index position was unique. Is there something else I need?
What do you get if you <cfdump var="#EventArray#"> after you are done
building the array.
You may also be running into an pass by reference problem.
When you create the structure with the <cfset EventInfo = StructNew()>
This creates a structure, assignes it some memory and references the
variable name 'eventInfo' to that memory location.
When you then Assign the eventinfo to an element of the eventarray, it
just assigns another pointer to the same memory. So all your eventArray
elements point to the same EventInfo memory location which has the last
set of data in it. I suspect you will see this when you dump the array.
Any time you find yourself repeating blocks of code, alarm bells should go off on your head.
Think modular code and functions! (The previous arguments about Q of Q, etc., are good too.)
Look at the attached code. It:
(1) Works (avoids the pass by reference issue)
(2) Is shorter.
(3) Is modular -- meaning it's easier to maintain.
<CFFUNCTION name="AddEventQryToArray" returntype="array">
<CFARGUMENT name="aTargetArray" type="array" required="yes">
<CFARGUMENT name="qSrcQry" type="query" required="yes"
contain columns: ID, StartDate, and EventType">
<CFSET var zTmpStruct = StructNew()><!--- create struct here --->
zTmpStruct.ID = arguments.qSrcQry.ID;
zTmpStruct.StartDate = arguments.qSrcQry.StartDate;
zTmpStruct.EventType = arguments.qSrcQry.EventType;
ArrayAppend (arguments.aTargetArray, zTmpStruct);
Just to be a bit nitpicky, the function code provide by MikerRoo avoided
the pass by reference problem by defining a new struct with the
structNew function for each iteration of the loop inside the function.
Which is the way I would have done it as well.
But, in order to avoid doing real work, I wanted to point out that with
the small change provide above, this User Defined Function (UDF) would
suffer a similar pass by reference issue. So it was MikerRoo's choice
of where to create a new structure, rather then his choice of doing it
in a UDF that resolved the pass by reference issue.
All other points about using an UDF are very valid.
> From a syntax perspective, when you loop through a query using cfloop (as
> opposed to cfoutput), you have to specfify the rownumber.
No you do not.
On Mon, 02 Oct 2006 13:14:07 -0700, Ian Skinner wrote:
> You may also be running into an pass by reference problem.
Yep. That's what it looks like to me.
> Try this
> <CFSET EventArray[ArrIndex]=dupliate(EventInfo)>
Typo aside, that's pretty much it, I reckon. Although I'd dispense with
maintaining the ArrIndex variable, which can be replaced with simply using
arrayAppend(). The counter seems to be serving no purpose other than
pointing to the end of the array: CF already knows where that is, so
there's no need to keep track of it separately.
I concur with everyone who says the whole construct (ie: the originally
posted code) looks a bit clunky though.
Why are you building an array of identically-keyed structs out of a query,
instead of leaving it as a query? As someone else said, if you MUST have
three separate queries (doubtful), then just QoQ them together. Better
yet, UNION them at database level.
This is the result of "smart" Cold Fusion design, where everything is passed by value, except structures...
Just change your code slightly. Move StructNew() inside the loop like this:
<CFLOOP .. .. .>
. . . . . . . . . . . . . . . .