Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

วิธีการเลือกบันทึกฐานข้อมูลในคำสั่งโดยพลการ

ใน Rails คุณสามารถรับระเบียนจำนวนมากจากฐานข้อมูลของคุณได้ง่ายๆ หากคุณมี ID:

Person.where(id: [1, 2, 3]).map(&:id) => [1, 2, 3]

แต่ถ้าคุณต้องการได้รับบันทึกกลับเป็น แตกต่าง สั่งซื้อ? บางทีเครื่องมือค้นหาของคุณอาจส่งคืน ID ที่เกี่ยวข้องมากที่สุดก่อน คุณรักษาอย่างไร บันทึกของคุณตามลำดับหรือไม่

คุณสามารถลอง where อีกครั้ง:

Person.where(id: [2, 1, 3]).map(&:id) => [1, 2, 3]

แต่นั่นไม่ได้ผลเลย แล้วทำอย่างไร คุณได้รับบันทึกของคุณกลับมาในลำดับที่ถูกต้องหรือไม่

วิธีที่เข้ากันได้:case คำชี้แจง

เช่นเดียวกับ Ruby SQL รองรับ case...when แถลงการณ์

คุณไม่เห็นมันบ่อยเกินไป แต่ case...when งบสามารถ เกือบ ทำตัวเหมือนแฮช คุณสามารถจับคู่ค่าหนึ่งกับอีกค่าหนึ่งได้:

case :b
when :a then 1
when :b then 2
when :c then 3
end # => 2

คำสั่ง case นั้นดูเหมือนแฮช:

{
  :a => 1,
  :b => 2,
  :c => 3
}[:b] # => 2

ดังนั้น คุณมีวิธีแมปคีย์เพื่อเรียงลำดับที่ควรปรากฏ และฐานข้อมูลของคุณสามารถจัดเรียงและส่งคืนผลลัพธ์ของคุณตามลำดับที่ต้องการได้

เมื่อทราบแล้ว คุณสามารถใส่รหัสและตำแหน่งลงใน case คำสั่งและใช้ใน SQL order ข้อ

ดังนั้น หากคุณต้องการให้วัตถุของคุณส่งคืนตามลำดับ [2, 1, 3] SQL ของคุณอาจมีลักษณะดังนี้:

SELECT * FROM people
  WHERE id IN (1, 2, 3)
  ORDER BY CASE id
    WHEN 2 THEN 0
    WHEN 1 THEN 1
    WHEN 3 THEN 2
    ELSE 3 END;

ด้วยวิธีนี้ บันทึกของคุณจะถูกส่งคืนในลำดับที่ถูกต้อง The CASE เปลี่ยนแต่ละ ID ตามลำดับที่ควรส่งคืน

แน่นอนว่ามันดูไร้สาระ และคุณสามารถจินตนาการได้ว่าประโยคแบบนี้จะสร้างเองได้น่ารำคาญเพียงใด

แต่คุณไม่ได้ มี เพื่อสร้างมันด้วยมือ นั่นคือสิ่งที่ Ruby มีไว้สำหรับ:

lib/extensions/active_record/find_by_ordered_ids.rb
module Extensions::ActiveRecord::FindByOrderedIds
  extend ActiveSupport::Concern
  module ClassMethods
    def find_ordered(ids)
      order_clause = "CASE id "
      ids.each_with_index do |id, index|
        order_clause << sanitize_sql_array(["WHEN ? THEN ? ", id, index])
      end
      order_clause << sanitize_sql_array(["ELSE ? END", ids.length])
      where(id: ids).order(order_clause)
    end
  end
end

ActiveRecord::Base.include(Extensions::ActiveRecord::FindByOrderedIds)

Person.find_ordered([2, 1, 3]) # => [2, 1, 3]

อย่างที่เราต้องการ!

วิธีที่สะอาดกว่า เฉพาะ MySQL

หากคุณใช้ MySQL มีวิธีที่ดีกว่านี้ MySQL มี ORDER BY FIELD พิเศษ ไวยากรณ์:

SELECT * FROM people
WHERE id IN (1, 2, 3)
ORDER BY FIELD(id, 2, 1, 3);

คุณสามารถสร้างสิ่งนั้นจาก Ruby:

lib/extensions/active_record/find_by_ordered_ids.rb
module Extensions::ActiveRecord::FindByOrderedIds
  extend ActiveSupport::Concern
  module ClassMethods
    def find_ordered(ids)
      sanitized_id_string = ids.map {|id| connection.quote(id)}.join(",")
      where(id: ids).order("FIELD(id, #{sanitized_id_string})")
    end
  end
end

ActiveRecord::Base.include(Extensions::ActiveRecord::FindByOrderedIds)

ดังนั้น หากคุณใช้ MySQL และไม่กังวลเกี่ยวกับความเข้ากันได้มากเกินไป นี่เป็นวิธีที่ดี อ่านง่ายขึ้นมากเมื่อข้อความเหล่านี้แสดงผ่านบันทึกของคุณ

เมื่อคุณต้องการแสดงเรกคอร์ดในลำดับที่ต้องการ คุณไม่จำเป็นต้องเรียงลำดับใน Ruby ด้วยข้อมูลโค้ดเล็กๆ น้อยๆ คุณสามารถปล่อยให้ฐานข้อมูลทำสิ่งที่ถนัดได้ เช่น ค้นหา จัดเรียง และส่งคืนข้อมูลไปยังแอปของคุณ