ruby on rails查詢

find 方法

User.find(id)  => 直接主鍵(id)查詢
User.find(id,id2)  => 查詢多個(gè)

take 方法

User.take(number)  => 返回 number 條數(shù)據(jù)
User.take  => 返回一條數(shù)據(jù) 并無視排序
User.take(2)  => 返回2條數(shù)據(jù)

first 方法

Client.first(number)  => 返回前 number 條數(shù)據(jù)
User.first  => 返回第一條數(shù)據(jù)

PS:first! 方法的行為和 first 方法類似,區(qū)別在于如果沒有找到匹配的記錄,first! 方法會(huì)拋出 ActiveRecord::RecordNotFound 異常。

last 方法

User.last(number)  => 返回后 number 條數(shù)據(jù)
User.last  => 返回最后一條數(shù)據(jù)

find_by 方法

User.find_by nickname: 'cwhh'  => 找到 nickname 是 cwhh 的數(shù)據(jù)

PS:find_by! 方法的行為和 find_by 方法類似,區(qū)別在于如果沒有找到匹配的記錄,find_by! 方法會(huì)拋出 ActiveRecord::RecordNotFound 異常。

find_each 方法

User.find_each do |user|
 p user
end
=>  User 里面所有 user 數(shù)據(jù)
  • :batch_size
User.find_each(batch_size: 5000) do |user|
 p user
end
=> 檢索 5000 條 打印 5000個(gè) user 數(shù)據(jù)
  • :start
User.find_each(start: 主鍵) do |user|
  p user
end
=> 打印出從主鍵開始 到最后的 user 數(shù)據(jù)
  • :finish
User.find_each(start: 開始的主鍵, finish: 結(jié)束的主鍵) do |user|
 p user
end
=> 打印從 start 開始,finish結(jié)束的所有 user 數(shù)據(jù)

find_in_batches方法

User.find_in_batches do |user|
  p user
end
=> 打印出 User 的所有user 的一個(gè)組合

PS: 和 find_each 類似,但是它是一次過將數(shù)據(jù)的組合傳入塊

條件查詢

# 最簡(jiǎn)單一個(gè)例子
User.where("nickname = 'cwhh'")
=> 會(huì)查處所有 nickname為 cwhh 的用戶

PS:上面的例子及其不安全,很容易受到 SQL 注入攻擊的風(fēng)險(xiǎn),要像下面這樣寫。

# 推薦寫法
User.where("nickname = ?",'cwhh')
=> 會(huì)查出所有 nickname為 cwhh 的用戶

# 多條件查詢
User.where("nickname= ? AND status = ?", params[:name], false)
=> 會(huì)查處所有 nickname 為傳入 參數(shù)對(duì)應(yīng) 并且 狀態(tài) 為 false 的所有用戶

# 如果條件中有很多變量,那么上面這種寫法的可讀性更高。
Client.where("created_at >= :start_date AND created_at <= :end_date", {start_date: params[:start_date], end_date: params[:end_date]})
=> 查詢 創(chuàng)建時(shí)間 大于等于傳入開始時(shí)間,并且小于傳入結(jié)束時(shí)間的 所有數(shù)據(jù)。
# 如果查詢的是個(gè)數(shù)組
Course.where("'#{params[:id]}' = ANY (teachers)")
=> 查出 傳入老師id對(duì)應(yīng)的所有課程。
  • 散列條件
User.where(nickname: 'cwhh')  => 查出所有 nickname 是 cwhh 的數(shù)據(jù)
  • 范圍條件
User.where(created_at: (Time.now.midnight - 1.day)..Time.now.midnight)
=> 查出 創(chuàng)建時(shí)間 是 現(xiàn)在時(shí)間減去一天,到現(xiàn)在傍晚的 所有數(shù)據(jù)
  • where.not
Client.where.not(nickname: 'cwhh')  => 查詢所有 nickname 不是 cwhh 的所有數(shù)據(jù)

排序

  • order 方法
User.order(:created_at)
# 或
User.order("created_at")
=> 按創(chuàng)建時(shí)間排序 輸出所有 User 數(shù)據(jù)
  • ASC(升序) 或 DESC(降序)
User.order(created_at: :desc)
# 或
User.order(created_at: :asc)
# 或
User.order("created_at DESC")
# 或
User.order("created_at ASC")
=> 輸出創(chuàng)建時(shí)間 升序 或者 降序的所有數(shù)據(jù)。
  • 按多個(gè)字段排序
User.order(orders_count: :asc, created_at: :desc)
=> 輸出訂單數(shù)量降序,創(chuàng)建時(shí)間升序的所有數(shù)據(jù)

選擇特定字段

Client.select("viewable_by, locked")
=> 輸出 client 所有數(shù)據(jù)的 viewable_by 字段 和 locked 字段。

