【问题标题】:SQL database (Firebird): problem with a foreign keySQL 数据库 (Firebird):外键问题
【发布时间】:2009-10-23 21:06:51
【问题描述】:

我的 SQL 数据库 (Firebird) 有一个名为 tTransaction 的表。它包含两列,senderFKreceiverFK。还有其他三个表,tBufferStocktFacilitytOutsideLocation

发送者或接收者可以是缓冲库存、我们自己的设施或外部位置。

我的问题是我不知道如何让 senderFKreceiverFK 引用正确的表。

我想到了一个新表,位于发件人与三个可能的发件人之间,ID 为 1 到 3 之间的数字,表中引用的 ID,但实际上这并不能解决问题。有什么想法吗?

诺伯特

【问题讨论】:

  • 你能改变现有的桌子设计吗?
  • 我使用的是 Firebird 2.5。是的,我可以更改现有的表。还没有数据。

标签: sql firebird foreign-key-relationship


【解决方案1】:

您尝试执行的操作无法在 SQL 中完成。一个 FK 最多不能引用三个不同的表。

你需要做的是:

  • 创建其他列senderBufferstockFKsenderFacilityFKsenderOutsideLocationFK
  • 将它们连接到适当的表
  • 在您的主表上有一个检查约束(如果支持)或触发器或其他一些机制,以确保在任何给定时间只有这三个中的一个具有值

这意味着,在任何给定时间,三个“fk”列中只有一个可以有值,但每个 FK 列都是特定表的特定 FK。

您可以将其直接放入您正在谈论的表中,或者您可以将其外部化到一个单独的表中,并从您的主表中仅引用该“中间”表,然后从那里获得这三个 FK

YourTable.SenderFK --> Intermediary.PK
    Intermediary.SenderBufferstockFK --> tBufferstock.ID
    Intermediary.SenderFacilityFK --> tFacility.ID
    Intermediary.SenderOutsideLocationFK --> tOutsideLocation.ID

或者您可以直接放弃 FK 关系,但这绝对不是一个好主意!

马克

【讨论】:

  • 为了提高数据完整性,您还可以定义一个检查约束(如果您的 DBMS 支持的话),它只要求三个 ID 列中的一个不为空。
  • 令我吃惊的是,每当您想从表格中获取信息时,此解决方案都会导致大量复杂性。您必须对应用程序进行编码以区分这三种情况。而且,每行都需要两个 NULL 值的设计似乎也不符合数据规范化的精神。
  • @Larry:我完全同意——它不漂亮。这种“引用其中一个 x 表”的场景永远不会是 :-(
  • @marc_s @Christian:谢谢!这听起来很有道理。我会试一试的。
【解决方案2】:

尝试以下架构:

tSenderReceiver (type INT, id INT, PRIMARY KEY (type, id))

tTransaction (id INT PRIMARY KEY, senderType INT, senderId INT, receiverType INT, receiverID INT,
      FOREIGN KEY (senderType, senderID) REFERENCES tSenderReceiver,
      FOREIGN KEY (receiverType, receiverID) REFERENCES tSenderReceiver
)

tBufferStock (type INT, id INT,
      CHECK (type = 1),
      PRIMARY KEY (type, id),
      FOREIGN KEY (type, id) REFERENCES tSenderReceiver
)

tFacility (type INT, id INT,
      CHECK (type = 2),
      PRIMARY KEY (type, id),
      FOREIGN KEY (type, id) REFERENCES tSenderReceiver
)

tOutsideLocation (type INT, id INT,
      CHECK (type = 3),
      PRIMARY KEY (type, id),
      FOREIGN KEY (type, id) REFERENCES tSenderReceiver
)

【讨论】:

  • +1 我本来打算提出类似的建议,但你打败了我,而且还有表格定义!
  • 这类似于我在下面提出的建议。我将通过以下方式更改此架构:1)将三个特定表中的任何公共列(特别是名称或描述)移动到 tSenderReceiver 表(使基本检索更容易)和 2)向 tSenderReceiver 添加一个单独的自动编号主键以在 tTransaction 中保存一列并简化 JOIN。
  • @Larry Lusting: tSenderReceiver 现在几乎不会参与任何连接,它只会用于确保完整性。但是,如果有一些常见的列,那么您的建议确实是有道理的。我现在记得之前有过类似的回答:stackoverflow.com/questions/1493229/…
【解决方案3】:

SQL 不支持“表 X 中的这一列或表 Y 中的那一列”形式的外键。你可以:

  1. 重构您的数据库,以便将所有三个可能的外键表合并为一个,可能称为 tCounterParty。如果这些表的结构相同或非常相似,这绝对是合适的。如果它们不相似,您仍然可以采用这种方法并使用链接到 tCounterParty 的其他三个表来保存不同的信息。

  2. 如果您的数据库支持,将引用完整性从外键移到触发器中。

【讨论】:

    【解决方案4】:

    您不能使用 3 列作为发送方,3 列作为接收方吗?因此您将拥有 bufferSenderFK、facilitySenderFK 和 facilitySenderFK。对于单个交易,可以使用 1 列,其他 2 列将为空。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-07-06
      • 1970-01-01
      • 2011-05-06
      • 2012-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多