很抱歉,如果这个问题令人困惑,因为我不确定如何提出问题,但我在这里:
我在rails控制台内试图找到所有订单所有订单状态为“错误”的用户,并且只有错误。用户有很多订单,每个订单的订单状态可能与“已完成”,“退款”或“错误”不同。
User.includes(:orders).where(orders: { state: "errored" })
这将返回所有具有一个或多个错误订单的用户,无论用户是否还有其他状态的订单。但我正在尝试提取仅错误订单的用户。
我已经尝试了很多东西,从迭代每个用户的每个订单,到尝试手动找到它们。但它必须是更好的方式。
答案 0 :(得分:1)
我的SQL不像以前那样,但我相信对于纯SQL解决方案,它需要看起来像:
SELECT "users".*
FROM "users"
LEFT JOIN orders on orders.user_id = users.id
LEFT JOIN orders non_errored_orders on non_errored_orders.user_id = users.id and non_errored_orders.state <> 'errored'
WHERE "non_errored_orders"."id" IS NULL AND "orders"."id" IS NOT NULL
因此,我们将orders
表与别名non_errored_orders
一起加入,这将使得如果存在用户ID匹配且状态不等于的订单错误,会出现一行(non_errored_orders.id
最终会显示为NOT NULL
)。在where
子句中,我们会向下筛选仅non_errored_orders.id IS NULL
的用户,过滤掉与错误订单匹配的所有用户。
然后我们再次加入orders
表,只在users.id = orders.user_id
上匹配别名。如果没有orders.id
,则表示用户根本没有表中的任何订单,因此我们希望仅过滤到orders.user_id IS NOT NULL
的用户,这意味着他们有订单。
您可以通过执行以下操作在rails中执行此类查询:
User.
joins(:orders).
joins("LEFT JOIN orders non_errored_orders on non_errored_orders.user_id = users.id and non_errored_orders.state <> 'errored'").
where(non_errored_orders: { id: nil }).
where.not(orders: { id: nil }).distinct
# User Load (0.3ms) SELECT DISTINCT "users".* FROM "users" INNER JOIN "orders" ON "orders"."user_id" = "users"."id" LEFT JOIN orders non_errored_orders on non_errored_orders.user_id = users.id and non_errored_orders.state <> 'errored' WHERE "non_errored_orders"."id" IS NULL AND ("orders"."id" IS NOT NULL) LIMIT ? [["LIMIT", 11]]
# => #<ActiveRecord::Relation [#<User id: 1, ...>]>
在我非常有限的测试集中,这似乎有效。
测试数据是
User.find(1).orders.create([ { state: 'errored' }, { state: 'errored' } ])
User.find(2).orders.create([ { state: 'errored' }, { state: 'completed' }])
User.find(3).orders.create([ { state: 'refunded' } ])
答案 1 :(得分:0)
那条漫长但简化的路径怎么样?
users_with_other_order_states = User.join(:orders).where.not(orders: { state: "errored" }).pluck(:id)
User.joins(:orders).where('orders.state = "errored" AND users.id NOT IN (?)', users_with_other_order_states)
答案 2 :(得分:-1)
我认为您可以尝试定义errored_orders
关系:
class User < ApplicationRecord
has_many errored_orders, ->{where state: 'errored'}
end
User.includes(:errored_orders).where(...)
希望它有所帮助!