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.
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.
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}
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).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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With