ActiveRecord Query Interface (1), Season 1

2,461 views

Published on

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

Published in: Education, Technology
2 Comments
2 Likes
Statistics
Notes
  • 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
No Downloads
Views
Total views
2,461
On SlideShare
0
From Embeds
0
Number of Embeds
1,284
Actions
Shares
0
Downloads
23
Comments
2
Likes
2
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • 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.

    ×