SQL: Могу ли я написать ограничение CHECK, которое проверяет данные во внешней таблице с использованием внешнего ключа? - PullRequest
0 голосов
/ 21 января 2012

Я проектирую тестовую базу данных в SQL Server 2008 R2 и / или SQL Azure. (Пока весь мой код будет работать на обоих.)

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

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

CREATE TABLE CustomerOrder
(
    ID INT NOT NULL IDENTITY PRIMARY KEY,
    CustomerID INT NOT NULL UNIQUE
        FOREIGN KEY REFERENCES Customer(ID)
        ON DELETE NO ACTION ON UPDATE CASCADE,
    ProductID INT NOT NULL UNIQUE
        FOREIGN KEY REFERENCES Product(ID)
        ON DELETE NO ACTION ON UPDATE CASCADE,
    Quantity INT NOT NULL DEFAULT 1,
    IsPaid BIT NOT NULL DEFAULT 0
)
GO

CREATE TABLE RMA
(
    ID INT NOT NULL IDENTITY PRIMARY KEY,
    CustomerOrderID INT NOT NULL UNIQUE
        FOREIGN KEY REFERENCES CustomerOrder(ID)
        ON DELETE NO ACTION ON UPDATE CASCADE,

    -- Add constraint to prevent RMAs from being
    -- created for orders that have not been paid.
    -- This could be a column constraint, or a table constraint.

    CHECK ( CustomerOrderID.IsPaid = 1 )

    -- ERROR: 'The multi-part identifier "CustomerOrderID.IsPaid"
    --         could not be bound.'
)
GO

В этом примере не имеет смысла помещать ограничение CHECK в таблицу CustomerOrder, потому что строка в таблице CustomerOrder полностью удовлетворена тем, что ей не платят, если для заказа нет RMA. Кроме того, ограничение в таблице CustomerOrder по-прежнему должно ссылаться на таблицу RMA для подтверждения наличия RMA, поэтому остается та же проблема.

Я также пробовал:

CHECK (EXISTS(SELECT co.ID FROM CustomerOrder co
              WHERE co.ID=CustomerOrderID AND
                    co.IsPaid=1))
-- ERROR: 'Subqueries are not allowed in this context.
--         Only scalar expressions are allowed.'

Поскольку это статическое ограничение для проверки основных данных, и на него никогда не будут ссылаться никакие другие объекты, я бы хотел избежать превращения этого в скалярную функцию или хранимую процедуру.
Однако, чтобы избежать использования скалярной функции, мне нужно будет определить ограничение в SQL (желательно одновременно с развертыванием моей базы данных и созданием таблицы).

Какой синтаксис SQL я мог бы использовать здесь для определения этого типа ограничения?

1 Ответ

2 голосов
/ 21 января 2012

Другой вариант (поскольку вы запрашивали решение без добавления триггеров или увеличения внешнего ключа), это удаление столбца IsPaid и добавление еще одной таблицы для платных заказов:

CREATE TABLE CustomerOrder
(
    ID INT NOT NULL IDENTITY PRIMARY KEY,
    CustomerID INT NOT NULL UNIQUE
        FOREIGN KEY REFERENCES Customer(ID)
        ON DELETE NO ACTION ON UPDATE CASCADE,
    ProductID INT NOT NULL UNIQUE
        FOREIGN KEY REFERENCES Product(ID)
        ON DELETE NO ACTION ON UPDATE CASCADE,
    Quantity INT NOT NULL DEFAULT 1
)
GO

CREATE TABLE CustomerOrderPaid
(
    ID INT NOT NULL PRIMARY KEY
        FOREIGN KEY REFERENCES CustomerOrder(ID)
        ON DELETE NO ACTION ON UPDATE CASCADE
)
GO

CREATE TABLE RMA
(
    ID INT NOT NULL IDENTITY PRIMARY KEY,
    CustomerOrderID INT NOT NULL UNIQUE
        FOREIGN KEY REFERENCES CustomerOrderPaid(ID)
        ON DELETE NO ACTION ON UPDATE CASCADE,
)
GO
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...