Database design 规范化这个数据库:在这个场景中什么是理想的?

Database design 规范化这个数据库:在这个场景中什么是理想的?,database-design,normalization,Database Design,Normalization,我正在设计一个游戏,其中一个角色有许多物品,这些物品可以是多种类型。有一个角色表和十二个不同的表,表中列出了按类型划分的可能物品(如武器、盔甲和各种其他物品类型) 我想制作一个表来保存这些项目类型的实例(基本上是一个字符的项目表),每一行都有一个来自字符表的外键来指示哪个字符拥有该项目的所有权 起初,我想我应该在characters的items表中创建外键——12个item表中每个表一个键。但由于每个项只能有一个“类型”,这将导致每行中有11个空字段,这似乎是错误的 更好的方法是什么?我还没有建

我正在设计一个游戏,其中一个角色有许多物品,这些物品可以是多种类型。有一个角色表和十二个不同的表,表中列出了按类型划分的可能物品(如武器、盔甲和各种其他物品类型)

我想制作一个表来保存这些项目类型的实例(基本上是一个字符的项目表),每一行都有一个来自字符表的外键来指示哪个字符拥有该项目的所有权

起初,我想我应该在characters的items表中创建外键——12个item表中每个表一个键。但由于每个项只能有一个“类型”,这将导致每行中有11个空字段,这似乎是错误的

更好的方法是什么?我还没有建立数据库,所以我可以考虑其他不使用12个项目表的库存想法,但要知道:管理员界面将允许用户根据需要添加/删除/修改每种类型的项目


此外,我希望坚持最佳规范化实践,因此我将忽略不可避免的“谁在乎?只做有效的事情并使用可空字段。”

我首先检查是否可以将这12个表合并为一个表。首先,因为它很简单,我打赌在这种情况下它是足够的

CHARACTER --<- CHAR_ITEMS  ->-- ITEM_TYPES_STI 
字符----项目类型
如果没有,试试看。基本上,为“项目类型”定义一个超级表,角色的项目引用该超级表。12个单独项目类型的每个子表也引用项目类型超级表:

CHARACTER --<- CHAR_ITEMS  ->-- ITEM_TYPES_SUPER --- ITEM_TYPE_SWORDS
CHARACTER---ITEM\u TYPE\u SUPER---ITEM\u TYPE\u剑
关于你的评论:我已经澄清了上面这句话。项目类型与项目类型之间的关系应为1:1。也就是说,对于剑中的每一行,超级剑中应该有一个不同的行。这样做的方法是使剑中的外键也成为它的主键


但并不是每一排都有一排剑。super中的行可以由shield中的行、axes或其他任何内容引用。但只有一个亚型。其思想是,所有项目类型的公共列都属于super,并且子类型特定的列都位于每个子类型表中。

如果使用以下表(我只包括列的键值)。CHARACTERS\u ITEMS表包含每个字符的项目列表。ItemTypeID和ItemID的组合将用于引用12个items表之一中的一行

CHARACTERS
----------
CharacterID (PK)

ITEMS
-----
ItemID (PK)

ITEM_TYPES
----------
ItemTypeID (PK)

CHARACTERS_ITEMS
----------------
CharacterID (FK)
ItemTypeID (FK)
ItemID (FK)
下面是一个可能也有帮助的视图的开始。它演示了如何使用ItemTypeId引用适当的表

CREATE VIEW v_character_items
AS
SELECT {list of columns}
FROM character_items
JOIN character_item_1 on character_items.ItemID = character_item_1.ItemID and character_items.ItemTypeID = 1

UNION 
SELECT {list of columns}
FROM character_items
JOIN character_item_2 ON character_items.ItemID = character_item_2.ItemID and character_items.ItemTypeID = 2

UNION
{other tables...}

在您的情况下,我会尝试将所有12个表合并回一个表

这样做的原因实际上与技术表设计无关,而是可以让您的角色以意想不到的方式重用对象

例如,你可以拥有一组可投掷属性,如努力、准确度、伤害、破损,因此匕首几乎不需要用力投掷,如果它卡住了目标,会造成大量伤害,另一方面,高脚杯很容易扔,但造成的伤害很小,或者金条很难扔,但会造成合理的伤害,即使严格来说它不是武器。
它还可以让你拥有武器,这些武器也是“珍宝”物品,具有巨大的价值或魔法用途(不知道你在计划什么样的游戏,所以这些例子可能不合适,我不知道你是否还在寻找答案,但我最近是如何做的:

CHARACTER -> Char/Item Link Table -> ITEM

ITEM
----
ID
NAME
TYPE
etc.
这允许您创建多个角色可以拥有的基本项目。如果您希望通过效果表(或类似工具)轻松对项目(即宝石槽、附魔等)进行单个角色修改,请执行以下操作:


通过这种方式,您可以让角色自定义自己的武器,同时保持基地不变。您还可以创建一组效果,而无需对游戏中的每个项目反复重复这些效果。

最佳规范化实践并不总是最佳编程实践。特别是,任何需要您查询12表的情况当您可以保证只返回其中1行时,这不是最佳编程实践,无论您的数据集多么紧凑和无冗余。您在这个系统中的优先级是什么?@Kylotan+1-应该始终应用规范化,但这是一种平衡行为,理论上,您可以将其规范化到第n级,但通过这个time您将有许多表,这会降低查询性能。如果我理解您的第二个示例:一个字符有许多字符项,一个项目类型超级有许多字符项和项目类型剑。如果管理员在项目类型剑表中插入一些剑,并且字符项表中的一行有一个映射到“剑”的键在item\u types\u super表中输入,我如何才能从item\u types\u剑术表中判断出该物品是哪把剑?谢谢,我会用它运行,看看会发生什么!我正在检查你的设计,看看它是否适合我,但我必须说:为什么要使用
联合
?我相信你应该学习
联合
语法。谢谢@Stephen.我肯定我有很多东西要向你学习。我不知道你可以在SQL中执行联接。假设你想显示以下列character\u items.CharacterID、character\u items.ItemId以及character\u item\u 1、character\u item\u 2等表格中的列。你能告诉我如果我用联接替换并集,SELECT子句会是什么样子吗?
SELECT character\u items.CharacterID,character\u items.ItemId,character\u item\u 1.*,character\u item\u 2.*从character\u items中连接character\u item\u 1在character\u items上连接character\u item\u 1.ItemId在character\u items上连接character\u item\u item\u item\u 2.ItemId=character\u item\u item\u item\u 2.item;
@Stephen-您的SELECT语句每个表中每个字符的行。如果
ITEM -> Item/Effect Link Table -> EFFECTS