将同一列作为总和,以及根据不同条件对同一列的部分总和
Sum same column as total sum, and also partial sums from that same column based on different conditions
我的架构如下所示:
Purchase属于OrderItem,OrderItem属于一个Order。购买属于通过order_items.
订购
购买有一个名为金额的列,订单有一个名为网关交易 ID 的列。当订单有 gateway_transaction_id 时,即视为在线购买。而当订单没有gateway_transaction_id时,则视为下线。
目前,我需要进行 total_sum 次购买,total_sum 次在线购买,以及 total_sum 次线下购买。
这是我目前拥有的:
all_active_purchases.joins(:order).selecting {
[
sum(amount).as('total_purchase_amount'),
count(id).as('total_purchases_count'),
count(distinct(purchaser_id)).as('total_purchaser_count')
]
这是使用 baby_squeel gem.
完成的
我可以这样添加线上和线下的捐赠范围:
scope :online -> { joins(:order).where.not(orders: {gateway_transaction_id: nil})
scope :offline -> { joins(:order).where(orders: {gateway_transaction_id: nil})
然后我可以得到另外两个总和:
purchases.online.sum(:amount)
purchases.offline.sum(:amount)
不过感觉最后两个查询没有必要。我想计算所有值作为计算 total_purchase_amount 的第一个查询的一部分,以减少数据库查询的数量。是否可以将所有这些计算为一个查询的一部分?我要标记 mysql 标记,我也可以在应用程序中使用 mysql 语法。
这是相关的架构:
create_table "purchases", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
t.decimal "amount", precision: 10, scale: 2, null: false
t.integer "purchaser_id", null: false
end
create_table "order_items", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
t.integer "order_id"
t.string "item_type"
t.integer "item_id"
end
create_table "orders", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
t.string "gateway_transaction_id"
end
示例数据:
Purchases:
id: 1, amount: 20
id: 2, amount: 30
order_items:
id: 1, item_type: "Purchase", item_id: 1, order_id: 1
id: 2, item_type: "Purchase", item_id: 2, order_id: 2
order:
id: 1, gateway_transaction_id: 'abcdef'
id: 2, gateway_transaction_id:
以上id为1的购买是在线购买,因为它的订单有网关交易id,而id为2的购买是离线的,因为它的订单为零gateway_transaction_id
您可以将 SUM
与 CASE
语句一起使用以获得“过滤器”聚合:
all_active_purchases.joins(:orders)
.select(
'SUM(CASE WHEN orders.gateway_transaction_id IS NULL THEN purchases.amount ELSE 0 END) AS offline_amount',
'SUM(CASE WHEN orders.gateway_transaction_id IS NOT NULL THEN purchases.amount ELSE 0 END) AS online_amount'
)
我的架构如下所示:
Purchase属于OrderItem,OrderItem属于一个Order。购买属于通过order_items.
订购购买有一个名为金额的列,订单有一个名为网关交易 ID 的列。当订单有 gateway_transaction_id 时,即视为在线购买。而当订单没有gateway_transaction_id时,则视为下线。
目前,我需要进行 total_sum 次购买,total_sum 次在线购买,以及 total_sum 次线下购买。
这是我目前拥有的:
all_active_purchases.joins(:order).selecting {
[
sum(amount).as('total_purchase_amount'),
count(id).as('total_purchases_count'),
count(distinct(purchaser_id)).as('total_purchaser_count')
]
这是使用 baby_squeel gem.
完成的我可以这样添加线上和线下的捐赠范围:
scope :online -> { joins(:order).where.not(orders: {gateway_transaction_id: nil})
scope :offline -> { joins(:order).where(orders: {gateway_transaction_id: nil})
然后我可以得到另外两个总和:
purchases.online.sum(:amount)
purchases.offline.sum(:amount)
不过感觉最后两个查询没有必要。我想计算所有值作为计算 total_purchase_amount 的第一个查询的一部分,以减少数据库查询的数量。是否可以将所有这些计算为一个查询的一部分?我要标记 mysql 标记,我也可以在应用程序中使用 mysql 语法。
这是相关的架构:
create_table "purchases", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
t.decimal "amount", precision: 10, scale: 2, null: false
t.integer "purchaser_id", null: false
end
create_table "order_items", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
t.integer "order_id"
t.string "item_type"
t.integer "item_id"
end
create_table "orders", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
t.string "gateway_transaction_id"
end
示例数据:
Purchases:
id: 1, amount: 20
id: 2, amount: 30
order_items:
id: 1, item_type: "Purchase", item_id: 1, order_id: 1
id: 2, item_type: "Purchase", item_id: 2, order_id: 2
order:
id: 1, gateway_transaction_id: 'abcdef'
id: 2, gateway_transaction_id:
以上id为1的购买是在线购买,因为它的订单有网关交易id,而id为2的购买是离线的,因为它的订单为零gateway_transaction_id
您可以将 SUM
与 CASE
语句一起使用以获得“过滤器”聚合:
all_active_purchases.joins(:orders)
.select(
'SUM(CASE WHEN orders.gateway_transaction_id IS NULL THEN purchases.amount ELSE 0 END) AS offline_amount',
'SUM(CASE WHEN orders.gateway_transaction_id IS NOT NULL THEN purchases.amount ELSE 0 END) AS online_amount'
)