关系数据库:有一个引用关联 table 的外键可以吗?
Relational Databases: Is it fine to have a foreign key referencing an Associative table?
假设我们有乘客,其中乘客可以参加许多航班,而一个航班可能有很多乘客。在每个航班中,每个乘客都可以选择 he/she 可以观看的独特电影。
对于乘客、航班以及它们之间的关联,我们有三个 table:
Flights
-----------
id
flight_number
Passengers
--------
id
name
PassengerFlights
---------------
passenger_id
flight_id
对于电影,它必须指定适用于哪个乘客和哪个航班。
在这种情况下,使用外键引用 PassengerFlights 联结点 table 是否可以,或者使用三个外键创建联结点 table 会更好吗(passenger_id, flight_id, movie_id)?例如:
选项 #1
MoviePassengerFlights
---------------------
movie_id
passenger_flight_id
选项 #2
MoviePassengerFlights
----------------------
movie_id
passenger_id
flight_id
我对似乎最直接的选项 #2 的担忧是,即使乘客和航班之间的关系被删除,它仍然是有效的记录。
对于此类用例,是否推荐选项 #1 或选项 #2?或者有更好的选择吗?
select取决于乘客购买电影的时间。如果他们只能在机上购买电影,那么选项 #2 就可以了,因为您不希望 passenger/flight 关系在航班开始后被删除。
另一方面,如果电影可以提前购买,如果乘客取消预订,你想退还购买的款项,那么选项 1 将保证你不能删除航班记录,如果电影购买仍然存在。
考虑是否可以在 passenger_flight_movie
中输入一行
该航班上没有的电影,或未在该航班上预订的乘客。这过于简单化了,但显示了限制。
-- Movie MOVIE_ID exists
--
movie {MOVIE_ID}
PK {MOVIE_ID}
-- Flight FLIGHT_ID exists
--
flight {FLIGHT_ID}
PK {FLIGHT_ID}
-- Passenger PASSENGER_ID exists.
--
passenger {PASSENGER_ID}
PK {PASSENGER_ID}
-- Movie MOVIE_ID is available on flight FLIGHT_ID.
--
movie_flight {MOVIE_ID, FLIGHT_ID}
PK {MOVIE_ID, FLIGHT_ID}
FK1 {FLIGHT_ID} REFERENCES flight {FLIGHT_ID}
FK2 {MOVIE_ID} REFERENCES movie {MOVIE_ID}
-- Passenger PASSENGER_ID is booked on flight FLIGHT_ID.
--
passenger_flight {PASSENGER_ID, FLIGHT_ID}
PK {PASSENGER_ID, FLIGHT_ID}
FK1 {FLIGHT_ID} REFERENCES flight {FLIGHT_ID}
FK2 {PASSENGER_ID} REFERENCES passenger {PASSENGER_ID}
-- Movie MOVIE_ID is available to passenger PASSENGER_ID
-- on flight FLIGHT_ID.
--
passenger_flight_movie {PASSENGER_ID, FLIGHT_ID, MOVIE_ID}
PK {PASSENGER_ID, FLIGHT_ID, MOVIE_ID}
FK1 {PASSENGER_ID, FLIGHT_ID} REFERENCES
passenger_flight {PASSENGER_ID, FLIGHT_ID}
FK2 {MOVIE_ID, FLIGHT_ID} REFERENCES
movie_flight {MOVIE_ID, FLIGHT_ID}
为了回答您的担忧,即即使乘客不再预订航班,m_p_f 记录仍可能保留 — 在 p_f table 中,将 (flight_id, passenger_id) table 的复合主键,并使用 ON DELETE CASCADE 规则将其引用为 m_p_f table 中的外键。那么如果删除了p_f中的记录,那么m_p_f中对应的记录也会被引擎自动删除。
junction/join table
在关系范式中,没有这样的东西。该术语是 Associative table。它 关联 两个父 table,并解析它们之间的多对多关系。 JOIN
是一个 SQL 动词。
The concern I'm having with Option #2, which seems the most straightforward, is that it remains a valid record even if the relationship between a Passenger and Flight gets deleted.
这是错误的。如果"the relationship between a Passenger and Flight gets deleted",乘客不再乘坐该航班,因此没有乘客可以为其预订电影的航班乘客。
更糟糕的是,如果乘客和航班之间的关系是 而不是 删除,您可以为任何旧航班保留任何旧乘客的电影......这是不正确的:电影预订应仅限于实际乘坐特定航班(PassengerFlight)的乘客。
我完全不明白那是怎么回事 "straight-forward"。
Would Option #1 or Option #2 be recommended for such use cases?
对于您声明的文件:
- 选项 1 正确。
- 选项 2 严重不正确。
这也是此类 "use cases" 的通用答案。
Is it fine to have a foreign key referencing an Associative table?
答案是肯定的。它在关系数据库中很常见,一旦你超过了几个 tables。每个 table 都是一个事实,每个关系都是两个事实之间的关系。 Associative table 只是一个 Fact,可以被任何从属 Fact 引用。
Or is there a better alternative?
是的。关系数据库。您声明的文件不是关系文件,它们是典型的 1960 年代、关系之前的记录归档系统,为方便起见部署在 SQL 中。这不完全是你的错:大量 "literature"; "theoreticians" 和其他作者销售的所有教科书,声称是 "relational" 实际上都是反关系的。他们所努力的就是他们所理解的:1960 年代,关系前的 RFS,"relational" 名存实亡。这是一场巨大的悲剧。关系数据库具有更高的完整性;力量;和速度。
这超出了问题的范围。有空再问问题,我会回答的。
假设我们有乘客,其中乘客可以参加许多航班,而一个航班可能有很多乘客。在每个航班中,每个乘客都可以选择 he/she 可以观看的独特电影。
对于乘客、航班以及它们之间的关联,我们有三个 table:
Flights
-----------
id
flight_number
Passengers
--------
id
name
PassengerFlights
---------------
passenger_id
flight_id
对于电影,它必须指定适用于哪个乘客和哪个航班。
在这种情况下,使用外键引用 PassengerFlights 联结点 table 是否可以,或者使用三个外键创建联结点 table 会更好吗(passenger_id, flight_id, movie_id)?例如:
选项 #1
MoviePassengerFlights
---------------------
movie_id
passenger_flight_id
选项 #2
MoviePassengerFlights
----------------------
movie_id
passenger_id
flight_id
我对似乎最直接的选项 #2 的担忧是,即使乘客和航班之间的关系被删除,它仍然是有效的记录。
对于此类用例,是否推荐选项 #1 或选项 #2?或者有更好的选择吗?
select取决于乘客购买电影的时间。如果他们只能在机上购买电影,那么选项 #2 就可以了,因为您不希望 passenger/flight 关系在航班开始后被删除。
另一方面,如果电影可以提前购买,如果乘客取消预订,你想退还购买的款项,那么选项 1 将保证你不能删除航班记录,如果电影购买仍然存在。
考虑是否可以在 passenger_flight_movie
中输入一行
该航班上没有的电影,或未在该航班上预订的乘客。这过于简单化了,但显示了限制。
-- Movie MOVIE_ID exists
--
movie {MOVIE_ID}
PK {MOVIE_ID}
-- Flight FLIGHT_ID exists
--
flight {FLIGHT_ID}
PK {FLIGHT_ID}
-- Passenger PASSENGER_ID exists.
--
passenger {PASSENGER_ID}
PK {PASSENGER_ID}
-- Movie MOVIE_ID is available on flight FLIGHT_ID.
--
movie_flight {MOVIE_ID, FLIGHT_ID}
PK {MOVIE_ID, FLIGHT_ID}
FK1 {FLIGHT_ID} REFERENCES flight {FLIGHT_ID}
FK2 {MOVIE_ID} REFERENCES movie {MOVIE_ID}
-- Passenger PASSENGER_ID is booked on flight FLIGHT_ID.
--
passenger_flight {PASSENGER_ID, FLIGHT_ID}
PK {PASSENGER_ID, FLIGHT_ID}
FK1 {FLIGHT_ID} REFERENCES flight {FLIGHT_ID}
FK2 {PASSENGER_ID} REFERENCES passenger {PASSENGER_ID}
-- Movie MOVIE_ID is available to passenger PASSENGER_ID
-- on flight FLIGHT_ID.
--
passenger_flight_movie {PASSENGER_ID, FLIGHT_ID, MOVIE_ID}
PK {PASSENGER_ID, FLIGHT_ID, MOVIE_ID}
FK1 {PASSENGER_ID, FLIGHT_ID} REFERENCES
passenger_flight {PASSENGER_ID, FLIGHT_ID}
FK2 {MOVIE_ID, FLIGHT_ID} REFERENCES
movie_flight {MOVIE_ID, FLIGHT_ID}
为了回答您的担忧,即即使乘客不再预订航班,m_p_f 记录仍可能保留 — 在 p_f table 中,将 (flight_id, passenger_id) table 的复合主键,并使用 ON DELETE CASCADE 规则将其引用为 m_p_f table 中的外键。那么如果删除了p_f中的记录,那么m_p_f中对应的记录也会被引擎自动删除。
junction/join table
在关系范式中,没有这样的东西。该术语是 Associative table。它 关联 两个父 table,并解析它们之间的多对多关系。 JOIN
是一个 SQL 动词。
The concern I'm having with Option #2, which seems the most straightforward, is that it remains a valid record even if the relationship between a Passenger and Flight gets deleted.
这是错误的。如果"the relationship between a Passenger and Flight gets deleted",乘客不再乘坐该航班,因此没有乘客可以为其预订电影的航班乘客。
更糟糕的是,如果乘客和航班之间的关系是 而不是 删除,您可以为任何旧航班保留任何旧乘客的电影......这是不正确的:电影预订应仅限于实际乘坐特定航班(PassengerFlight)的乘客。
我完全不明白那是怎么回事 "straight-forward"。
Would Option #1 or Option #2 be recommended for such use cases?
对于您声明的文件:
- 选项 1 正确。
- 选项 2 严重不正确。
这也是此类 "use cases" 的通用答案。
Is it fine to have a foreign key referencing an Associative table?
答案是肯定的。它在关系数据库中很常见,一旦你超过了几个 tables。每个 table 都是一个事实,每个关系都是两个事实之间的关系。 Associative table 只是一个 Fact,可以被任何从属 Fact 引用。
Or is there a better alternative?
是的。关系数据库。您声明的文件不是关系文件,它们是典型的 1960 年代、关系之前的记录归档系统,为方便起见部署在 SQL 中。这不完全是你的错:大量 "literature"; "theoreticians" 和其他作者销售的所有教科书,声称是 "relational" 实际上都是反关系的。他们所努力的就是他们所理解的:1960 年代,关系前的 RFS,"relational" 名存实亡。这是一场巨大的悲剧。关系数据库具有更高的完整性;力量;和速度。
这超出了问题的范围。有空再问问题,我会回答的。