如何为存储订单明细的关系数据库建模?

时间:2019-05-22 19:36:05

标签: android sqlite database-design android-room

我正在为Android开发一个餐厅POS应用程序,我正在尝试确定使用Room ORM确保其可维护性的最佳数据库建模方法。我的数据库除其他事项外,还需要保留交易/订单中所有已售商品的记录,以及订单本身的日志以及在餐厅内出售的食品清单。 考虑以下表格(为简洁起见,我仅包括我认为与该问题相关的列,可能无法说明我将要编目的所有信息),因此我可以创建一个包含所有已下订单的日志的表,并对其进行调用all_orders:

all_orders
-----------
id (PK)
oder_details_id (FK) - referencing the PK from order_details table
date
notes
total
payment_type

我还可以创建一个表,其中包含餐厅提供的所有食品/菜肴,我们将其称为all_items:

all_items
---------
id (PK)
name
category
price

到目前为止,还没有问题,但是我目前的困惑就在这里— 我如何设法保持订单中已售出的实际食品的日志? 我考虑过的一种方法是按订单号创建表格,但是动态创建表格已经是一个问题,到年底拥有60,000张表格将成为可维护性的噩梦。 因此,我的另一种可能的解决方案是创建一个名为order_details的表,该表每年可能最终包含成千上万的条目,并包含以下列:

order_details
-------------
id (PK)
item_id (FK) - referencing the PK from the all_items table
order_id (FK) - referencing the PK from the all_orders table
quantity_ordered

并且,当用户想要从上个星期开始下达订单时,程序可以使用联接查询,该查询将产生以下内容以显示在应用的用户界面中:

order
---------
id (PK)
date (from the all_orders table)
name (from all_items)
category (from all_items)
price (from all_items)
total (from all_orders)
payment_type (from all_orders)

恐怕 order_details表太宽了,因为它将包含成千上万个条目,并且对其进行查询很慢。我敢肯定,为它建立索引会有所帮助,但这是解决此问题的正确方法吗?如果不是,是否有更好的“最佳实践”解决方案?如果可能的话,重点在于将任何订单及其项目组合在一起,而不仅仅是将所有订单中的所有项目转储到一个表中。任何帮助将不胜感激。

编辑:该问题不是this的重复,并且尽管有帮助,但是所提供的链接没有提供有关我真正询问的内容的任何其他上下文,也与我所寻求的答案完全无关。我已加粗了我的最后一个原始段落,因为我的问题实际上是关于如何对上述数据建模,因为根据我的研究如何存储附在订单上的实际订单明细,这对我来说尚不清楚 (我遇到的许多教程/类似问题都未能完全解释上述内容而失败)。

1 个答案:

答案 0 :(得分:1)

all_orders 表将是多余的,因为它只是重复其他数据,并且有悖于规范化。

您可能想要分类表而不是重复数据(即归一化分类)。

同样,您可能还需要一个payment_type表(再次进行归一化)。

为订单创建单个表格可能只会造成噩梦。

价格和总数不一样吗?说提取数据时可以得出总数,所以不需要存储此类信息。

因此,以下结构模式可能接近您想要的结构:-

DROP TABLE IF EXISTS item;
DROP TABLE IF EXISTS category;
CREATE TABLE IF NOT EXISTS category (_id INTEGER PRIMARY KEY, category_name TEXT);

CREATE TABLE IF NOT EXISTS item (
    _id INTEGER PRIMARY KEY, 
    item_name TEXT UNIQUE, 
    category_ref INTEGER REFERENCES category(_id) ON DELETE CASCADE ON UPDATE CASCADE, 
    item_price REAL
);

DROP TABLE IF EXISTS payment_type;
CREATE TABLE IF NOT EXISTS payment_type (
    _id INTEGER PRIMARY KEY, 
    payment_type TEXT UNIQUE, 
    surcharge REAL
);

-- NOTE cannot call a table order as it is a keyword (not rea true but have to enclose the name e.g.g [order]). 
DROP TABLE IF EXISTS customer_order;
CREATE TABLE IF NOT EXISTS customer_order (
    _id INTEGER PRIMARY KEY, 
    customer_name TEXT, 
    date TEXT DEFAULT CURRENT_TIMESTAMP, 
    payment_type_ref INTEGER REFERENCES payment_type(_id) ON DELETE CASCADE ON UPDATE CASCADE
);

DROP TABLE IF EXISTS order_detail;
CREATE TABLE IF NOT EXISTS order_detail (
    customer_order_ref INTEGER REFERENCES customer_order(_id) ON DELETE CASCADE ON UPDATE CASCADE, 
    item_ref REFERENCES item(_id) ON DELETE CASCADE ON UPDATE CASCADE,
    quantity
);

示例

以下是本机SQL,它演示了上面的架构:-

第1部分添加(插入)数据:-

INSERT INTO category (category_name) VALUES
    ('Fish'),('Beef'),('Chicken'),('Lamb'),('Sea Food')
;
INSERT INTO item (item_name, item_price, category_ref) VALUES
    ('Fish and Chips',11.30,1),
    ('Steak and Kidney Pudding',15.45,2),
    ('Lamb Chops, Mashed Potato and Gravy',17.40,3)
;

INSERT INTO payment_type (payment_type, surcharge) VALUES
    ('Master Card',0.05),('Visa',0.05),('Cash',0),('American Express',0.15)
;

INSERT INTO customer_order (customer_name, payment_type_ref) VALUES
    ('Fred',3),
    ('Mary',1),
    ('Tom',2),
    ('Jane',4)
;
INSERT INTO order_detail (customer_order_ref, item_ref, quantity) VALUES
    (1,1,2),(1,2,1), -- Fred (id 1) orders 2 Fish and Chips (id 1) and 1 Steak and Kidney (id 2)
    (2,3,10), -- Mary orders 10 Lamb chops
    (3,2,1),(3,1,1),(3,3,1), -- Tom orders 1 of each
  (4,1,1) -- Just Fish and chips for Jane   
;

第2部分-提取有用的(也许)数据

以下是您可以使用SQL进行处理的示例,其中包括派生数据(如上述建议 ):-

SELECT 
    customer_name, 
    date, 
    group_concat(item_name) ||'('||quantity||')' AS items, 
    sum(item_price) AS total_price, 
    payment_type, 
    round(sum(item_price) * surcharge,2) AS surcharge,
    round((sum(item_price) * surcharge) + sum(item_price),2) AS total_price
    FROM customer_order
        JOIN order_detail ON customer_order._id = order_detail.customer_order_ref
        JOIN item ON order_detail.item_ref = item._id
        JOIN payment_type ON customer_order.payment_type_ref = payment_type._id
    GROUP BY customer_order._id -- Treats all data for an order as a single row allowing the use of aggregate functions on the groups e.g. sum, group_concat
;

结果

enter image description here