Active Record Query Interface 数据查询接口(界面) 看到第8节。
- http://guides.rubyonrails.org/active_record_querying.html
✅How to find records using a variety of methods and conditions.
✅How to specify the order, retrieved attributes,grouping, and other properties of the found records.
✅ How to use eager loading(预先积极加载) to reduce the number of database queries needed for data retrieval.
✅ How to use dynamic finder methods.
✅ How to use method chaining to use multiple Active Record methods together.
✅ How to check for the existence of particular records
✅ How to perform to do sth useful or difficult various calculations on Active Record models.
✅ How to run EXPLAIN on relations.(如何在关联上跑explain命令)
Active Record will perform queries on the database for you and is compatible(兼容) with most database systems, including MySQL,SQLite ,etc..
1 .Retrieving Objects from the Database
The methods are: find ,where,select,group,20多种。
Finder methods that return a collection, such as where and group, return an instance of ActiveRecord::Relation.
Methods that find a single entity, such as find and first, return a single instance of the model.
The primary operatin of Model.find(options) can be summarized as:
- 根据options转化成SQL语句,激发查询语句并从数据库返回结果
- 从数据库返回的模型的每行结果实例化为相关的Ruby对象
- Run after_find and then after_initialize callbacks, if any.
1.1Retrieving single objects
1.11 find
通过指定primary key来检索object。可以同时检索多个primary key ,并返回一个数组,数组内包含所以匹配的记录。例子:
client = Client.find([1,10]) //或者写Client.find(1,10)
#=> [#<Client id: 1, first_name: "Lifo">, #<Client id: 10, first_name: "Ryan">]
等同于:
SELECT * FROM clients WHERE(clients.id IN (1,10))
如果primary key没有匹配的记录,find method会抛出ActiveRecord::RecordNotFound异常
1.12 take(数字)
The take method retrieves a record without any implicit ordering .例子:
参数是几,就返回几条记录。
client = Client.take # => #<Client id: 1, first_name: "Lifo"> |
等同于:
SELECT * FROM clients LIMIT 1 |
如果没有检索到哪怕一条数据就会返回 nil.
1.13 first
find the first record ordered by primary key(default).
如果没有检索到哪怕一条数据就会返回 nil.
可以传入数字参数,根据数字,返回对应的记录数量。
Product.first(2) 等同于
可以和order连用。
first! ,if no matching record is found, it will rasie ActiveRecord::RecordNotFound
1.14 last
用法和first一样,sql语句是按照 DESC 降序排列。
1.15 find_by
finds the first record matching some conditions.例子:
Client.find_by first_name: 'XXX'
等同于
Client.where(first_name: 'xxx').take //take是取where找到的第一个数据。
1.2 Retrieving Multiple Objects in Batches
分批取回大量对象,多次检索,每次检索的记录数量有限制。默认1000条。
当dadabase非常大的时候,User.all.each 。。end 会占用超大内存,和时间。所以Rails提供了2个method:
find_each和find_in_batches,1000条以上记录,用这个比较好。batch processing 批处理
1.2.1 find_each 方法
User.find_each(可选参数) do |user| NewsMailer.weekly(user).deliver_now end |
有3个options for find_each:
- :batch_size: 指定每次检索返回多少条数据.
- :start and :finish 根据primary id,确定开始和结束。
find_in_batches()方法,和find_each方法的区别
find_in_batches()每次返回的是一个数组,里面是模型对象的集合。
find_each()每次返回的是独立数量的模型对象,没有用数组括起来。
2 conditions --where()
不要用pure string,容易被injection exploits.注射攻击剥削。
㊗️:find和find_by method在ruby和rails 中已经自动可以规避这个问题。
攻击方法:在where的查询中添加一些string(有多种方法),来绕过登陆验证,获取数据 。
⚠️ :where, find_by_sql, connection.execute()等条件片段的查询,需要手动避免注入。 好的方法就是只用数组,或hash.
Returns a new relation, which is the result of filtering the current relation according to the conditions in the arguments
2.2 Array Conditions
Clinet.where("orders_count = ?", params[:orders])
Client.where("orders_count = ? AND locked = ?", params[:orders], false)
placeholder, 可以在条件字符串中指定keys,之后附加相关的keys/values对儿。
Client.where("created_at >= :start_date AND created_at < :end_date", {start_date: params[:start_date], end_date: params[:end_date]})
2.3 Hash Condititons 具体看api
可以用Equality Conditions,Range Conditions, Subset Conditions.
Client.where(locked: true)
-> select * from clients where(clients.locked = 1)
Client.where(created_at: (Time.now.midnight - 1.day)..Time.now.midnight)
->SELECT
*
FROM
clients
WHERE
(clients.created_at
BETWEEN
'2008-12-21 00:00:00'
AND
'2008-12-22 00:00:00'
)
Client.where(orders_count: [1,3,5])
-> SELECT
*
FROM
clients
WHERE
(clients.orders_count
IN
(1,3,5))
在 belongs_to relationship, an association key can be used to specify the model if an ActiveRecord object is used as the value.
for example:
author = Author.find(1); // author 被定义为一个关联的对象
Post.where(author_id: author) //也可以写成:where(author: author) 但前者容易理解。
NOT
Client.where.not(locked: true)
-> select * from clients where(clients.locked != 1)
OR
Client.where(locked: true).or(Client.where(orders_count: [1,3,5]))
->select * from clients where(clients.locked = 1 or clients.orders_count in (1,3,5))
3 Ordering
Client.order(created_at:
:desc
)
相当于MySQL:
SELECT * from client ORDER BY created_at ASC;
Client.order("orders_count ASC").order("created_at DESC")
-> select * from clients order by orders_count asc, created_at desc
4 Selecting Specific Fields
select用于从结果集中选择字段的子集,就是只捞出column "vewable_by"和“locked”的值,其他列不捞出。
Client.select( "viewable_by, locked" ) |
等同于
SELECT viewable_by, locked FROM clients |
5 Limit and Offset
You can use limit to specify the number of records to be retrieved,
Client.limit(5) 等同于 SELECT * FROM clients LIMIT 5
如果使用offset
Client.limit(
5
).offset(
30
)将返回5条记录,从31st开始。
⚠️ :用offset必须先用limit
6
To apply a Group by clause to the SQL fired by the finder, you can use the group method.
Order.select("date(created_at) as ordered_date, sum(price) as total_price").group("date(created_at)")
->
select date(created_at) as ordered_date, sum(price) as total_price FROM orders GROUP BY date(created_at)
7 Having方法
用having进行group by的条件限制。例子:
Order.select( "date(created_at) as ordered_date, sum(price) as total_price" ). group( "date(created_at)" ).having( "sum(price) > ?" , 100 ) |
等同于:
SELECT
date
(created_at)
as
ordered_date,
sum
(price)
as
total_price
FROM
orders
GROUP
BY
date
(created_at)
HAVING
sum
(price) > 100
This returns the data and total price for each order object, grouped by the day they were created and where the price is more than $100.
上面的语句返回每个order对象的日期和总价,查询结果按照日期分组并排序(合并?),并且总价需要大于100.
8 Overriding Conditions 覆盖条件(对条件进行限制)
8.1 unscope
移除指定的条件。
Article.where(
'id > 10'
).limit(
20
).order(
'id asc'
).unscope(
:order
)等同于:
SELECT * FROM articles WHERE id > 10 LIMIT 20 |
8.2 only
指定用哪个查询条件。 和unscope正相反。
8.3 reorder :
The reorder method overrides the default scope order.当建立了一个一对多关联并指定排列的顺序后,想要在查询某个一对多的对象的实例上从新排序(不使用在model中申明的):可以用reorder.
class Article < ApplicationRecord has_many :comments , -> {order( 'posted_at DESC' ) } end Article.find( 10 ).comments.reorder( 'name' ) |
SQL语句会被执行executed:
SELECT * FROM articles WHERE id = 10 SELECT * FROM comments WHERE article_id = 10 ORDER BY name |
8.4 reverse_order 配合reorder或者order,升序变降序。
9 Null Relation
Article.none # returns an empty Relation and fires no queries.返回nil, [] |
当一个对象被设置为只读,他的属性不能被修改。
client = Client.readonly.first
client.visits += 1
client.save #这时会报错❌,raise ActiveRecord::ReadOnlyRecord exception
积极锁,和消极锁。 防止在数据库更新时,出现混乱情况。
(没仔细看。)
积极锁允许多个用户同时更新同一条记录,并假定产生数据冲突的可能性最小。其原来是检查读取记录后看是否有其他进程尝试更新记录,如果有就抛出异常。
为了使用乐观锁,表格有一个整数型字段lock_version。每次记录更新,会同步增加这个字段的值。 如果更新请求中字段的值比当前数据库的字段的值小,更新请求失败,抛出异常。
抛出异常后,需要救援异常并处理冲突,或回滚或合并或使用其他逻辑来解决冲突。
12 Joining Tables 联结表
连个方法:
- joins: 对应SQL的 INNER JOIN ...ON
- left_outer_joins: 对应LEFT OUTER JOIN
1 使用字符串 SQL 片段
Author.joins("INNER JOIN posts ON posts.author_id = authors.id")
->
SELECT authors.* FROM authors INNER JOIN posts ON posts.author_id = authors.id
2 使用 Array/Hash of Named Associations使用具名关联数组或散列
如果连个model已经建立了关联:
Category.joins(:articels)
-》
select categories.* from categories inner join articles on articles.category_id = categories.id
会返回一个包含category 对象的数组,如过有多个article和一个category关联,则返回的这个数组中会出现多次这个category对象。
可以附加destinct方法 ,这样重复的category对象不会出现了。
3. 多个关联的联结
category has_many :articles
articles has_many :comments
Article.joins(:category, :comments)
->
select articles.* from articles
inner join categories on articles.category_id = categories.id
inner join comments on comments.artice_id = articles.id
解释:把属于某个目录并至少有一条评论的文章作为一个Article对象返回。
同样,拥有多个评论的一篇文章会在Article对象的数组中出现多次。
4单层嵌套关联的联结⚠️ 没细看
Article.joins(comments: :guest)
5 为joining table 指明条件
可以使用array, string条件 作为关联数据表的条件。
散列需要特殊的语法:
time_range = (Time.now。midnight - 1.day)..Time.now.midnight
Client.joins(:orders).where("orders.created_at" => time_range)
或者
Client.joins(:orders).where(orders: {created_at: time_range})
select clients.* from clients
inner join orders on clients.order_id = orders.id
where orders.created_at between "XXX时间" and "xxx时间"
解释:查找昨天创建过订单的所有客户,在生成的SQL中使用了between..and..
13 Eager Loading Associations
一种查找机制:目的是减少查询数据库的次数。
client has_one :address
clients = Client.limit(10)
clients.each do |c|
puts c.address.postcode
end
先查询10条clients记录,然后每条记录执行关联查询,一个调用了数据库11次。
为了提高效能:使用includes()方法。
clients = Client.includes(:address).limit(10)
这行代码执行了2次数据库。
1. select * from clients limit 10
2. select addresses.* from addresses where(addresses.client_id IN (1,2,3,..10))
把常用的查询定义为方法,可以在关联对象或模型上作为方法调用。
总会返回一个ActiveRecord::Relation object
scope :published, -> {where(published: ture)}
完全等同于类方法:
def self.publish
where(published: true)
end
在作用域中可以链接其他scope。
如:
Article.published #作为类方法使用
category.articles.published #在关联对象上调用。
14.1 传递参数。
scope :created_before, ->(time) {where("created_at < ?", time)}
14.2 可以在{}内使用 if.
谨慎使用,如果if 的结果是false,会返回nil,并导致NoMethodError❌
14.3 默认作用域
default_scope:
在模型的任意查询中会自动附加上默认作用域、
default_scope {where("removed_at IS NULL")}
⚠️更新记录时,不会加上这个方法。
⚠️default_scope方法总在自定义的scope和where方法前起作用
14.4 合并作用域
两个scope连接起来,相当于使用了AND来合并作用域。
14.5 unscoped方法:删除所有的作用域。
Client.unscoped.all只执行常规查询 -》 select * from clients
Client.where(published:false).unscoped.all
不会执行where条件查询,把where当成了scope.
15 Dynamic Finders
find_by_*()方法。其实就是find_by(key/value)
16 enum
给一个类型是integer的列,指定一组值作为选项。
create_table :conversations do |t|
t.column :status, :integer, default: 0
end
class Conversation < ActiveRecord::Base
enum status: { active: 0, archived: 1 }
end
17. Understanding the chain方法链连接多个ActiveRecord方法。
Person
.select('people.id, people.nam')
.joins(:comments)
.where('comments.created_at > ?', 1.week.ago)
等同
SELECT people.id, people.name
FROM people
INNER JOIN comments ON comments.people_id = people.id
WHERE comments.created_at > "2015-01-01"
19 可以使用完全的SQL:
find_by_sql() ,返回对象的数组。
sellect_all(),和find_by_sql()是近亲,区别是返回的是散列构成的数组,每行散列表示一条记录,没有被实例化。
pluck(),返回查询字段的值的数组。
Client.where(active: true) .pluck(:id)
-> select id from clients where active =1 #=> [1, 2, 3]
pluck()方法相当于使用select().map{|x| x.attr}
Client.select(:id, :name).map{|c| [c.id, c.name]}
-> Client.pluck(:id, :name)
⚠️,pluck()返回的是数组,所以不能放在查询方法链的中间,只能放置在最后。
20 ids方法
获得关联的所有ID, 数据表的primary_key
collection_singular_ids 这是has_many中的选项。返回关联对象的id的数组。\
@book_ids = @author.book_ids
21 exists?()方法,看是否存在记录。
也可以拥有关联记录collections.exists?()
也可以用于表的查询: 返回true/false,可以接受多个参数,
Client.exists?(1) #id等1的客户是否存在。
any? 是否存在一条记录
many? 是否存在2条(含)以上的记录。
21 calculation
Client.count
-> select count(*) as count_all from clients 算有多少条记录
Client.where(first_nam: "Tom").count
-> select count(*) as count_all from clients where(first_name = 'Tom')
算名字是Tom 的记录的数量。
Client.count(:age),返回有age字段的记录的数量
Client.average("orders_count") , 返回字段的平均值
Client.minimum("age")
Client.maximum("age")
Client.sum("orders_count")
Active Record Query Interface 数据查询接口(界面) 看到第8节。的更多相关文章
- 阶段5 3.微服务项目【学成在线】_day09 课程预览 Eureka Feign_10-课程详情页面静态化-课程详情模型数据查询接口
根据课程详情页面写一个获取数据模型的接口 目录的数据来自于课程计划表 右侧是课程的图片 需要写一个接口 获取课程相关的所有信息. 所以就需要一个模型类,里面包含了基本信息.图片信息.等各种详情页面的信 ...
- Active Record 数据库模式-增删改查操作
选择数据 下面的函数帮助你构建 SQL SELECT语句. 备注:如果你正在使用 PHP5,你可以在复杂情况下使用链式语法.本页面底部有具体描述. $this->db->get(); 运行 ...
- Android开源库--ActiveAndroid(active record模式的ORM数据库框架)
Github地址:https://github.com/pardom/ActiveAndroid 前言 我一般在Android开发中,几乎用不到SQLlite,因为一些小数据就直接使用Preferen ...
- Dynamics CRM 2015/2016 Web API:新的数据查询方式
今天我们来看看Web API的数据查询功能,尽管之前介绍CRUD的文章里面提到过怎么去Read数据,可是并没有详细的去深究那些细节,今天我们就来详细看看吧.事实上呢,Web API的数据查询接口也是基 ...
- hibernate框架学习第五天:数据查询、投影等
复习day1环境搭建CRUD操作DB6个核心的APIday2TO PO DO 及其状态切换OID 自然主键 代理主键(uuid)一级缓存 Session绑定 load/get关系1对1 1对多(重点) ...
- 架构模式数据源模式之:表数据入口(Table Data Gateway)、行数据入口(Row Data Gateway)、活动记录(Active Record)
一:表数据入口(Table Data Gateway) 表数据入口提供了用于访问单个表或者视图(也包含了联表查询)的所有SQL,通常一个表一个类.其它代码通过它来实现对数据库的交互.基于这个特点,表数 ...
- 2017.2.21 activiti实战--第十三章--流量数据查询与跟踪(一)查询接口介绍及运行时数据查询
学习资料:<Activiti实战> 第十三章 流量数据查询与跟踪 本章讲解运行时与历史数据的查询方法.主要包含三种:标准查询,Native查询,CustomSql查询. 13.1 Quer ...
- Yii Active Record 查询结果转化成数组
使用Yii 的Active Record 来获取查询结果的时候,返回的结果集是一个对象类型的,有时候为了数据处理的方便希望能够转成数组返回.比如下面的方法: // 查找满足指定条件的结果中的第一行 $ ...
- Yii2 三层设计模式:SQL Command、Query builder、Active Record(ORM)
用Yii2也有一段时间了,发现Yii2 Framework对Database的操作有非常良好的结构和弹性. 接下来介绍三种数据库操作方式. SQL Command Level: // Get DB c ...
随机推荐
- git本地分支与远程分支
github上已经有master分支 和dev分支 在本地 git checkout -b dev 新建并切换到本地dev分支 git pull origin dev 本地分支与远程分支相关联 在本地 ...
- linux 中的 vim 设置粘贴板
https://blog.csdn.net/zhangxiao93/article/details/53677764 亲测有效
- js点击什么显示什么的内容,隐藏其它和进度条
点击什么显示什么的内容 <div style="width:200px; height:40px"> <div class="yiji" st ...
- windows下redis 配置文件参数说明
1.先看redis.windows.conf 文件 # Redis configuration file example # Note on units: when memory size is ne ...
- 【数据结构】算法 Maximum Subarray
最大子数组:Maximum Subarray 参考来源:Maximum subarray problem Kadane算法扫描一次整个数列的所有数值,在每一个扫描点计算以该点数值为结束点的子数列的最大 ...
- cookiejar
referer:https://www.cnblogs.com/why957/p/9297779.html文章介绍了四种模拟登陆方法 yield Request()可以将一个新的请求返回给爬虫执行 在 ...
- C# 链表去重 List 一维 二维 分别使用 Distinct() GroupBy() 方法
分别使用List中Distinct(),GroupBy()实现链表的去重. 1.先上效果: 一维链表中分别有元素“aa”,"bb",'aa','aa',"cc" ...
- Javascript基础语法(一)
一.Javascript简介 1. 定义 基于事件和对象驱动,并具有安全性能的脚本语言. 2. 出现背景 上世纪90年代,在美国有出现,当时有上网的环境,并且有网站服务在运行. 注册服务 上图涉及的问 ...
- Hibernate的load和get方法的区别
这次我们聊一下Hibernate3.2 Session加载数据时get和load方法的区别,我总结的如下: 1. 对于get方法,hibernate会确认一下该id对应的数据是否存在,首先在sessi ...
- Java面试题整理---网络篇
1.BIO.AIO和NIO的概念及区别? 2.什么是长连接和短连接? 3.http1.0.http1.1和http2.0的区别? 4.https和http的区别? 5.https的工作原理? ...