我有一个很多行为的故事。这些行为不是连续的(我不知道哪个是第一幕,第二个,第三个,等等)。
每个故事都以挑战结束。
为了代表关系数据库中的所有数据库,我使用了下表:
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->新故事
注意:行为可以不止一个。
答案 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
中所需的所有列,您只需删除表Challenge
和ActionType
即可。如果你需要知道它的行为类型(标准与挑战),请使用ThisActionType
列而不是可能包含NextActionType
的{{1}}。
还要从Story表中删除C,A
并找到一种方法来识别FirstActID
表中的第一个/最后一个动作 - 每个动作只能属于此模型中的一个故事,并且第一个和最后一个显然很特别。
所以,到它完成时它会看起来像这样
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)
),表示它是一个挑战。