# 輸出數(shù)據(jù)無重復(fù)
Client.select(:name).distinct
=> 輸出 Client 所有數(shù)據(jù)里的 name 字段,并且不帶重復(fù)
  • 輸出只有某字段的數(shù)據(jù)
User.select{ |user| user.realname  }
=> 輸出 realname 有值的數(shù)據(jù)
User.select{ |user| user.realname == nil }
=> 輸出 所有 realname 沒有值的數(shù)據(jù)

限量和偏移量

User.limit(5)
=> 打印5條user數(shù)據(jù)

User.limit(5).offset(30)
=> 打印5條user數(shù)據(jù) 從第31條開始

條件覆蓋

User.where.not('nickname = ?','nil').limit(2).unscope(:limit)
=> 找到nickname不是空的user數(shù)據(jù),unscope(:limit) 把limit限制給刪除了

User.where.not('nickname=? AND realname=?','cwhh','123123').unscope(where: :realname)
=> 還可以把where的某條件刪除

空關(guān)系

User.none
=> 返回一個(gè)空 Relation 對(duì)象,而且不執(zhí)行查詢

聯(lián)結(jié)表

class Category < ApplicationRecord
  has_many :articles
end
 => 一個(gè)創(chuàng)造者擁有多篇文章

class Article < ApplicationRecord
  belongs_to :category
  has_many :comments
  has_many :tags
end
=> 一篇文章 只有一個(gè)創(chuàng)造者
=> 一篇文章 擁有多個(gè)評(píng)論
=> 一篇文章 擁有多個(gè)標(biāo)簽
 
class Comment < ApplicationRecord
  belongs_to :article
  has_one :guest
end
=> 一個(gè)評(píng)論 只有一對(duì)應(yīng)一篇文章
=> 并且一個(gè)評(píng)論只對(duì)應(yīng)一個(gè)客人
 
class Guest < ApplicationRecord
  belongs_to :comment
end
=> 一個(gè)客人對(duì)應(yīng)一個(gè)評(píng)論
 
class Tag < ApplicationRecord
  belongs_to :article
end
=> 一個(gè)標(biāo)簽對(duì)應(yīng)一篇文章
  • 單個(gè)關(guān)聯(lián)的聯(lián)結(jié)
Category.joins(:articles)
=> 擁有文章的作者都打印出來
=> 如果這個(gè)作者有多篇文章,那么這個(gè)作者將會(huì)出現(xiàn)多次。

# 如果不想重復(fù),可以
Category.joins(:articles).distinct
  • 多個(gè)關(guān)聯(lián)的聯(lián)結(jié)
Article.joins(:category, :comments)
=> 打印出屬于某個(gè)作者至少有一條評(píng)論的Article數(shù)據(jù)打印出來
=> 注意,依然會(huì)重復(fù)。
  • 單層嵌套關(guān)聯(lián)的聯(lián)結(jié)
Article.joins(comments: :guest)
=> 打印出,擁有客人評(píng)論的文章數(shù)據(jù)
  • 多層嵌套關(guān)聯(lián)的聯(lián)結(jié)
Category.joins(articles: [{ comments: :guest }, :tags])
=> 把擁有評(píng)論,擁有標(biāo)簽的文章創(chuàng)建者打印出來

及早關(guān)聯(lián)

  • 1+n問題
clients = Client.limit(10)
 
clients.each do |client|
  puts client.address.postcode
end

# 這里查詢 存在查詢過多的問題 每條 client 都是去找他對(duì)應(yīng)的address 和 postcode
#一共要找 1+10次address+10次postcode

# 作出改動(dòng)
clients = Client.includes(:address).limit(10)
 
clients.each do |client|
  puts client.address.postcode
end
=> 這里一早把擁有地址的client 都找出來 然后再去找postcode,所以只執(zhí)行了2次查詢
  • 多個(gè)關(guān)聯(lián)的數(shù)組
Article.includes(:category, :comments)
=> 上面的代碼會(huì)加載所有文章、所有關(guān)聯(lián)的分類和每篇文章的所有評(píng)論。
Category.includes(articles: [{ comments: :guest }, :tags]).find(1)
=> 上面的代碼會(huì)查找 ID 為 1 的分類,并及早加載所有關(guān)聯(lián)的文章、這些文章關(guān)聯(lián)的標(biāo)簽和評(píng)論,以及這些評(píng)論關(guān)聯(lián)的訪客。
  • 為及早關(guān)聯(lián)指定條件
User.includes(:user_grounp).where(:user_grounp,  {name: :teacher})
=> 提早關(guān)聯(lián)有只有teacher小組里的的user用戶數(shù)據(jù) 
  • 要想像上面的代碼那樣使用 where 方法,必須在 where 方法中使用散列。如果想要在 where 方法中使用字符串 SQL 片段,就必須用 references 方法強(qiáng)制使用聯(lián)結(jié)表:
User.includes(:user_groups).where('user_groups.name=?','teacher').references(:user_groups)

作用域

