6

У меня есть таблица 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.TYPECURRENCY, а также в SECURITIES также проверяет, относится ли ссылка ASSETS.TYPE для SECURITIES.ID является SECURITY?

Возможно, я могу написать триггеры для проверки значения ASSETS.TYPE, но я ищу другое решение прямо сейчас (если возможно, конечно).

Если есть лучшие способы сделать то, что нужно (как лучший дизайн базы данных), пожалуйста, поделитесь своими идеями.

P.S. Я предполагаю, что это довольно распространенная проблема, поэтому, если есть статьи об этом или подобные вопросы, заданные в этой сети или некоторые общие решения, не стесняйтесь делиться ими.

+0

Смотрите мой ответ [здесь] (https: // StackOverflow.ком/а/26093733/3404097). (Этот конкретный вопрос смутно частично не имеет таблицы Student (ваш ASSESTS_DATA) в его исходном тексте, но имеет один в диаграмме «Редактирование».) Ваш первый дизайн похож на тот, который я предлагаю (относительно прямолинейно) (1-й набор пуль), а ваш может быть измененным/CHECKed, как я предлагаю (второй набор пуль) – philipxy

+0

@philipxy: как я отметил свой вопрос, FireBird. – potashin

+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')) 
); 

И подобный constraion для TO поля и в SECURITIES для CURRENCY области.
Но я думаю, что ваш новый дизайн, с отдельными FK для security и currency, лучший дизайн.

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

И Using Firebird, может потребоваться иной синтаксис. Взгляните: Firebird reference

+0

Синтаксис Firebird 'CHECK' тот же. –

+0

В вашем примере вы проверяете столбцы одной и той же таблицы, но можете ли вы привести пример, указывающий на значение столбца из другой таблицы? – potashin

+0

@notulysses В этом случае вам может быть лучше с переосмыслением вашей модели или с использованием триггеров. –

1

Вы можете сделать это декларативно, изменив дизайн своих ключей и используя идентифицирующие отношения.

Вот план:

enter image description here

Посмотрите, как ASSET.ASSET_TYPE распространяется через обе «ветви», только чтобы быть объединены в SECURITY.ASSET_TYPE.

С SECURITY.ASSET_TYPE - это только одно поле, одно из SECURITY строка никогда не может подключаться к нескольким типам активов. Сказать немного по-другому: если ASSET и CURRENCY подключены к тому же SECURITY, они должны иметь одинаковые ASSET_TYPE.

В дополнение к этому, CURRENCY никогда не может указывать на ASSET s различного типа.

При необходимости вы можете вернуть старые ключи суррогата (и другие поля) в эту модель.


Это, как говорится, генерируя ASSET_NO представляет некоторые проблемы.

  • Вы можете просто использовать auto-incrementing механизм встроенного в ваш DBMS, но что бы оставить «дыру» (то есть два различных типа актива никогда не будет использовать то же целое число, даже если они технически возможно).
  • Или вы можете найти следующее значение вручную, но в этом случае вам придется обрабатывать параллелизм (либо сериализовать вставки с помощью блокировки, либо вставить повторную попытку, если одновременная транзакция пробовала одно и то же значение).
2

IMO технически проект может быть подвергнут критике в двух категориях:

  • Имея двойного назначения внешнего ключа в таблице активов называется type (Polymorphic Association anti-pattern).
    Это будет нарушать первую нормальную форму (атомный вопрос), теряя ссылочную целостность.
    Решение может быть упрощение взаимосвязи по наследованию.
    Имея базу таблица для таблиц валюты и безопасности под названием Money, содержащая совместно используемые им свойства, например name.
    Первичный ключ денежной таблицы будет первичным ключом Currency и Security таблиц.
    Наличие внешнего ключа Money внутри Asset будет решением.
  • Использование surrogate identifier на таблицах активов, которые приведут Потеря бизнес-логики в схеме.
    Я предпочту иметь составной первичный ключ в таблице активов 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}

    enter image description here
+0

Была такая идея, как: таблица 'ASSET_TYPE' (одно поле' ID', возможные значения 'SECURITY' /' CURRENCY'), таблица 'MONEY' (не правильный выбор имени для этой таблицы, но в изяществе совместимости с ваш ответ, я оставляю его как есть) (два поля: 'ID',' TYPE' ('FK'' ASSET_TYPE.ID'). И триггер для вставки в таблицу 'SECURITIES' или' CURRENCIES' ('FX', выбирая правильные слова) на' MONEY.TYPE'. Наверное, я могу использовать только один триггер для решения этой проблемы. В вашем дизайне я вижу только один поток: я могу помещать ценные бумаги наподобие «GAZP» в таблицу «ВАЛЮТА» и наоборот. – potashin

+0

Извините за мой плохой английский. В моем ответе нет механизма триггеров, существует только две контрольные ограничения! Может быть, я не понимаю область вашего дизайна. позволяет поэтапно протекать по сценарию, чтобы узнать, что произойдет. Сначала мы определяем 'GAZP' как строку в Security? –

+0

Я не думаю, что вы не поняли эту концепцию, я просто не знаю, как сделать так, чтобы ценные бумаги не пошли в таблицу валют (aka fx) и наоборот. Кроме того, все они должны быть в денежный стол. – potashin

Смежные вопросы