Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

ActiveRecord Query Interface (1), Season 1

2,617 views

Published on

제9차 ROR Lab 강의록입니다.

Published in: Education, Technology
  • Oh I'm sorry. Just updated this slide.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • These are good slides but this one will offend a lot of people. The image doesn't contribute anything to the content, it's not funny and it just makes you look like a perv (specially the age clause), do yourself a favor and get rid of the pic.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

ActiveRecord Query Interface (1), Season 1

  1. 1. The 9th Round of ROR Lab.Active RecordQuery Interface(1) March 17th, 2012 Hyoseong Choi ROR Lab.
  2. 2. ActiveRecord• No more SQL statements MySQL PostgreSQL : select * from tables SQLite ... ORM Active • SQL query Record • Fire Finder • Ruby object Methods • after_find callback ROR Lab.
  3. 3. Finder Methods of ActiveRecord1.where2.select3.group4.order5.reorder6.reverse_order7.limit8.offset9.joins10.includes11.lock12.readonly13.from14.havingActiveRecord::Relation ROR Lab.
  4. 4. Retrieving A Single Object• find• first• last• first!• last! ROR Lab.
  5. 5. Retrieving A Single Object - find - # Find the client with primary key (id) 10. client = Client.find(10) # => #<Client id: 10, first_name: "Ryan">SELECT * FROM clients WHERE (clients.id = 10)ActiveRecord::RecordNotFound exception ROR Lab.
  6. 6. Retrieving A Single Object - first - client = Client.first # => #<Client id: 1, first_name: "Lifo">SELECT * FROM clients LIMIT 1nil if no matching record is found ROR Lab.
  7. 7. Retrieving A Single Object - last - client = Client.last # => #<Client id: 221, first_name: "Russel">SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1nil if no matching record is found ROR Lab.
  8. 8. Retrieving A Single Object - first! - client = Client.first! # => #<Client id: 1, first_name: "Lifo">SELECT * FROM clients LIMIT 1RecordNotFound if no matching record ROR Lab.
  9. 9. Retrieving A Single Object - last! - client = Client.last! # => #<Client id: 221, first_name: "Russel">SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1RecordNotFound if no matching record ROR Lab.
  10. 10. Retrieving Multiple Objects• Using multiple primary keys• In batches • find_each :batch_size, :start, • find_in_batches :batch_size, :start + find options (except for :order, :limit) ROR Lab.
  11. 11. Retrieving Multiple Objects - Using multiple primary keys - # Find the clients with primary keys 1 and 10. client = Client.find([1, 10]) # Or even 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))ActiveRecord::RecordNotFound exception ROR Lab.
  12. 12. Retrieving Multiple Objects - in Batches - to iterate over a large set of records• find_each : each record to the block individually as a model• find_in_batches : the entire batch to the block as an array of models # This is very inefficient when the users table has thousands of rows. User.all.each do |user|   NewsLetter.weekly_deliver(user) end OK to 1,000 ROR Lab.
  13. 13. RetrievingMultiple Objects - in Batches : find_each -User.find_each do |user|  NewsLetter.weekly_deliver(user)endUser.find_each(:batch_size => 5000) do |user|  NewsLetter.weekly_deliver(user)endUser.find_each(:start => 2000, :batch_size => 5000)do |user|  NewsLetter.weekly_deliver(user)end ROR Lab.
  14. 14. Retrieving Multiple Objects - in Batches : find_each - Article.find_each { |a| ... } # => iterate over all articles, in chunks of 1000 (the default) Article.find_each(:conditions => { :published => true }, :batch_size => 100 ) { |a| ... } # iterate over published articles in chunks of 100http://archives.ryandaigle.com/articles/2009/2/23/what-s-new-in-edge-rails-batched-find ROR Lab.
  15. 15. Retrieving Multiple Objects - in Batches : find_in_batches - # Give add_invoices an array of 1000 invoices at a time Invoice.find_in_batches(:include => :invoice_lines) do |invoices|   export.add_invoices(invoices) endoptions : • :batch_size & :start • options of find method (except :order and :limit) ROR Lab.
  16. 16. Retrieving Multiple Objects - in Batches : find_in_batches -Article.find_in_batches { |articles| articles.each { |a| ... } } # => articles is array of size 1000Article.find_in_batches(:batch_size => 100 ) { |articles|articles.each { |a| ... } } # iterate over all articles in chunks of 100class Article < ActiveRecord::Base scope :published, :conditions => { :published => true }endArticle.published.find_in_batches(:batch_size => 100 ){ |articles| ... } # iterate over published articles in chunks of 100 ROR Lab.
  17. 17. Conditions - where -• String conditions• Array conditions• Hash conditions ROR Lab.
  18. 18. String Conditions Client.where("orders_count = ‘2’") ROR Lab.
  19. 19. Array ConditionsClient.where("orders_count = ?", params[:orders])Client.where("orders_count = ? AND locked = ?", params[:orders], false) XClient.where("orders_count = #{params[:orders]}") hacking!!! by SQL injection http://guides.rubyonrails.org/security.html#sql-injection ROR Lab.
  20. 20. Array Conditions - Placeholder conditions -Client.where("created_at >= :start_date ANDcreated_at <= :end_date", {:start_date =>params[:start_date], :end_date =>params[:end_date]}) ROR Lab.
  21. 21. Array Conditions - Range conditions - Client.where(:created_at => (params[:start_date].to_date).. (params[:end_date].to_date))SELECT "clients".* FROM "clients" WHERE("clients"."created_at" BETWEEN 2010-09-29 AND2010-11-30) ROR Lab.
  22. 22. Hash Conditions - Equality conditions -Client.where(:locked => true)Client.where(locked => true) ROR Lab.
  23. 23. Hash Conditions - Range conditions - Client.where(:created_at => (Time.now.midnight - 1.day)..Time.now.midnight)SELECT * FROM clients WHERE (clients.created_atBETWEEN 2008-12-21 00:00:00 AND 2008-12-2200:00:00) ROR Lab.
  24. 24. Hash Conditions - Subset conditions - Client.where(:orders_count => [1,3,5])SELECT * FROM clients WHERE (clients.orders_count IN(1,3,5)) ROR Lab.
  25. 25. OrderingClient.order("created_at")Client.order("created_at DESC")# ORClient.order("created_at ASC")Client.order("orders_count ASC, created_at DESC") ROR Lab.
  26. 26. SelectingIf the select method is used, all the returning objects will be read only.Client.select("viewable_by, locked") SELECT viewable_by, locked FROM clientsActiveModel::MissingAttributeError: missing attribute: <attribute>Client.select(:name).uniq SELECT DISTINCT name FROM clientsquery = Client.select(:name).uniq# => Returns unique namesquery.uniq(false)# => Returns all names, even if there are duplicates ROR Lab.
  27. 27. Limit & OffsetClient.limit(5) SELECT * FROM clients LIMIT 5Client.limit(5).offset(30) SELECT * FROM clients LIMIT 5 OFFSET 30 ROR Lab.
  28. 28. Group Order.select( "date(created_at) as ordered_date, sum(price) as total_price") .group("date(created_at)")SQL SELECT date(created_at) as ordered_date, sum(price) as total_price FROM orders GROUP BY date(created_at) ROR Lab.
  29. 29. Having Order.select( "date(created_at) as ordered_date, sum(price) as total_price") .group("date(created_at)") .having("sum(price) > ?", 100)SQL SELECT date(created_at) as ordered_date, sum(price) as total_price FROM orders GROUP BY date(created_at) HAVING sum(price) > 100 ROR Lab.
  30. 30. Overriding Conditions• except• only• reorder• reverse_order ROR Lab.
  31. 31. Overriding Conditions - except -Post.where(id > 10).limit(20).order(id asc).except(:order) SELECT * FROM posts WHERE id > 10 LIMIT 20 ROR Lab.
  32. 32. Overriding Conditions - only -Post.where(id > 10).limit(20).order(id desc).only(:order, :where) SELECT * FROM posts WHERE id > 10 ORDER BY id DESC ROR Lab.
  33. 33. Overriding Conditions - reorder - class Post < ActiveRecord::Base   ..   ..   has_many :comments, :order => posted_at DESC end   Post.find(10).comments.reorder(name)SELECT * FROM posts WHERE id = 10 ORDER BY nameSELECT * FROM posts WHERE id = 10 ORDER BY posted_at DESC ROR Lab.
  34. 34. Overriding Conditions - reverse_order - Client.where("orders_count > 10").order(:name).reverse_orderSELECT * FROM clients WHERE orders_count > 10 ORDER BY name DESC Client.where("orders_count > 10").reverse_orderSELECT * FROM clients WHERE orders_count > 10 ORDER BYclients.id DESC ROR Lab.
  35. 35. Readonly Objectsclient = Client.readonly.firstclient.visits += 1client.save ActiveRecord::ReadOnlyRecord exception ROR Lab.
  36. 36. Locking Records for Update• To prevent “race conditions”• To ensure “atomic updates”• Two locking mechanisms ‣ Optimistic Locking : version control ‣ Pessimistic Locking : DB lock ROR Lab.
  37. 37. Optimistic Locking• “lock_version” in DB table (default to 0)• set_locking_column to change column name c1 = Client.find(1) c2 = Client.find(1)   c1.first_name = "Michael" c1.save # increments the lock_version column   c2.name = "should fail" c2.save # Raises an ActiveRecord::StaleObjectError ROR Lab.
  38. 38. Optimistic Locking• To turn off, ActiveRecord::Base.lock_optimistically = false• To override the name of the lock_version column class Client < ActiveRecord::Base   set_locking_column :lock_client_column end ROR Lab.
  39. 39. Pessimistic Locking• A locking mechanism by DB• An exclusive lock on the selected rows• Usually wrapped inside a transaction• Two types of Lock ‣ FOR UPDATE (default, an exclusive lock) ‣ LOCK IN SHARE MODE ROR Lab.
  40. 40. Pessimistic Locking Item.transaction do   i = Item.lock.first   i.name = Jones   i.save end SQL (0.2ms)   BEGIN Item Load (0.3ms)   SELECT * FROM `items` LIMIT 1 FOR UPDATE Item Update (0.4ms)   UPDATE `items` SET `updated_at` = 2009-02-07 18:05:56, `name` = Jones WHERE `id` = 1 SQL (0.8ms)   COMMIT ROR Lab.
  41. 41. Pessimistic Locking Item.transaction do   i = Item.lock("LOCK IN SHARE MODE").find(1)   i.increment!(:views) end item = Item.first item.with_lock do   # This block is called within a transaction,   # item is already locked.   item.increment!(:views) end ROR Lab.
  42. 42. Joining Tables - Using a String SQL Fragment - Client.joins(LEFT OUTER JOIN addresses ON addresses.client_id = clients.id)SELECT clients.*FROM clientsLEFT OUTER JOIN addressesON addresses.client_id = clients.id ROR Lab.
  43. 43. Joining Tables- Using Array/Hash of Named Associations - only with INNER JOIN• a Single Association• Multiple Associations• Nested Associations(Single Level)• Nested Associations(Multiple Level) ROR Lab.
  44. 44. Joining Tables - Using Array/Hash of Named Associations - only with INNER JOINclass Category < ActiveRecord::Base  has_many :postsend class Post < ActiveRecord::Base • a Single Association  belongs_to :category  has_many :comments  has_many :tagsend Category.joins(:posts) class Comment < ActiveRecord::Base  belongs_to :post  has_one :guestend SELECT categories.*  FROM categoriesclass Guest < ActiveRecord::Base   INNER JOIN posts  belongs_to :commentend ON posts.category_id = categories.id class Tag < ActiveRecord::Base  belongs_to :post “return a Category object for all categories with posts”end ROR Lab.
  45. 45. Joining Tables - Using Array/Hash of Named Associations - only with INNER JOINclass Category < ActiveRecord::Base  has_many :postsend class Post < ActiveRecord::Base • Multiple Associations  belongs_to :category  has_many :comments  has_many :tagsend Post.joins(:category, :comments) class Comment < ActiveRecord::Base  belongs_to :post  has_one :guest SELECT posts.* FROM postsend    INNER JOIN categoriesclass Guest < ActiveRecord::Base ON posts.category_id = categories.id  belongs_to :comment   INNER JOIN commentsend ON comments.post_id = posts.id class Tag < ActiveRecord::Base “return all posts that have a category and at least one comment”  belongs_to :postend ROR Lab.
  46. 46. Joining Tables - Using Array/Hash of Named Associations - only with INNER JOINclass Category < ActiveRecord::Base  has_many :postsend class Post < ActiveRecord::Base • Nested Associations(Single Level)  belongs_to :category  has_many :comments  has_many :tagsend Post.joins(:comments => :guest) class Comment < ActiveRecord::Base  belongs_to :post  has_one :guest SELECT posts.* FROM postsend    INNER JOIN commentsclass Guest < ActiveRecord::Base ON comments.post_id = posts.id  belongs_to :comment   INNER JOIN guestsend ON guests.comment_id = comments.id class Tag < ActiveRecord::Base  belongs_to :post “return all posts that have a comment made by a guest”end ROR Lab.
  47. 47. Joining Tables - Using Array/Hash of Named Associations - only with INNER JOINclass Category < ActiveRecord::Base  has_many :postsend class Post < ActiveRecord::Base • Nested Associations(Multiple Level)  belongs_to :category  has_many :comments  has_many :tagsend Category.joins(:posts => class Comment < ActiveRecord::Base [{:comments => :guest}, :tags]  belongs_to :post  has_one :guestend  SELECT categories.* FROM categoriesclass Guest < ActiveRecord::Base   INNER JOIN posts ON posts.category_id = categories.id  belongs_to :comment INNER JOIN comments ON comments.post_id = posts.idend  INNER JOIN guests ON guests.id = comments.quest_idclass Tag < ActiveRecord::Base INNER JOIN tags ON tags.post_id = posts.id  belongs_to :postend ROR Lab.
  48. 48. Joining Tables - Specifying Conditions on the Joined Tables -: using Array and String Conditions time_range = (Time.now.midnight - 1.day)..Time.now.midnight Client.joins(:orders) .where(orders.created_at => time_range): using nested Hash Conditions time_range = (Time.now.midnight - 1.day)..Time.now.midnight Client.joins(:orders) .where(:orders => {:created_at => time_range}) ROR Lab.
  49. 49. Joining Tables - Inner Join - SELECT <select_list> FROM TableA A INNER JOIN TableB B ON A.Key = B.Key ROR Lab.
  50. 50. Joining Tables - Left Join -SELECT <select_list> SELECT <select_list>FROM TableA A FROM TableA ALEFT JOIN TableB B LEFT JOIN TableB BON A.Key = B.Key ON A.Key = B.Key WHERE B.Key IS NULL ROR Lab.
  51. 51. Joining Tables - Right Join -SELECT <select_list> SELECT <select_list>FROM TableA A FROM TableA ARIGHT JOIN TableB B RIGHT JOIN TableB BON A.Key = B.Key ON A.Key = B.Key WHERE A.Key IS NULL ROR Lab.
  52. 52. Joining Tables - Full Outer Join -SELECT <select_list> SELECT <select_list>FROM TableA A FROM TableA AFULL OUTER JOIN TableB B FULL OUTER JOIN TableB BON A.Key = B.Key ON A.Key = B.Key WHERE A.Key IS NULL OR B.Key IS NULL ROR Lab.
  53. 53. ROR Lab.
  54. 54. 감사합니다.
  55. 55.   ROR Lab.

×