#寫在model里的
class User < ApplicationRecord
  scope :sex, -> { where(sex: '男') }
end
#這兩種方法達(dá)到的效果相同
class User < ApplicationRecord
  def self.sex
    where(sex: '男')
  end
end
  • 在作用域中可以使用別的作用域
class User < ApplicationRecord
  scope :sex,               -> { where(sex:  '男') }
  scope :sex_and_age, -> { sex.where("age > 18") }
end
  • 調(diào)用
user = User.first
user.sex
  • 傳入?yún)?shù)
class User < ApplicationRecord
  scope :created_before, ->(time) { where("created_at < ?", time) }
end

# 調(diào)用都是一樣的
user = User.first
user.created_before(Time.now)

#當(dāng)作用域需要接受參數(shù)時(shí),推薦改用類方法。使用類方法時(shí),這些方法仍然可以在關(guān)聯(lián)對(duì)象上訪問:
class Article < ApplicationRecord
  def self.created_before(time)
    where("created_at < ?", time)
  end
end

#調(diào)用一樣的
user.user_groups.created_before(time)
  • 使用條件
class Article < ApplicationRecord
  scope :created_before, ->(time) { where("created_at < ?", time) if time.present? }
end

class Article < ApplicationRecord
  def self.created_before(time)
    where("created_at < ?", time) if time.present?
  end
end
  • 應(yīng)用默認(rèn)作用域
class Client < ApplicationRecord
  default_scope { where("removed_at IS NULL") }
end

class Client < ApplicationRecord
  def self.default_scope
    # 應(yīng)該返回一個(gè) ActiveRecord::Relation 對(duì)象
  end
end

默認(rèn)作用域在創(chuàng)建記錄時(shí)同樣起作用,但在更新記錄時(shí)不起作用。例如:

合并作用域

class User < ApplicationRecord
  scope :active, -> { where state: 'active' }
  scope :inactive, -> { where state: 'inactive' }
end
 
User.active.inactive
# 混用where 方法 
User.active.where(state: 'finished')

class User < ApplicationRecord
  default_scope { where state: 'pending' }
  scope :active, -> { where state: 'active' }
  scope :inactive, -> { where state: 'inactive' }
end
 
User.all
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending'
 
User.active
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' AND "users"."state" = 'active'
 
User.where(state: 'inactive')
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' AND "users"."state" = 'inactive'

有一點(diǎn)需要特別注意,default_scope 總是在所有 scope 和 where 之前起作用。
在上面的代碼中我們可以看到,在 scope 條件和 where 條件中都合并了 default_scope 條件。

enum 宏

enum status: {activation: 1, not_activation: 2}
User.create(name:'cwh',age:'18',status: 'activation')
User.find_by_name('cwh')
=> 這時(shí)候存到數(shù)據(jù)庫時(shí)候 status 就是 1
=> 輸出的時(shí)候 status 就是 activation

find_or_create_by 方法

這個(gè)方法 如果找到 就返回這個(gè)數(shù)據(jù),沒有找到就 創(chuàng)建一條這樣的數(shù)據(jù)

find_or_initialize_by 方法

此方法和find_or_create_by差不錯(cuò),只不過不是創(chuàng)建時(shí)候是new,不是create,要手動(dòng)保存

使用 SQL 語句進(jìn)行查找

Client.find_by_sql("SELECT * FROM clients
  INNER JOIN orders ON clients.id = orders.client_id
  ORDER BY clients.created_at desc")

pluck方法

User.pluck(:nickname)
=> 返回的是所有名字的一個(gè)組合的一個(gè)數(shù)組

檢查對(duì)象是否存在

User.exists?  => true
User.exists?(id: [1,2,3])  => 只要有一條對(duì)應(yīng)記錄存在就會(huì)返回 true
User.exists?(nickname: 'cwhh')  => true
User.exists?(nickname: '1231231231')  => false

計(jì)算

User.count => 200

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,824評(píng)論 18 399
  • Lua 5.1 參考手冊(cè) by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 14,259評(píng)論 0 38
  • 年底大盤點(diǎn),推薦書的信息一堆一堆地?fù)涿娑鴣?。因?yàn)檫@些推薦書的文章多是發(fā)布在年輕人活躍的平臺(tái)上,所以,很多人推薦的書...
    弘曉隨喜閱讀 474評(píng)論 0 0
  • 近期在看我的前半生,總覺得劇情人設(shè)有點(diǎn)扎心,小三搶走了自己的老公,自己又喜歡上了閨密的男友,不得不說真是有夠糾結(jié)的...
    落花思緒閱讀 269評(píng)論 0 0
  • 再窮 不要借錢去消費(fèi),信用卡 上的錢終歸是要還的,還在用信用卡盲目消費(fèi)的朋友醒醒吧,面對(duì)現(xiàn)實(shí),從頭開始還不晚! 再...
    陶瓊閱讀 173評(píng)論 0 0

友情鏈接更多精彩內(nèi)容