我有一张表ASSETS
,其结构如下所示:
----------------------------------------------------
ID (PK) | DESCRIPTION | TYPE | Do- | Do+ | Dx- | Dx+
----------------------------------------------------
TYPE
列有外键,可能的值为SECURITY
或CURRENCY
(即 FX ),我也有另外两个表:CURRENCIES
(例如,EUR
,RUB
或USD
):
--------------------------------------------------------
ID (PK)| FROM (FK ASSETS.ID) | TO (FK ASSETS.ID) | VALUE
--------------------------------------------------------
和SECURITIES
(例如,MTS
,GAZP
或VTB
):
----------------------------------------------------------
ID (PK)(FK ASSETS.ID)| CURRENCY (PK)(FK ASSETS.ID) | VALUE
----------------------------------------------------------
我如何制定一个约束,它不仅像CURRENCIES.FROM
,CURRENCIES.TO
和SECURITIES.CURRENCY
中的外键一样,还会检查引用ASSETS.TYPE
是否{{1在} CURRENCY
中还会检查SECURITIES
ASSETS.TYPE
的{{1}}是否为SECURITIES.ID
?
我想我可以编写触发器来检查SECURITY
值,但我现在正在寻找另一种解决方案(如果有可能,当然)。
如果有更好的方法来做所需的事情(作为更好的数据库设计),请分享您的想法。
P.S。我想这是一个非常普遍的问题,所以如果有关于它的文章或者在这个网络上提出的类似问题或者一些通用案例解决方案,请随时分享。
答案 0 :(得分:4)
对原始问题的回答是使用额外的CHECK
约束,如:
CREATE TABLE CURRENCIES (
...
CONSTRAINT c_asset_from CHECK(exists(select 1 from ASSETS a where a.id = from and a.type = 'CURRENCY'))
);
对TO
字段以及SECURITIES
CURRENCY
字段的类似约束。
但我认为你的新设计,security
和currency
的单独的 FK ,是更好的设计。
答案 1 :(得分:2)
IMO从技术上讲,设计可能会分为两类:
type
(Polymorphic
Association anti-pattern)的两用外键。 Money
的货币和安全表的表,包含它们的共享属性,如name
。 Currency
和Security
表的主键
将Money
内的Asset
外键设为解决方案。PK{ID, TYPE(money fk)}
中的复合主键。CURRENCIES
和SECURITIES
上的约束将解决问题
问题。CURRENCIES_chk {FK.CURRENCY = FK_TO.Money && FK.CURRENCY = FK_FROM.Money}
SECURITIES_chk {FK.SECURITY = FK.Money}
答案 2 :(得分:1)
你可以使用支票。 你想硬编码这些值吗?
CREATE TABLE Persons
(
P_Id int NOT NULL,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Address varchar(255),
City varchar(255),
CONSTRAINT chk_Person CHECK (P_Id>0 AND City='Sandnes')
)
来源:W3schools
使用firebird可能需要不同的语法。 看看:Firebird reference
答案 3 :(得分:1)
您可以通过更改密钥的设计和使用识别关系来声明性地执行此操作。
以下是蓝图:
了解ASSET.ASSET_TYPE
如何通过"分支"传播,仅在SECURITY.ASSET_TYPE
合并。
由于SECURITY.ASSET_TYPE
只是一个字段,因此一个SECURITY
行永远不能连接到多个资产类型。换句话说:如果ASSET
和CURRENCY
与同一SECURITY
相关联,则它们必须具有相同的ASSET_TYPE
。
除此之外,CURRENCY
永远不会指向不同类型的ASSET
。
您可以根据需要将旧的代理键(和其他字段)带回此模型。
话虽如此,生成ASSET_NO
会带来一些挑战。
auto-incrementing
的{{1}}机制,但这样会留下"漏洞" (即两种不同的资产类型永远不会使用相同的整数,即使它们在技术上可以)。