Nhìn bề ngoài, .update_all
đang chạy một truy vấn SQL duy nhất đang cập nhật tất cả các nhận xét với user_id
trên 11. Về mặt kỹ thuật, .where[user_id: 11]
là truy vấn cuối cùng, nhưng nó không nên chạy truy vấn SQL chỉ cho các mối quan hệ của related_comments
sao?
Tôi có một giải pháp thay thế mà tôi có thể thực hiện việc này, nhưng nó sẽ yêu cầu hai truy vấn SQL và có vẻ quá cồng kềnh hơn mức cần thiết
comment = Comment.find[params[:id]]
# same as above
related_comment_ids = comment.where[something: params[:something]
.union[comment.where[something_else: params[:something_else]]]
.where[user_id: comment.user_id].pluck[:id]
#=> [12, 14, 17, 18]
Comment.where[id: related_comment_ids].update_all[receive_notifications: true]
#=> SQL [5.7ms] UPDATE "comments" SET "receive_notifications" = 't'
#=> WHERE "comments"."id" IN [18, 14, 17, 12] [sql_query]
#=> 4
Vào chế độ toàn màn hình Thoát chế độ toàn màn hình
Trong một thời gian rất dài trong Rails, không thể kết hợp câu lệnh xóa với truy vấn GROUP_BY và HAVING. Có vẻ như đó là thứ lẽ ra phải được hỗ trợ ngay lập tức, nhưng tiếc là đã bị bỏ qua — cho đến tận bây giờ
Trước
Việc sử dụng GROUP_BY hoặc HAVING trong câu lệnh xóa đã bị bỏ qua. Hãy xem một ví dụ
Ở đây, một người dùng có nhiều phiếu bầu và chúng tôi đang cố gắng đếm những người dùng có ít hơn ba phiếu bầu
User.joins[:votes].group["users.id"].having["count[votes.id] < 3"].count
=> {2=>1, 1=>2}
Nếu chúng tôi thực hiện update_all
với mệnh đề group
và
User.joins[:votes].group["users.id"].having["count[votes.id] < 3"].count
=> {2=>1, 1=>2}
0 thì ActiveRecord sẽ bỏ qua nóUser.joins[:votes].group["users.id"].having["count[votes.id] < 3"].update_all[consistent: true]
# actual
UPDATE "users" SET "consistent" = ? WHERE "users"."id" IN [
SELECT "users"."id" FROM "users" INNER JOIN "votes" ON "votes"."user_id" = "users"."id"
] [["consistent", "t"]]
# expected
UPDATE "users" SET "consistent" = ? WHERE "users"."id" IN [
SELECT "users"."id" FROM "users" INNER JOIN "votes" ON "votes"."user_id" = "users"."id"
GROUP BY users.id HAVING [count[votes.id] Traceback [most recent call last]:
1: from [irb]:10
ActiveRecord::ActiveRecordError [delete_all doesn't support group, having]
Sau đó
May mắn thay, Rails 7 cho phép các mệnh đề GROUP BY và HAVING với update_all và sử dụng các truy vấn lồng nhau khi thực hiện DELETE với mệnh đề GROUP BY và HAVING
Điều thú vị là MySQL không hỗ trợ sử dụng câu lệnh DELETE hoặc UPDATE kết hợp với GROUP_BY hoặc HAVING. Để phá vỡ điều này, PR sử dụng các truy vấn lồng nhau