Как добавить ограничение внешнего ключа в таблицу A (идентификатор, тип), ссылающуюся на одну из двух таблиц: таблицу B (идентификатор, тип) или таблицу C (идентификатор, тип)? - PullRequest
0 голосов
/ 05 февраля 2019

Я хочу использовать два столбца в таблице A в качестве внешних ключей для одной из двух таблиц: таблицы B или таблицы C. Используя столбцы table_a.item_id и table_a.item_type_id, я хочу, чтобы любые новые строки имели либосовпадающие item_id и item_type_id в Таблице B или Таблице C.

Пример:

Table A: Inventory 
+---------+--------------+-------+
| item_id | item_type_id | count |
+---------+--------------+-------+
|       2 |            1 |    32 |
|       3 |            1 |    24 |
|       1 |            2 |    10 |
+---------+--------------+-------+

Table B: Recipes
+----+--------------+-------------------+-------------+----------------------+
| id | item_type_id |       name        | consistency | gram_to_fluid_ounces |
+----+--------------+-------------------+-------------+----------------------+
|  1 |            1 | Delicious Juice   | thin        | .0048472             |
|  2 |            1 | Ok Tasting Juice  | thin        | .0057263             |
|  3 |            1 | Protein Smoothie  | heavy       | .0049847             |
+----+--------------+-------------------+-------------+----------------------+

Table C: Products
+----+--------------+----------+--------+----------+----------+
| id | item_type_id |   name   | price  | in_stock | is_taxed |
+----+--------------+----------+--------+----------+----------+
|  1 |            2 | Purse    | $200   | TRUE     | TRUE     |
|  2 |            2 | Notebook | $14.99 | TRUE     | TRUE     |
|  3 |            2 | Computer | $1,099 | FALSE    | TRUE     |
+----+--------------+----------+--------+----------+----------+

Other Table: Item_Types
+----+-----------+
| id | type_name |
+----+-----------+
|  1 | recipes   |
|  2 | products  |
+----+-----------+

Я хочу иметь таблицу инвентаризации, где сотрудники могут вводить запасысчитается независимо от того, является ли продукт рецептом или продуктом.Я не хочу иметь таблицы product_inventory и recipe_inventory, так как мне нужно выполнить много операций со всеми элементами инвентаря независимо от типов элементов.

Одним из решений было бы создание справочной таблицы следующим образом:

Table CD: Items
+---------+--------------+------------+-----------+
| item_id | item_type_id | product_id | recipe_id |
+---------+--------------+------------+-----------+
|       2 |            1 | NULL       | 2         |
|       3 |            1 | NULL       | 3         |
|       1 |            2 | 1          | NULL      |
+---------+--------------+------------+-----------+

Это просто кажется очень громоздким, плюс мне теперь нужно было бы добавлять / удалять продукты / рецепты из этой новой таблицы всякий раз, когда они добавляются / удаляются из соответствующих таблиц.(Есть ли автоматический способ добиться этого?)

CREATE TABLE [dbo].[inventory] (
    [id] [bigint] IDENTITY(1,1) NOT NULL,
    [item_id] [smallint] NOT NULL,
    [item_type_id] [tinyint] NOT NULL,
    [count] [float] NOT NULL,
CONSTRAINT [PK_inventory_id] PRIMARY KEY CLUSTERED ([id] ASC)
) ON [PRIMARY]

Что я действительно хотел бы сделать, это что-то вроде этого ...

ALTER TABLE [inventory]  
ADD  CONSTRAINT [FK_inventory_sources] FOREIGN KEY ([item_id],[item_type_id])
REFERENCES {[products] ([id],[item_type_id]) OR [recipes] ([id],[item_type_id])}

Может быть, нет решения, как яЯ описываю это, так что если у вас есть какие-либо идеи, где я могу поддерживать ту же / аналогичную схему, я определенно открыт для их изучения!Спасибо:)

Ответы [ 4 ]

0 голосов
/ 05 февраля 2019

Поскольку ваши продукты и рецепты хранятся отдельно и, по-видимому, в большинстве своем имеют отдельные столбцы, то, вероятно, правильный подход - использовать отдельные таблицы инвентаризации.Например,

CREATE TABLE dbo.ProductInventory
(
        Product_id INT NOT NULL,
        [count] INT NOT NULL,
    CONSTRAINT FK_ProductInventory__Product_id FOREIGN KEY (Product_id) 
        REFERENCES dbo.Product (Product_id)
);

CREATE TABLE dbo.RecipeInventory
(
        Recipe_id INT NOT NULL,
        [count] INT NOT NULL,
    CONSTRAINT FK_RecipeInventory__Recipe_id FOREIGN KEY (Recipe_id) 
        REFERENCES dbo.Recipe (Recipe_id )
);

Если вам нужно объединить все типы, вы можете просто использовать представление:

CREATE VIEW dbo.Inventory
AS
    SELECT  Product_id AS item_id,
            2 AS item_type_id,
            [Count]
    FROM    ProductInventory
    UNION ALL
    SELECT  recipe_id AS item_id,
            1 AS item_type_id
            [Count]
    FROM    RecipeInventory;
