ColdFusion Query of Queries And Undefined Cell Values

Posted July 17, 2006 at 1:52 PM

Tags: ColdFusion, SQL

I just came across an interesting "Feature" of the ColdFusion query involving null values. As I already knew, you can use the ColdFusion function QueryAddRow() to add records to existing record sets. What I did not realize is that after adding a row, those cells in the new record exist in a sort quasi-null value state.

Take this example for instance, where we create a test query from scratch (the same thing happens if you query directly from a SQL database):

 Launch code in new window » Download code as text file »

  • <!--- Create a test query of sexy body parts. --->
  • <cfset qParts = QueryNew( "id, body_part, weight" ) />
  •  
  • <!--- Add some records to the query. --->
  • <cfset QueryAddRow( qParts ) />
  • <cfset qParts[ "id" ][ qParts.RecordCount ] = 1 />
  • <cfset qParts[ "body_part" ][ qParts.RecordCount ] = "face" />
  • <cfset qParts[ "weight" ][ qParts.RecordCount ] = "60%" />
  •  
  • <cfset QueryAddRow( qParts ) />
  • <cfset qParts[ "id" ][ qParts.RecordCount ] = 2 />
  • <cfset qParts[ "body_part" ][ qParts.RecordCount ] = "butt" />
  • <cfset qParts[ "weight" ][ qParts.RecordCount ] = "20%" />
  •  
  • <cfset QueryAddRow( qParts ) />
  • <cfset qParts[ "id" ][ qParts.RecordCount ] = 3 />
  • <cfset qParts[ "body_part" ][ qParts.RecordCount ] = "legs" />
  • <cfset qParts[ "weight" ][ qParts.RecordCount ] = "5%" />
  •  
  • <cfset QueryAddRow( qParts ) />
  • <cfset qParts[ "id" ][ qParts.RecordCount ] = 4 />
  • <cfset qParts[ "body_part" ][ qParts.RecordCount ] = "boobies" />
  • <cfset qParts[ "weight" ][ qParts.RecordCount ] = "15%" />

For each row that was added, all cells in the record were set. The following query uses the beloved query of queries feature to get all records that have a body part defined:

 Launch code in new window » Download code as text file »

  • <!--- Query for defined parts. --->
  • <cfquery name="qGoodParts" dbtype="query">
  • SELECT
  • id,
  • body_part,
  • weight
  • FROM
  • qParts
  • WHERE
  • <!--- Make sure we only get parts that are defined. --->
  • body_part LIKE '_%'
  • </cfquery>
  •  
  • <!--- Dump out the query. --->
  • <cfdump var="#qGoodParts#" />

This query runs with absolutely no problems. Now, let's add another record but instead of setting all the cells, we are going to leave the BODY_PART field undefined:

 Launch code in new window » Download code as text file »

  • <!--- Add another record to the query. --->
  • <cfset QueryAddRow( qParts ) />
  • <cfset qParts[ "id" ][ qParts.RecordCount ] = 5 />
  • <cfset qParts[ "weight" ][ qParts.RecordCount ] = "5%" />

Notice that in the above query, only ID and WEIGHT are defined, BODY_PART is not. If we try to run that same query of queries that we ran above, we get a the error "Null Pointers are another name for undefined values." If you run it through the CFError handler, it describes the error to be: java.lang.NullPointerException. It's like it won't let me reference the cell since it wasn't explicitly set.

But, if you run the query with no WHERE clause:

 Launch code in new window » Download code as text file »

  • <cfquery name="qGoodParts2" dbtype="query">
  • SELECT
  • id,
  • body_part,
  • weight
  • FROM
  • qParts
  • </cfquery>

... It works absolutely fine. Not only that, you can even use the ORDER BY clause:

 Launch code in new window » Download code as text file »

  • <cfquery name="qGoodParts3" dbtype="query">
  • SELECT
  • id,
  • body_part,
  • weight
  • FROM
  • qParts
  • ORDER BY
  • body_part ASC
  • </cfquery>

... and that works fine. To me, that doesn't make any sense. A WHERE clause will break on an unset value, but an ORDER BY clause will execute quite correctly.

