首先,理解find(:first,…)方法是非常重要的,该方法在同样的conditions设置下,和find(:all,…)方法生成同样的sql语句,不同之处仅在于只返回一条记录。在调用的时候,一种的参数为:first,另一种为:all。
find方法执行一个select from这样的sql语句,:all标记指定返回表中所有的记录,:first返回第一条记录。但是现在:first还不能保证你得到的就是表中的第一条记录,原因是什么?我们继续往下看。
:conditions参数指定了SQL语句的where部分,可以包含Sql语句或者包含可以替换的参数的名字,值,上一篇我们已经做了了解。
daves_orders = Order.find(:all, :conditions => "name = 'Dave'") name = params[:name] other_orders = Order.find(:all, :conditions => ["name = ?", name]) yet_more = Order.find(:all, :conditions => ["name = :name and pay_type = :pay_type", params])
上面的find方法并不能保证按照特定的顺序返回记录,除非指定查询的排序(order by)部分。:order参数就是用来指定SQL的排序条件的,下面的例子演示了查询名字为Dave的订单,并且按照pay_type,shipped_at字段进行降序排列。
orders = Order.find(:all, :conditions => "name = 'Dave'", :order => "pay_type, shipped_at DESC")
我们还可以设置:limit参数来限制返回的记录数,如果你使用:limit参数,或许还想指定排序条件,下面的例子返回10条记录,并且按照指定条件排序:
orders = Order.find(:all, :conditions => "name = 'Dave'", :order => "pay_type, shipped_at DESC", :limit => 10)
参数:offset经常与:limit参数一同出现,用来指定从第一条记录起,返回指定的偏移量,下面代码演示了:offset参数的使用:
def Order.find_on_page(page_num, page_size) find(:all, :order => "id", :limit => page_size, :offset => page_num*page_size) end
从上面的代码可以看到,这样使用find的场景就是分页显示数据,用pagesize指定每页的记录数,然后由pagenum*page_size指定从第几条开始提取数据。
参数:join用来指定主表和哪些表进行关联查询,:join参数指定的部分会插入到SQL中,下面的代码演示取得一个所有名为“Programing Ruby”的条目的列表:
LineItem.find(:all, :conditions => "pr.title = 'Programming Ruby'", :joins => "as li inner join products as pr on li.product_id = pr.id")
在后面的内容里,我们还会了解更多的进行表关联查询的方法。
现在,我们在来回头看看:all和:first参数,实际上在使用:first参数时,默认的带有参数:limit,只不过:limit参数的值为1。如果你要取得最后一条记录,只需要改变:order里的排序方向为降序。
find方法为我们构建了完整的Sql查询,而方法find_by_sql方法则允许我们对Sql有完整的控制,该方法只有一个参数,就是你想要使用的完整的sql语句,下面是示例代码:
orders = LineItem.find_by_sql("select line_items.* from line_items, orders " + " where order_id = orders.id " + " and orders.name = 'Dave Thomas' ")
现在有一个问题了,就是返回的Model对象中都包含有哪些属性呢?我们使用attributes( ), attribute_names( ), and attribute_present?( )方法来确定在Model对象中都包含有哪些属性,第一个返回一个hash,里面是键值对,第二个返回属性名的数组,第三个判断Model对象中是否含有某个属性,例如:
orders = Order.find_by_sql("select name, pay_type from orders") first = orders[0] p first.attributes p first.attribute_names p first.attribute_present?("address") 程序的结果: {"name"=>"Dave Thomas", "pay_type"=>"check"} ["name", "pay_type"] false
find_by_sql方法也可以用来创建包含有派生(derived)(注1)的Model对象,如果你使用了as XXX 这样的sql来给派生字段一个别名,这个别名会作为Model中的属性名,例如:
items = LineItem.find_by_sql("select *, " + " quantity*unit_price as total_price, " + " products.title as title " + " from line_items, products " + " where line_items.product_id = products.id ") li = items[0] puts "#{li.title}: #{li.quantity}x#{li.unit_price} => #{li.total_price}"
在find_by_sql方法中,我们一样可以使用占位符来给Sql语句传递参数,例如:
Order.find_by_sql(["select * from orders where amount > ?", params[:amount]])