almost 10 years ago
我們公司系統裡面有一個使用情境:有一個 method 要去查詢一個 Order,路上哪些司機車上放的貨可以送單,甚至這些司機可以要設定條件多少距離內可以送。
OK.
-
order
has_manysold_products
-
sold_products
belongs_tomenu_item
-
driver_session
has_manydriver_session_items
-
driver_session_item
belongs_tomenu_item
這個使用情境就是要對 driver_session 造一個 scope 然後丟貨物需求數量,回傳可以繼續串接下去的 ActiveRecord::Relation。
一般 method 實作想法會是
- 我先去問路上有哪些司機,身上有載客戶所要的貨
- 然後對這些司機一個一個對他身上的貨夠不夠送
- 然後列出這些司機的名單
虛擬碼會是
然後再去下 on_roard_driver 和 can_ship_this_order 的條件。問題是這會有 db 掃描的問題。有 20 個 driver,3個 driver_session_item 就要問 20*3 = 60 次。有 10 個單要問就要問 600 次。(這是純 Ruby 解法,不是 SQL 解法)
下 SQL 難度沒有太高。不過難的是如何用 ActiveRecord 把這個作法拼出來,還能維護。
先說最後解法。
主要想法是用 array 的 map 拼 SQL 出來再塞 subquery。是的,scope 可以用這種奇技淫巧用 map 出來再塞回去組 query。ActiveRecord 翻譯的動...
延伸閱讀可以看這兩篇:
http://stackoverflow.com/questions/6686920/activerecord-query-union
http://stackoverflow.com/questions/11838537/query-intersection-with-activerecord
不管你是要做 UNION, INTERSECTION 或者是多條件的 JOIN 都可以用這種密技解。而且 code 可以維護,不用真的寫 SQL。