ใน 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 มีไว้สำหรับ:
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:
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 ด้วยข้อมูลโค้ดเล็กๆ น้อยๆ คุณสามารถปล่อยให้ฐานข้อมูลทำสิ่งที่ถนัดได้ เช่น ค้นหา จัดเรียง และส่งคืนข้อมูลไปยังแอปของคุณ