【问题标题】:Database structure and calculated rows数据库结构和计算行
【发布时间】:2014-08-25 22:17:03
【问题描述】:

一些背景

我正在构建一个购物车。如products 表中的redeemable 字段所示,某些产品(并非全部)可兑换。

兑换产品时,redeemed_qtylocation_idline_item_states 表中设置为一行。这允许做两件事:

  1. 虽然产品最初有位置,但一旦兑换,我们可以为兑换数量设置新位置
  2. 您可以多次兑换购买的产品(最多兑换总购买数量)

问题

我正在尝试创建一个报告,该报告将列出所有 line_items,但由 line_item_states 增强/扩展。

例如,给定下面的数据,它应该列出 LineItem 3 次:

Product               | Redeemed? | Qty | Location
Full Yard Landscaping | No        | 4   | 2
Full Yard Landscaping | Yes       | 8   | 3
Full Yard Landscaping | Yes       | 2   | 1

它被列出了 3 次,因为 line_itemline_item_states 是按位置分组的,它们的 redeemed_qty 相加。

我能够在没有第一行的情况下实现上表。那是计算出的剩余未兑换数量的行。所以基本上是某种虚拟行?

这是我当前生成上表的查询(没有第一行):

LineItem.select('"line_items".*,
        COALESCE("locs"."location_id", "products"."location_id") "location_id",   
        COALESCE("locs"."rqty", "line_items"."qty") "lqty",
        "locs"."rqty" "qty_redeemed"')
.joins('LEFT OUTER JOIN
            (SELECT "lie"."line_item_id",
                    "lie"."location_id",
                    SUM("lie"."redeemed_qty") "rqty"
             FROM "line_item_states" "lie"
             GROUP BY "lie"."line_item_id", "lie"."location_id") "locs"
          ON ("line_items"."id" = "locs"."line_item_id")
        LEFT OUTER JOIN "products"
          ON "products"."id" = "line_items"."product_id"')

问题

如何扩展查询以在示例表中生成第一行?
甚至可能吗?我看错了吗?


信息和样本数据

数据

订单项:

#<LineItem id: 24, order_id: 19, product_id: 3, created_at: "2014-08-20 01:27:53", updated_at: "2014-08-21 05:51:51", qty: 14, discount: #<BigDecimal:7ff0ba69e238,'0.0',9(18)>, discount_type: nil, price: #<BigDecimal:7ff0ba69e0f8,'0.1069E3',18(18)>, total: #<BigDecimal:7ff0ba69e030,'0.14966E4',18(18)>>

产品:

#<Product id: 3, title: "Full Yard Landscaping", full_price: #<BigDecimal:7ff0ba4d6400,'0.299E3',9(18)>, created_at: "2014-08-18 02:23:25", updated_at: "2014-08-21 05:50:56", price_overridable: true, deposit_price: #<BigDecimal:7ff0ba4d5910,'0.11E3',9(18)>, gvable: true, redeemable: true, location_id: 2>

LineItemState:

[#<LineItemState id: 51, redeemed_qty: 1, location_id: 1, user_id: 1, created_at: "2014-08-21 05:26:33", updated_at: "2014-08-21 05:26:33", line_item_id: 24, notes: nil>,
 #<LineItemState id: 52, redeemed_qty: 1, location_id: 3, user_id: 1, created_at: "2014-08-21 05:26:56", updated_at: "2014-08-21 05:26:56", line_item_id: 24, notes: nil>,
 #<LineItemState id: 53, redeemed_qty: 2, location_id: 3, user_id: 1, created_at: "2014-08-21 05:30:30", updated_at: "2014-08-21 05:30:30", line_item_id: 24, notes: nil>,
 #<LineItemState id: 54, redeemed_qty: 1, location_id: 3, user_id: 1, created_at: "2014-08-21 05:31:08", updated_at: "2014-08-21 05:31:08", line_item_id: 24, notes: nil>,
 #<LineItemState id: 55, redeemed_qty: 1, location_id: 3, user_id: 1, created_at: "2014-08-21 05:31:22", updated_at: "2014-08-21 05:31:22", line_item_id: 24, notes: nil>,
 #<LineItemState id: 56, redeemed_qty: 1, location_id: 3, user_id: 1, created_at: "2014-08-21 05:31:59", updated_at: "2014-08-21 05:31:59", line_item_id: 24, notes: nil>,
 #<LineItemState id: 57, redeemed_qty: 1, location_id: 3, user_id: 1, created_at: "2014-08-21 05:58:21", updated_at: "2014-08-21 05:58:21", line_item_id: 24, notes: nil>,
 #<LineItemState id: 58, redeemed_qty: 1, location_id: 3, user_id: 1, created_at: "2014-08-21 06:03:34", updated_at: "2014-08-21 06:03:34", line_item_id: 24, notes: nil>,
 #<LineItemState id: 59, redeemed_qty: 1, location_id: 1, user_id: 1, created_at: "2014-08-21 06:04:20", updated_at: "2014-08-21 06:04:20", line_item_id: 24, notes: "Another cool message dude!">]

产品

架构

create_table "products", force: true do |t|
  t.string   "title"
  t.decimal  "full_price",        precision: 7, scale: 2, default: 0.0
  t.datetime "created_at"
  t.datetime "updated_at"
  t.boolean  "price_overridable",                         default: false
  t.decimal  "deposit_price",     precision: 7, scale: 2, default: 0.0
  t.boolean  "gvable",                                    default: false
  t.boolean  "redeemable",                                default: false
  t.integer  "location_id"
end

型号

class Product < ActiveRecord::Base
  has_many :line_items
  belongs_to :location
end

订单项

架构

  create_table "line_items", force: true do |t|
    t.integer  "order_id"
    t.integer  "product_id"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.integer  "qty",           limit: 8,                         default: 1
    t.decimal  "discount",                precision: 7, scale: 2, default: 0.0
    t.string   "discount_type"
    t.decimal  "price",                   precision: 7, scale: 2, default: 0.0
    t.decimal  "total",                   precision: 7, scale: 2, default: 0.0
  end

型号

class LineItem < ActiveRecord::Base
  belongs_to :product
  has_many :line_item_states
end

LineItemState

架构

create_table "line_item_states", force: true do |t|
  t.integer  "redeemed_qty"
  t.integer  "location_id"
  t.integer  "user_id"
  t.datetime "created_at"
  t.datetime "updated_at"
  t.integer  "line_item_id"
  t.text     "notes"
end

型号

class LineItemState < ActiveRecord::Base
  belongs_to :line_item
  belongs_to :user
  belongs_to :location
end

【问题讨论】:

  • 您的查询与显示的输出相矛盾。请编辑以使其连贯。
  • 嘿@ErwinBrandstetter,它与输出有何矛盾?这就是我正在使用的查询。当然,我选择的字段比我显示的要多,否则它是准确的。
  • 您的输出包含Product | Redeemed? | Qty | Location 列,这不是显示的查询返回的内容。只是让它明确。

标签: sql ruby-on-rails database postgresql ruby-on-rails-4


【解决方案1】:

我建议您使用CTE 计算兑换数量。在用于从基本数量中减去并将计算的行附加到 UNION ALL 的主查询中。

使用一组基本列,查询可能如下所示:

WITH cte AS (
   SELECT line_item_id, location_id, SUM(redeemed_qty) AS qty
   FROM   line_item_states
   GROUP  BY line_item_id, location_id
   )

SELECT FALSE AS redeemed, li.id AS line_item_id, li.location_id
      ,CASE WHEN r.qty IS NULL THEN li.qty ELSE li.qty - r.qty END AS qty
FROM   line_items li
LEFT   JOIN (
   SELECT line_item_id, sum(qty) AS qty
   FROM   cte
   GROUP  BY 1
   ) r ON r.line_item_id = li.id

UNION  ALL
SELECT TRUE, c.line_item_id, COALESCE(c.location_id, p.location_id), c.qty
FROM   cte c
JOIN   line_items    li ON li.id = l.line_item_id 
LEFT   JOIN products p  ON p.id = li.product_id;

【讨论】:

  • 感谢@ErwinBrandstetter,我不了解 CTE,所以这肯定解决了这种情况。但是,我决定返回并创建父/子行项目情况以简化查询。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-17
  • 1970-01-01
  • 2013-02-17
  • 2021-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多