我正在制作一款游戏,用户可以使用虚拟货币购买虚拟物品,并将这些物品交给其他用户。我们需要能够跟踪物品的历史(谁买了它,谁被赋予了它等)和当前的所有者。我正在努力解决一些桌面设计问题。
我的想法是(稍微简化表格设计并省略空间的约束/键/等):
TABLE order
id INT NOT NULL AUTO_INCREMENT,
buyer_id INT NOT NULL,
paid INT UNSIGNED NOT NULL,
owned_item_id INT NOT NULL,
------------------------------------------------------
TABLE owned_item
id INT NOT NULL AUTO_INCREMENT,
store_product_id INT NOT NULL,
owner_id INT NOT NULL,
------------------------------------------------------
TABLE gift
id INT NOT NULL,
giver_id INT NOT NULL,
receiver_id INT NOT NULL,
owned_item_id INT NOT NULL,
根据想法,购买商品时,会为该商品创建 order
和 owned_item
。如果该项目有资格,则会在 gift
表格中创建一个新条目,并更新owner_id
字段。
这种方法可以很容易地确定当前拥有给定项目的人。 然而,它具有冗余数据,并为数据完整性问题留下了空间。如果'owner_id'字段设置不正确,我们最终可能会得到A购买并赠送给B的项目的记录,但现在却被C莫名其妙地拥有。
这样的结构应该如何规范化?我考虑过删除 owned_item
表:
TABLE order
id INT NOT NULL AUTO_INCREMENT,
buyer_id INT NOT NULL,
paid INT UNSIGNED NOT NULL,
product_id INT NOT NULL,
------------------------------------------------------
TABLE gift
id INT NOT NULL,
giver_id INT NOT NULL,
receiver_id INT NOT NULL,
order_id INT NOT NULL,
我不喜欢这个解决方案,因为查找某个人拥有的所有项目都会变得非常复杂(找到每个礼物记录X,其中收件人是A,并且没有以后的礼品记录存在于同一订单中,与find结合使用每个订单记录Y,其中买方是A并且该订单不存在礼品记录)但如果这是正确的解决方案,那么我将做。
答案 0 :(得分:0)
对于您正在寻找的事情,这样的事情将是一个很好的3nf架构。
实体和交易保持通用,以便简化所有实体/交易关系。
-- An Entity is a person or business, as a party in a transaction
CREATE TABLE entity (
id INT NOT NULL AUTO_INCREMENT,
entity_type ENUM('store', 'person') NOT NULL
name VARCHAR NOT NULL
);
-- Unique item types - items are each an instance of an item-type
-- e.g. the item "Steve's broom" may be an item of type "broom"
CREATE TABLE item_type (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR NOT NULL
);
-- Non-unique item, instance of an item-type owned by an entity
CREATE TABLE item (
id INT NOT NULL AUTO_INCREMENT,
-- optionally include owner_id as a quick-reference to the current owner of the item
owner_id INT NULL REFERENCES entity (id),
-- FK to unique item types, e.g. "broom"
item_type_id INT NOT NULL REFERENCES item_type (id),
-- possible description, e.g. "Steve's broom"
description VARCHAR NOT NULL
);
-- A transaction is a sale, gift, or other method of transferrence
-- of an item between entities. Transaction is a bad name, because
-- it's a reserved word. That's why it's encased in ticks.
-- You'd probably be better off choosing a different generic name
CREATE TABLE `transaction` (
id
-- transaction_type can be NULL in cases of origination with entity
transaction_type ENUM('sale', 'gift') NULL,
-- NULL in cases of origination with an entity
from_entity_id INT NULL REFERENCES entity (id),
to_entity_id INT NOT NULL REFERENCES entity (id),
-- amount can be 0 in cases of gifts
amount DECIMAL(9,2) UNSIGNED NOT NULL DEFAULT 0
);
A"礼物"事务的数量为0(如果你想让它可以为空,则为NULL)。
"起源"事务(例如,某事已经发现或被发现)将没有transaction_type和0 amount。
要知道项目的当前所有者是谁,请使用一个视图来检索最后一个" to_entity_id"对于交易表中的该项目,例如:
SELECT
e.name
FROM entity AS e
INNER JOIN `transaction` AS t ON e.id = t.to_entity_id
INNER JOIN
(SELECT MAX(id) AS id
FROM `transaction`
WHERE item_id = 5) AS tx ON tx.id = t.id
或者,您也可以将owner_id存储在项目表中(请参阅上面的架构中的注释)。这将是一个多余的,并且需要在每个事务上更新该表,但是会节省大量昂贵的查询以了解谁拥有什么。