I have a model called A with columns col and col2. The col1 has an unique index. (I am using Postgres database.)
class A < ActiveRecord::Base
# id, col1, col2
end
Data:
id col1 col2
== ==== ====
1 2 3
2 3 4
Let us try to find the first row matching the given value in col2 OR col1.
a = A.first(:conditions=> ["col2 = :id OR col1 = :id", {:id => 3}])
# select * from A where (col2 = 3 OR col1 = 3) LIMIT 1
The SQL above returns the row#2 rather than row#1. I suspect the query optimizer chooses to execute col1 = 3 first as col1 has an unique index.
How do I override this behavior? How do I instruct Postgres optimizer to use the existing order for the OR condition?
If you don’t specify an explicit order then first row doesn’t make any sense; the result set from a specific query at a specific moment in time will, of course, have a first row but there is no guarantee that running the same query again with the same data will produce the same first row. Tables in a relational database are not ordered so there is no specified existing order at all. You’re making a bad assumption; the implementation may implicitly order the records by the PK on the disk but there’s no guarantee of that and no guarantee that the next version will behave the same; furthermore, there’s no guarantee that the database will return rows in disk-order, the database is free to order the rows in any way it wants to unless you have specified a specific order with an ORDER BY clause.
If you want an order then you should include an ORDER BY clause; you probably want something more like this:
And if you want to look at
col2beforecol1then you should say so:col2 = :id OR col1 = :idandcol1 = :id OR col2 = :idare equivalent boolean expressions so the database is free to checkcol2 = :idbefore, after, or at the same time ascol1 = :idand it is free to access the rows in any order it pleases.