使用具有 3 个外键的 1 个联结 table 或具有共享排序的 2 个联结 table?

Use 1 junction table with 3 foreign keys Or 2 junction tables with shared sequencing?

我有 3 个表,我正在尝试 正确地 在它们之间创建关系:

一个'game phase'可以有一个或多个'game event(s)',一个'game event'可以有一个或多个'game phase(s)'。 (多对多)

一个'game phase'可以有一个或多个'action window(s)',一个'action window'可以有一个或多个'game phase(s)'。 (多对多)

A 'game event' 与 'action window' 无关。

但是,我对创建 2 个单独的联结表犹豫不决,因为 'game events' 和 'action windows' 共享相同的 出现顺序(又名序列)编号系统每个 'game phase'。我不确定我将如何维护它。

在仍然能够轻松跟踪出现顺序的同时布置这些表格的最正确方法是什么?

创建一个 table 交汇点:

game_phase_steps

+----+-----------+-------+----------+---------+
| id | phase_id  | rank  |   type   | step_id |
+----+-----------+-------+----------+---------+
|  1 |         1 |    1  | event    |       2 |
|  2 |         1 |    2  | action   |       1 |
+----+-----------+-------+----------+---------+
  • id - game_phase_steps
  • 的主键
  • phase_id - 游戏阶段的外键
  • rank - 游戏阶段中步骤的唯一出现顺序
  • 类型 - 游戏阶段可以有事件或动作
  • step_id - event_id 用于游戏事件的国外参考或 action_id 用于动作的国外参考 window

不知道您的 game_eventaction_window 是如何构建的。 但是如果您需要单个查询中的所有数据,您可能需要执行两个左联接,一个到 game_event,一个到 action_window,以及 return 您想要从适当的联接中获得的字段table 像这样:

game_phase_steps g
LEFT JOIN game_event e
    ON game_phase_steps.type = "event" 
        AND game_phase_steps.step_id = e.id
LEFT JOIN action_window a
    ON game_phase_steps.type = "action" 
        AND game_phase_steps.step_id = a.id

如果您的 table 的结构不同,那么您可能需要 select 这样的声明:

SELECT CASE WHEN g.type = "event" THEN e.some_field ELSE a.some_field END

我建议设计代表序列 of 'game events''action windows',属于同一个序列步骤中的同一个序列。

即引入“gaming sequence”和“gaming sequence detail”实体,结点table避免了"by design",表示'game event(s)'和'action window(s)[=70的共享排序事实=]' 通过在“游戏序列”中具有相同的序列步骤(由于考虑到“而避免'game event' 与 'action window'") 无关。

架构

+--------------+ 1      1,n +-------------------+ 1,n
|  game_phase  +------------+  game_phase_play  +----+
|              |            |                   |    |
+--------------+            +-------------------+    |
                                                     |
                                                     | 1
+--------------------------+ 1,n         1 +---------+---------+
|  gaming_sequence_detail  +---------------+  gaming_sequence  |
|                          |               |                   |
++--------+----------------+               +-----+-------------+
 | 1,n    |                                      |
 |        +---+  seq_step                        +---+ seq_steps_number
 |
 |
 |                                      +--------------+
 |                                +-----+  game_event  |
 | 1,n +----------------+         |     |              |
 +-----+  gaming_value  | <-------+     +--------------+
       |                |         |     +-----------------+
       +----------------+         +-----+  action_window  |
                                        |                 |
                                        +-----------------+

前缀

gph_                    === game_phase_
gseq_                   === gaming_sequence_
gv_                     === gaming_value_

表格

game_phase              ( id , description, ... )
game_phase_play         ( id , gph_id, gseq_id, date, description, ... )
gaming_sequence         ( id, seq_steps_number, ... )
gaming_value            ( id , type, ... )
gaming_sequence_detail  ( gseq_id, gv_id, seq_step, ... )

我还为“游戏事件”和“动作window(s)[=70”引入了一个泛化实体=]' 名为“gaming value”,对于包含在“gaming sequence”中很有用。这种概括可以代表一种游戏 immutable 值(在我们的例子中有 2 种不同类型,但可扩展),因此选择的命名(已经从“gaming objectified 切换”和“可观察到的游戏”)。

'gaming value(s)' 在gaming sequence中,这两种类型是“stepped together 通过 gaming_sequence_detail 中的 (gseq_id, seq_step) 对的相等性(可以说这种“”是一种关系;这种解决方案的行为更像是在序列步骤中表示 sibilings,还允许扩展到超过 2 种类型的“gaming values”)。

'游戏事件'和动作window(s)'在gaming sequence detail可以单独修改,也可以出现“unpaired”。

gaming_sequence_detail 中的一个约束是对于每个 seq_step 值可以存在一个 game_event 和一个 action_window,因此 seq_step 的最大基数单个 gseq_id 是 2。

如果是这样,相同的 gaming_value 也可能在同一序列中出现不止一次。此外,该设计还可以表示不同 'game phase play(s)'.

之间的共享序列