Ok, so let's take it one step further. We are testing on a text field. What happens if we do the same test on the numeric ID field? Let's add another record, but leave the ID field undefined:

 Launch code in new window » Download code as text file »

  • <!--- Add another record to the query. --->
  • <cfset QueryAddRow( qParts ) />
  • <cfset qParts[ "body_part" ][ qParts.RecordCount ] = "hips" />
  • <cfset qParts[ "weight" ][ qParts.RecordCount ] = "5%" />

Now, let's run the ColdFusion query of queries with a reference to the ID field in the WHERE clause:

 Launch code in new window » Download code as text file »

  • <cfquery name="qGoodParts4" dbtype="query">
  • SELECT
  • id,
  • body_part,
  • weight
  • FROM
  • qParts
  • WHERE
  • <!--- Make sure we only get parts have a very small ID. --->
  • id < 3
  • </cfquery>

Again, this runs perfectly fine. Well, sort of; it returns the records with IDs 1 and 2, but it also returns the record with the undefined ID field.

Well, maybe it's not the numeric vs. the text field type. I mean, SELECT doesn't seem to be throwing the error when we remove the WHERE clause. Maybe it's the LIKE statement itself. Let's try running the query of queries using a text comparison other than LIKE:

 Launch code in new window » Download code as text file »

  • <!--- Query for defined parts. --->
  • <cfquery name="qGoodParts5" dbtype="query">
  • SELECT
  • id,
  • body_part,
  • weight
  • FROM
  • qParts
  • WHERE
  • body_part = 'face'
  • </cfquery>

This runs perfectly. No errors, no runtime exceptions. It doesn't even return any undefined row values. So what is it about the LIKE directive of the WHERE clause? There must be some calculations going on under the hood that cannot handle undefined values. I wouldn't say that it's a NULL issue as I have covered in previous posts that while NULL values are not great, they will not throw errors in queries.

As one final test, I tried to run the query if something that would have to do calculations with the numeric ID field. Remember that earlier we added a record with an unset ID field value:

 Launch code in new window » Download code as text file »

  • <cfquery name="qGoodParts6" dbtype="query">
  • SELECT
  • id,
  • body_part,
  • weight
  • FROM
  • qParts
  • WHERE
  • <!--- Force ID to be used in math. --->
  • (id + 1) = 3
  • </cfquery>

Again, no errors. It returns the correct record (ID = 2). Damn you LIKE directive, DAMN YOU! After some more testing, I have found that UPPER() and LOWER() on body_part field cause NULL pointer exceptions on undefined query of query values.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Other Searches  |  Print Page




Reader Comments

Nov 20, 2006 at 12:39 PM // reply »
1 Comments

I suppose you've already found the solution to this, but just in case..

I ran into a similar problem doing some datagrid filtering with query of queries.. a quick summary:

WHERE
lower(somecolumn) like lower('somevalue%')

would yield the nullPointerException if any of the values of somecolumn were null in the original query. To fix it:

WHERE
lower('f'+somecolumn) like lower('f'+'somevalue%')

It works great, but it seems pretty lame that it can add or concatenate a nonnull value to a null value just fine, but it can't compare one? Gar.


Nov 21, 2006 at 7:39 AM // reply »
7,572 Comments

Tim,

That is a most excellent solution! Thanks for posting that. I agree that it is lame that it can concatenate but not compare. ColdFusion query of queries have a bunch of weird bugs, but I still love 'em.

The solution that I have settled on (and this is not always in my control) is just trying never to return a NULL value from the data base except for when absolutely necessary. So, i use things like:

ISNULL( COLUMN_NAME, '' )

So that if the column is NULL at least it returns an empty string instead of a null value. While these are not exactly the same thing, it works nicely. But in cases where this is not possible, i LOVE your solution. Thanks.


TJ
Feb 21, 2008 at 1:37 AM // reply »
1 Comments

This was EXTEMELY helpful....I had the NULL error when trying to use the Q of Q with LIKE...the fix to add on an extra letter to the column and value worked great....Glad to have found a fix after hours of racking my brain!

Thanks


Feb 21, 2008 at 7:16 AM // reply »
7,572 Comments

@TJ,

Glad to help.


May 29, 2008 at 7:29 PM // reply »
11 Comments

