YANQ (Yet Another Newbie Question): Ordered entries in a database

I know this is kinda basic, but who else could I ask besides you folks?

Is there a standard SQL way to indicate that the records in a database
should always be returned sorted by a particular column?

Is there a standard (or better) Rails way to indicate the same thing?

Is there a non-standard way to do this specific to Sqlite3, MySQL, etc... ?

Yes, I know I can do a:

parts = Part.find(:order => :number)

whenever I want to retrieve a list of parts from my db, but the spirit
of DRY doesn't seem to be appeased when I find myself writing this
_everywhere_ I fetch parts.

I suppose I could write a specific class method for my Part model, or
perhaps I could even override the default #find method, but I started
wondering if, perhaps, there was a standard SQL way, standard Rails
way, or nonstandard db-specific way, to indicate that I always want
records returned from my Parts table to be sorted by part number.

--wpd

See:
<http://ryandaigle.com/articles/2008/11/18/what-s-new-in-edge-rails-default-scoping>

Thanks! That's just what I was l looking for.

I still wonder if there is some way to optimize this at the database
-- If I know that I'm always going to return records sorted in a
certain order, perhaps the database engine could do something to
optimize for this. I have heard the term "index" used in the context
of database engines... perhaps I should look into what that means and
whether or not it is the sort of magic that is supposed to apply to
this situation.

In the mean time, I'll start playing with #default_scope, assuming
it's present in 2.3.4.

--wpd

Thanks! That's just what I was l looking for.

I still wonder if there is some way to optimize this at the database

... I have heard the term "index" used in the context
of database engines... perhaps I should look into what that means and
whether or not it is the sort of magic that is supposed to apply to
this situation.

No, it's not. An RDBMS has no intrinsic sort order, so if what you're
looking for exists at all, it'll be a vendor-specific extension.

In the mean time, I'll start playing with #default_scope, assuming
it's present in 2.3.4.

It is.

And, your database should have an index to match the :order clause of your default_scope

So if you have a Person model and you always want to get them
by :order => 'last_name, first_name'

Then the database ought to have an index, too. In a migration it would look something like:

class AddPeopleNameIndex < ActiveRecord::Migration
def self.up
   add_index :people, [:last_name, :first_name], :name => 'index_people_by_full_name'
end
def self.down
   remove_index :people, :name => 'index_people_by_full_name'
end

(But if you didn't know about database indexes until now, get yourself to some friendly neighborhood documentation ASAP!)

-Rob

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com

Is there a non-standard way to do this specific to Sqlite3, MySQL, etc... ?

You can use a view:

http://dev.mysql.com/doc/refman/5.0/en/create-view.html

This is supported with slightly varying syntax by Oracle, MSSQL,
MySQL, and PostgreSQL. I can't remember if AR support for views has
been added to any newer version of Rails yet, but here is a gem I have
used in the past:

http://activewarehouse.rubyforge.org/rails_sql_views/

There are some caveats and gotchas, but as long as your query is read-
only data you should be fine. Another option is to hack the Rails core
MySQL (or database-specific) adapter and trick AR into seeing views as
tables (though I wouldn't suggest this for any production code).

HTH!

From what I've read, using #default_scope and adding an index to my db
seem to be the way to go. I was looking for some way to tell the db,
"BTW, whenever I grab records from this table, I'm going to want them
sorted by the 'number' field, so if there's anything you might want to
do to make that operation go more quickly, you should probably do
that." It seems that adding an index for that field tells the db
engine that there is something special about that field and that it
might want to optimize things to speed up searches (and ultimately
sorts) on that field. Once I've told the db engine about that, then
telling Rails that the default scope should be to sort by that field,
I've gotten where I wanted to get.

Some simple testing shows that the default_scope notion doesn't
propagate to #has_many relationships. For example, if I wanted to
fetch all of my lot records, sorted by the part numbers, then I still
need to specify a sort order if I want the results to be sorted by
part number. Not too surprising...

--wpd

So you can add an :order clause to the has_many relationship:

class Parent
   has_many :children, :order => 'date_of_birth'
end

-Rob

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com