Справка по ограничениям SQL Server - PullRequest
0 голосов
/ 27 ноября 2009

У меня проблемы с подходящим ограничением в SQL Server 2005. Моя проблема связана со следующими таблицами:

Table PKTable
{
  pk integer primary key,
  property integer,
}

Table FKTable
{
  pk integer primary key,
  fk integer references PKTable(pk), 
}

Я действительно хочу сделать невозможным существование записи fk_rec, когда запись PKTable, на которую она ссылается, имеет свойство = 5. Первое, что я попытался сделать, это создать представление с привязкой к схеме со следующим запросом и создать уникальный индекс для поля UniqueCol.

SELECT     'True' AS UniqueCol, 'uh oh' AS DiffCol
FROM         FKTable INNER JOIN
                      PKTable ON FKTable.fk = PKTable.pk
WHERE      PKTable.property = 5
UNION
SELECT     'True' AS UniqueCol, 'default' AS DiffCol

Таким образом, в принципе запись ('True', 'default') всегда будет существовать в представлении, и когда кто-то пытается вставить строку в FKTable, а запись PKTable, на которую он ссылается, имеет свойство = 5, я получаю нарушение ограничения потому что первая часть запроса объединения что-то вернет. Это была идея в любом случае. Но SQL Server 2005 не допускает индексы для представлений, которые включают объединение. Затем я попытался создать другое представление:

SELECT UniqueCol, DiffCol FROM TheViewAbove

Поместить уникальный индекс в UniqueCol в этом случае не удастся, потому что у вас не может быть индексов в представлении, которое ссылается на другое представление. Я знал, что это был длинный выстрел. Есть ли способ обойти это?

Спасибо!

Ответы [ 4 ]

2 голосов
/ 27 ноября 2009

Два пути.

  1. Создайте таблицу подтипов (скажем, она называется NonProp5s, в которой есть только не свойство = 5 строк), а затем ссылается на pk в этой таблице подтипов из FKTable вместо основного PKTable. Это не обязательно что-то большее, чем столбец pk в нем, (Create Table NonProp5s (pk Integer Primary Key Not Null) ключ в том, что вставка в родительский pkTable всегда вставляет строку в NonProp5s с тем же значением pk, , за исключением , где значение свойства равно 5. (Вам также понадобится триггер обновления для вставки / удаления строки всякий раз, когда значение свойства в PKTable изменяется на / с 5.)
  2. Создать 2 триггера. Один на вставку / обновление таблицы FK, которая откатывает транзакцию, если вы пытаетесь вставить запись, которая ссылается на строку PK со свойством = 5, и Второй триггер при обновлении таблицы PK, которая откатывает транзакцию, если пытается изменить свойство на значение = 5, если в FKTable есть дочерние записи.
1 голос
/ 27 ноября 2009
  1. Создание уникального ограничения для PKTable (pk, свойство)
  2. Добавьте столбец PK_property в вашу дочернюю таблицу. Имейте проверочное ограничение, гарантирующее, что (свойство <> 5)
  3. Иметь внешний ключ, относящийся (pk, pk_property) к PKTable (pk, свойство)
0 голосов
/ 28 ноября 2009

Вы также можете использовать триггеры для реализации ограничений, например:

Первое создание таблиц:

CREATE TABLE tPK(
ID int NOT NULL PRIMARY KEY
,[Property] int NULL
)
go

CREATE TABLE tFK(
ID int NOT NULL PRIMARY KEY
,fk int NOT NULL
)
go

ALTER TABLE tFK ADD
CONSTRAINT FK1_tFK FOREIGN KEY(fk) REFERENCES tPK(ID)
    ON UPDATE CASCADE
    ON DELETE CASCADE
go  

Затем добавьте триггер в родительскую таблицу

CREATE TRIGGER trgPK ON tPK
    AFTER INSERT, UPDATE
AS
IF UPDATE(Property) 
    BEGIN
        DELETE  FROM tFK 
        WHERE   fk IN ( SELECT  T.ID
                        FROM    tPK AS T
                        WHERE   T.[Property] = 5 )

    END
go

А на дочернем столе:

CREATE TRIGGER trgFK ON dbo.tFK
    AFTER INSERT, UPDATE
AS
IF UPDATE(fk) 
    BEGIN
        DELETE  FROM tFK 
        WHERE   fk IN ( SELECT  T.ID
                        FROM    tPK AS T
                        WHERE   T.[Property] = 5 )

    END
GO

Если вам нужно много загружать, тогда:

  1. отключить оба триггера,
  2. данные загрузки,
  3. включить оба триггера,
  4. обновить строку в любой таблице.
0 голосов
/ 27 ноября 2009

Я действительно не хотел менять таблицы или отношения между таблицами, поэтому вот что я сделал:

Я создал таблицу с именем DummyTable, в которой более 1 записи. Я положил 2 в нем. Затем я построил представление:

SELECT pk FROM FKTable 
    INNER JOIN PKTable ON FKTable.fk = PKTable.pk
    INNER JOIN DummyTable ON 1 = 1
WHERE PKTable.property = 5

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

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