Ben,

Have you experienced this on CF8? I get this problem on CF7 with a reporting suite that I built but I haven't tried running the app on CF8 yet. Wondering if there have been any fixes in this area?


May 29, 2008 at 7:34 PM // reply »
7,572 Comments

@Brian,

I have not tried the specifically on CF8. I don't think they updated much query stuff, though.


Aug 4, 2008 at 8:07 AM // reply »
1 Comments

Hi,

I have this same problem with CF8. Thanks for the solutions.

Chris.


May 13, 2009 at 10:23 AM // reply »
3 Comments

Ben,

You stated that you use the following to prevent problems with nulls in the QoQs:

ISNULL( COLUMN_NAME, '' )

Is this a function that you can use within the QoQ itself? Or, in the database, when creating the original query object?


May 19, 2009 at 9:48 AM // reply »
7,572 Comments

@Jason,

I use IsNull() generally at the main SQL level. I am not sure off-hand if it is supported by Query of Queries.


Oct 22, 2009 at 2:43 PM // reply »
56 Comments

I just ran into this old problem again.

I have a massive query with about half of the rows having null data in one of the fields.

Using the like clause %#filter#% on the QoQ was returning all rows with undefined data above the first row that met the like criteria. The remaining rows behaved correctly. i.e. null or not, they were not returned unless the filter matched.

Strange brew.


Oct 31, 2009 at 3:43 PM // reply »
7,572 Comments

@Justin,

That's definitely and odd behavior! ColdFusion query of queries certainly rock, but they can fall short and be very limiting if you don't have the "right" kind of data to work with.


Dec 3, 2009 at 1:12 PM // reply »
7 Comments

Tim, Ben,

Thanks for the help--I was going nuts over this one. Should have Googled sooner!

Ben Nadel to the rescue! (again)


Dec 3, 2009 at 2:25 PM // reply »
7,572 Comments

@Jon,

No worries - I just like that you come visit some time :)


Post Comment  |  Ask Ben

Recent Blog Comments
Mar 20, 2010 at 12:07 PM
Drawing On The iPhone Canvas With jQuery And ColdFusion
Simply awesome. Saved my day. ... read »
Mar 20, 2010 at 9:00 AM
Building A Fixed-Position Bottom Menu Bar (ala FaceBook)
I would like to say thx for an easy way to create a bottom bar. I do have a ?. Is it possible to center the bar if i want to resize it to ex 85%. Regards Offenbach ... read »
Mar 19, 2010 at 7:26 PM
MySQL 3/4 - com.mysql.jdbc.Driver And allowMultiQueries=true
Thank you very much for this post. Adding allowMultiQueries="true" in context.xml didn't help until I added it to url as allowMultiQueries=true Good idea is to use prepared statements and it will he ... read »
Jim
Mar 19, 2010 at 4:49 PM
Nobody Puts Baby In The Corner!
Wow. This is like suddenly finding a support group for your secret shame. I'm not alone! I always liked this movie, even though it is extremely cheesy. I just wish Jennifer Grey hadn't gotten the ... read »
Mar 19, 2010 at 4:47 PM
Application.cfc OnRequest() Method Affects OnError() Arguments
@Jason and @Ben, I've been doing some CF9 refactoring on our systems and noticed an odd occurrence with onError as well. Found a way to work around my problem, but what I saw was... Background: Our ... read »
Jim
Mar 19, 2010 at 4:44 PM
Shoot 'Em Up Starring Clive Owen And Paul Giamatti
I actually enjoyed this movie quite a lot. It was different, certainly, but I think they were going for more of a Quentin Tarentino-"wow, that was weird"-vibe than an actual spoof. Once I realize ... read »
Mar 19, 2010 at 4:34 PM
An Intensive Exploration Of jQuery With Ben Nadel (Video Presentation)
Hey I guess the video is down. Is there anyway you can upload to youtube or vimeo or some other service? Greatly appreciated. ... read »
Mar 19, 2010 at 4:24 PM
ColdFusion CFPOP - My First Look
@Ben Thanks for the follow up! The root of the problem had to do with being able to trace bounced emails to specific records in a DB table. Let's say you run an email campaign and you get 1,000 bou ... read »