views:

273

answers:

3

I'm on SQL Server 2008, using NHibernate as persistence layer (although this problem is purely SQL, I believe).

I've boiled down my problem to the following SQL statement:

SELECT TOP 2
    this_.Id   as Id36_0_,
    this_.Name as Name36_0_,
    ROW_NUMBER() OVER (ORDER BY this_.IsActive) as MyOrder
FROM    Campsites this_
ORDER BY this_.IsActive  /* a bit field */

This is part of the query that NH generates for retrieving a paged result set. The above statement gives me the following result:

Id36_0_ Name36_0_                       MyOrder
9806    Camping A Cassagnau                 1
8869    Camping a la ferme La Bergamotte    2

However, if I omit the ROW_NUMBER() OVER (ORDER BY this_.IsActive) - which is what NH generates for retrieving results on the first page - I get two completely different table entries in my result:

SELECT   TOP 2
    this_.Id   as Id36_0_,
    this_.Name as Name36_0_
    /* ROW_NUMBER() OVER(ORDER BY this_.IsActive) as MyOrder */
FROM     Campsites this_
ORDER BY this_.IsActive  /* a bit field */

returns

Id36_0_ Name36_0_
22876   Centro Vacanze Pra delle Torri
22135   Molecaten Park Napoleon Hoeve

This completely confuses me and leads to a bug in our app where I get the same Campsite entry as the first element on the first AND the second page of our search.

Why does the same ORDER BY clause work differently inside the ROW_NUMBER OVER() expression?

+4  A: 

ORDER BY this_.IsActive /* a bit field */

since that is a bit field it can only be 0 or 1...I assume you have many rows with this bit field being 0 or 1 ordering it by that doesn't make sense, what if 90% is active...you are not really ordering correctly in that case because you don't have a second ordering.

why don't you pick something that is unique...maybe his_.Name for example

or what about this?

ROW_NUMBER() OVER (ORDER BY this_.IsActive, this_.Name) 
SQLMenace
Of course, you're right. Most of my Campsites are active - so even 99% of them have the value 1. Still, sometimes I want to order by a (different) bit field to get e.g. first all Campsites with a certain attribute and then the rest. As from what I now understand, I need to use a second ORDER BY criterion.
Oliver
+3  A: 

It's basically random in both instances because a bit field is bad for any ordering (as SQL Menace noted). They are separately evaluated by the DB Engine because they have nothing to do with each other.

Note:

  • The internal ORDER BY only applies to the ROW_NUMBER() value ordering.
  • Your output ORDER BY is only this_.IsActive
gbn
Thanks for the insight. This makes sense. So my question really should be: why does NHibernate do it like that? Should I open a new question for that?
Oliver
I'd open a new question. It's a NHibernate question, not SQL then. it is odd though if this is what NHibernate does, unless it sorts client-side using the new column. But this is basic SQL stuff though in most DB engines.
gbn
+3  A: 

You expect the result to be ordered by Name too, but only have IsActive in the ORDER BY clause.

The nature of SELECT is set-based, so you should not rely on arbitrary (but seemingly correct) ordered results of your query if you do not explicitly define the order.

devio
Thanks for your answer, devio. Good you mentioned SET-based, bc now it makes a lot of sense that an ORDER BY <bit> returns an unpredictable order of results (within each value, of course).
Oliver