从所有订单都具有状态 "errored" 的订单中选择用户
Selecting users from orders where all orders has the state "errored"
抱歉,如果问题令人困惑,因为我不确定如何提出问题,但我开始了:
我在 rails 控制台中,试图找到所有有订单的用户,其中所有订单的状态都是 "errored",并且只有错误。一个用户有很多订单,每个订单上的订单状态可以不同于 "completed"、"refunded" 或 "errored"。
User.includes(:orders).where(orders: { state: "errored" })
这将按预期返回所有有一个或多个错误订单的用户,无论用户是否也有其他州的订单。但我正在尝试获取 ONLY 有错误订单的用户。
我尝试了很多方法,从遍历每个用户的每个订单,到尝试手动查找它们。但它必须是更好的方法。
我想你可以尝试定义一个 errored_orders
关系:
class User < ApplicationRecord
has_many errored_orders, ->{where state: 'errored'}
end
User.includes(:errored_orders).where(...)
希望对您有所帮助!
我的 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
table 与别名 non_errored_orders
连接起来,如果存在用户 ID 匹配且状态为不等于 errored,将出现一行(并且 non_errored_orders.id
将以 NOT NULL
结尾)。在 where
子句中,我们然后过滤到只有 non_errored_orders.id IS NULL
的用户,过滤掉所有匹配没有 错误的订单的用户 .
然后我们再次加入 orders
table,没有别名只匹配 users.id = orders.user_id
。如果没有 orders.id
,则意味着用户在 table 中根本没有任何订单,因此我们希望过滤到只有 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' } ])
稍微长一点但简化的路径怎么样?
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)
抱歉,如果问题令人困惑,因为我不确定如何提出问题,但我开始了:
我在 rails 控制台中,试图找到所有有订单的用户,其中所有订单的状态都是 "errored",并且只有错误。一个用户有很多订单,每个订单上的订单状态可以不同于 "completed"、"refunded" 或 "errored"。
User.includes(:orders).where(orders: { state: "errored" })
这将按预期返回所有有一个或多个错误订单的用户,无论用户是否也有其他州的订单。但我正在尝试获取 ONLY 有错误订单的用户。
我尝试了很多方法,从遍历每个用户的每个订单,到尝试手动查找它们。但它必须是更好的方法。
我想你可以尝试定义一个 errored_orders
关系:
class User < ApplicationRecord
has_many errored_orders, ->{where state: 'errored'}
end
User.includes(:errored_orders).where(...)
希望对您有所帮助!
我的 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
table 与别名 non_errored_orders
连接起来,如果存在用户 ID 匹配且状态为不等于 errored,将出现一行(并且 non_errored_orders.id
将以 NOT NULL
结尾)。在 where
子句中,我们然后过滤到只有 non_errored_orders.id IS NULL
的用户,过滤掉所有匹配没有 错误的订单的用户 .
然后我们再次加入 orders
table,没有别名只匹配 users.id = orders.user_id
。如果没有 orders.id
,则意味着用户在 table 中根本没有任何订单,因此我们希望过滤到只有 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' } ])
稍微长一点但简化的路径怎么样?
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)