GO

Если вы создаете новый item_type, то вам все равно нужно изменить дизайн БД, чтобысоздайте новую таблицу, так что вам просто нужно будет одновременно изменить представление

Другая возможность - это иметь одну таблицу «Предметы», а затем сделать ссылку «Продукты / рецепты» на это.Итак, вы начинаете с таблицы элементов, каждая из которых имеет уникальный идентификатор:

CREATE TABLE dbo.Items
(
        item_id INT IDENTITY(1, 1) NOT NULL 
        Item_type_id INT NOT NULL,
    CONSTRAINT PK_Items__ItemID PRIMARY KEY (item_id),
    CONSTRAINT FK_Items__Item_Type_ID FOREIGN KEY (Item_Type_ID) REFERENCES Item_Type (Item_Type_ID),
    CONSTRAINT UQ_Items__ItemID_ItemTypeID UNIQUE (Item_ID, Item_type_id)
);

Обратите внимание на уникальный ключ, добавленный в (item_id, item_type_id), это важно для ссылочной целостности позже.

Тогда каждая из ваших вложенных таблиц имеет отношение 1: 1 с этим, поэтому ваша таблица продуктов будет иметь вид:

CREATE TABLE dbo.Products
(
        item_id BIGINT NOT NULL,
        Item_type_id AS 2,
        name VARCHAR(50) NOT NULL,
        Price DECIMAL(10, 4) NOT NULL,
        InStock BIT NOT NULL,
    CONSTRAINT PK_Products__ItemID PRIMARY KEY (item_id),
    CONSTRAINT FK_Products__Item_Type_ID FOREIGN KEY (Item_Type_ID) 
        REFERENCES Item_Type (Item_Type_ID),
    CONSTRAINT FK_Products__ItemID_ItemTypeID FOREIGN KEY (item_id, Item_Type_ID) 
        REFERENCES dbo.Item (item_id, item_type_id)
);

Несколько замечаний:

  • item_id isснова первичный ключ, обеспечивающий соотношение 1: 1.
  • вычисляемый столбец item_type_id (как 2), гарантирующий, что все item_type_id установлены в 2. Это ключ, поскольку он позволяет добавить ограничение внешнего ключа
  • внешний ключ на (item_id, item_type_id) вернуться к таблице предметов.Это гарантирует, что вы можете вставить запись в таблицу продуктов только в том случае, если исходная запись в таблице товаров имеет item_type_id, равный 2.

Третьим вариантом будет отдельная таблица для рецептов и продуктов исделать любые столбцы не обязательными для обоих обнуляемых. Этот ответ о типах наследования стоит прочитать.

0 голосов
/ 05 февраля 2019

Я думаю, что в вашей базе данных есть недостаток.Лучший способ решить вашу актуальную проблему - это иметь рецепты и продукты в одной таблице.Прямо сейчас у вас есть избыточный столбец в каждой таблице с именем item_type_id.Этот столбец ничего не стоит, если только у вас нет элементов в одной таблице.Я говорю избыточно, потому что оно имеет одинаковое значение для абсолютно каждой записи в каждой таблице.

У вас есть два варианта.Если вы не можете изменить дизайн базы данных, работайте без внешних ключей и сделайте логический слой выбранным из правильных таблиц.

Или, если вы можете изменить дизайн базы данных, сделайте продукты и получатели существующими в одной таблице,У вас уже есть таблица item_type, которая может идентифицировать категоризацию элементов, поэтому имеет смысл поместить все элементы в одну таблицу

0 голосов
/ 05 февраля 2019

Вы можете добавить некоторые вычисляемые столбцы в таблицу Inventory:

ALTER TABLE Inventory
    ADD _recipe_item_id AS CASE WHEN item_type_id = 1 THEN item_id END persisted
ALTER TABLE Inventory
    ADD _product_item_id AS CASE WHEN item_type_id = 2 THEN item_id END persisted

Затем вы можете добавить два отдельных внешних ключа к двум таблицам, используя эти два столбца вместо item_id.Я предполагаю, что столбец item_type_id в этих двух таблицах уже рассчитан / ограничен соответствующим образом, но если нет, то вы можете рассмотреть это тоже.

Поскольку эти вычисленные столбцы NULL, когда выбран неправильный типи поскольку SQL Server не проверяет ограничения FK, если хотя бы одно значение столбца равно NULL, они оба могут существовать, и в любой момент будет выполняться только одно или другое.

0 голосов
/ 05 февраля 2019

Вы можете добавить только одно ограничение для столбца или пары столбцов.Подумайте о яблоках и апельсинах.Столбец не может ссылаться как на апельсины, так и на яблоки.Это должен быть либо апельсин, либо яблоко.

Как примечание: это может быть каким-то образом достигнуто с помощью PERSISTED COMPUTED columns, однако это только приводит к накладным расходам и сложности.

Проверьте это для справки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...