Reputation: 44601
I have a table ASSETS
that has a structure as it is shown below :
----------------------------------------------------
ID (PK) | DESCRIPTION | TYPE | Do- | Do+ | Dx- | Dx+
----------------------------------------------------
TYPE
column has a foreign key, possible values are SECURITY
or CURRENCY
(i.e. FX), also I have two more tables : CURRENCIES
(for example, EUR
, RUB
or USD
) :
--------------------------------------------------------
ID (PK)| FROM (FK ASSETS.ID) | TO (FK ASSETS.ID) | VALUE
--------------------------------------------------------
and SECURITIES
(for example, MTS
, GAZP
or VTB
) :
----------------------------------------------------------
ID (PK)(FK ASSETS.ID)| CURRENCY (PK)(FK ASSETS.ID) | VALUE
----------------------------------------------------------
How I can make a constraint, that not only acts like foreign key in CURRENCIES.FROM
, CURRENCIES.TO
and SECURITIES.CURRENCY
,but also checks if referring ASSETS.TYPE
is CURRENCY
, and in SECURITIES
also checks if referring ASSETS.TYPE
for SECURITIES.ID
is SECURITY
?
I guess I can write triggers to check ASSETS.TYPE
value, but I am searching for another solution right now (if it is possible, of course).
If there are better ways to do the things a want (as a better database design), please, share your ideas.
P.S. I guess it is quite a common problem, so if there are articles about it or similar questions asked on this network or some general-case-solutions, feel free to share.
Upvotes: 6
Views: 2954
Reputation: 7284
IMO technically the design could be criticized in two categories:
type
(Polymorphic
Association anti-pattern). Money
,containing shared properties of them, like name
. Currency
and Security
tables.Money
inside Asset
will be the solution.PK{ID, TYPE(money fk)}
.CURRENCIES
and SECURITIES
will solve the
problem.CURRENCIES_chk {FK.CURRENCY = FK_TO.Money && FK.CURRENCY = FK_FROM.Money}
SECURITIES_chk {FK.SECURITY = FK.Money}
Upvotes: 2
Reputation: 22759
Answer to your original question is to use an additional CHECK
constraint like :
CREATE TABLE CURRENCIES (
...
CONSTRAINT c_asset_from CHECK(exists(select 1 from ASSETS a where a.id = from and a.type = 'CURRENCY'))
);
And similar constraion for TO
field and in SECURITIES
for CURRENCY
field.
But I think your new design, with separate FK for security
and currency
, is better design.
Upvotes: 4
Reputation: 615
You could use checks for this. Do you want to hardcode these values?
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')
)
Source: W3schools
And using firebird might require different syntax. Take a look at: Firebird reference
Upvotes: 1
Reputation: 52157
You can do that declaratively by changing the design of your keys and using identifying relationships.
Here is the blueprint:
Look how ASSET.ASSET_TYPE
is propagated through both "branches", only to be merged in the SECURITY.ASSET_TYPE
.
Since SECURITY.ASSET_TYPE
is just one field, one SECURITY
row can never connect to multiple asset types. To say it slightly differently: if ASSET
and CURRENCY
are connected to the same SECURITY
, they must have the same ASSET_TYPE
.
In addition to that, CURRENCY
can never point to ASSET
s of different type.
You can bring back your old surrogate keys (and other fields) into this model as necessary.
That being said, generating ASSET_NO
presents some challenges.
auto-incrementing
mechanism built-into your DBMS
, but that would leave "holes" (i.e. two different asset types will never use the same integer, even though they technically can).Upvotes: 1