数据库设计问题

时间:2011-04-27 13:10:12

标签: database-design

我有一个很多行为的故事。这些行为不是连续的(我不知道哪个是第一幕,第二个,第三个,等等)。

每个故事都以挑战结束。

为了代表关系数据库中的所有数据库,我使用了下表:

Story
---------------------------------------
Id              | PK
Name            | String
FirstActId      | FK to ACT table

Act
---------------------------------------
Id              | PK
StoryId         | FK to STORY table
Name            | String
Description     | Very long string
NextActionType  | FK to ACTIONTYPE table
NextId          | Its value depends on NextActionType

ActionType
---------------------------------------
Id              | PK
Name            | Values= 'Act', 'Challenge', 'Story'.

Challenge
---------------------------------------
Id              | PK
Name            | String
Description     | Very long string
NextActionType  | FK to ACTIONTYPE table
NextId          | Its value depends on NextActionType

我使用Story.FirstActId知道哪个是故事的第一幕(我试图说"Select MIN(Id) from Act where StoryId = ?"不起作用。)。

然后,我使用Act.NextId来了解此行为后的行为或挑战。 Act.NextId可以是法案PK或挑战PK或故事PK。这取决于Act.NextActionType值。

你怎么看?这是一个好的设计吗?

我的问题是我有挑战表,与任何其他表没有任何关系。

更新

换句话说,我需要一个系统来知道接下来要去哪里。我将遇到以下情况:

story-> act-> challenge-> act - >新故事 故事 - > ACT-> challente->新故事

注意:行为可以不止一个。

4 个答案:

答案 0 :(得分:1)

您的表格设计不在3NF中并且可能存在更新异常(例如,如果删除故事的第一个行为,则整个链断开;如果其NextActId更新,则链条完全更改)。另一个问题是你必须递归地寻找链接以获取故事的所有行为,而不是在一个查询中获取它们。

如果您希望能够在故事之间重复使用行为,则应使用间接表:

StoriesActsMap
--------------
storyid
actid
ordinal_number

如果您不需要在故事之间重复使用行为,那么您可以坚持使用Acts表:

   Act
   -------------
   actid
   actDescription, etc.
   ordinal_number
   storyid

挑战的处理也取决于。

挑战也可以成为一种行为吗?如果是这样,您应该将其存储在Acts中并拥有ActsType表:

   Act
   --------------
   actid
   acttypeid
   ...see rest of Act above

   ActsType
   --------------
   acttypeid
   acttype (Act, Challenge)

如果挑战是一种行为,那么它在故事中的定位(最后一次)是否将其定义为挑战?如果是这样,ActsType不是必需的,它只是StoriesActMap / Act上的MAX序号

如果挑战是挑战而永远不是一项法案,那么它应该存储在单独的表格中。如果可以在故事之间重复使用挑战,您可以拥有StoriesChallengeMap表,或者只有具有storyid键的挑战表,如果无法重复使用,则可以将其映射到故事。 storyid将是这些表格上的唯一键,因为故事只有一个挑战。

假设挑战永远是挑战,而不能在故事之间分享行为/挑战,设计将如下:

Story
----------
storyid
other info

Act
----------
actid
storyid
actorder (ordinal number of acts, (actorder, storyid) is a prime)
other info

Challenge
----------
chid
storyid
other info

现在,您可以在一个查询中获取故事的所有行为和挑战。请注意,如果没有外键约束,删除一个故事就会孤立Acts / a Challenge。

答案 1 :(得分:0)

我看到它的方式,Challenge只是Act的(子)类型。考虑到Act表包含Challenge中所需的所有列,您只需删除表ChallengeActionType即可。如果你需要知道它的行为类型(标准与挑战),请使用ThisActionType列而不是可能包含NextActionType的{​​{1}}。

还要从Story表中删除C,A并找到一种方法来识别FirstActID表中的第一个/最后一个动作 - 每个动作只能属于此模型中的一个故事,并且第一个和最后一个显然很特别。

所以,到它完成时它会看起来像这样

enter image description here

Act(F,L,A)将用于识别第一个,最后一个,任何一个。

答案 2 :(得分:0)

我会改变一些事情:

Act
---------------------------------------
...
NextAct         | FK to Act table, can be NULL
Challenge       | FK to Challenge table, can be NULL

No need of ActionType

您将节省空间。如果NextAct不为null,则行为之后是Act, 如果挑战不为空,则法案之后是挑战。

当然,条件(NextAct xor Challenge)必须始终为true。您可以通过在Act表中的插入上添加表约束来断言。

如果您有很多类型的下一步操作(因为我们这里只有两个操作,很容易),您需要以不同的方式查看问题: “挑战有一个法案”, “一项法案可以有一项法案” “ActionN已采取行动”

就像那样,你将能够找到下面的行动:

SELECT
  challenge_id,
  act_id,
  ...
FROM
  Act
LEFT OUTER JOIN
  Act NextAct ON Act.next_act_id = NextAct.act_id
...
LEFT OUTER JOIN
  Challenge ON Act.challenge_id = Challenge_id

至少有一个不会为NULL。

答案 3 :(得分:0)

对我而言,Acts&挑战似乎存储了相同类型的信息,因此将它们放在不同的表格中似乎有些过分。

我可能会去...

Story
---------------------------------------
Id              | PK
Name            | String
FirstActId      | FK to ACT table

Items (Acts or Challenges)
---------------------------------------
Id              | PK
StoryId         | FK to STORY table
Name            | String
Description     | Very long string
Order           | Int - which position this Act / Challenge should go in

你可以有一个标志,表明某事是法案还是挑战。

但是,如果我理解您的描述,那么您可以通过约定来识别项目,例如将第一个项目的Order设置为0,使其成为第一个法案,当一个法案/挑战是该集合中的最后一个项目(即Max(Order)),表示它是一个挑战。