2012-06-10 3 views
1
  • Я не хочу, чтобы заказы удалялись при удалении клиента. (On Delete Cascade)
  • Я использую столбцы идентификаторов, поэтому мне не нужно. Обновляйте каскад
  • Должна быть возможность удалить таблицу клиентов, хотя существуют указания, указывающие/ссылающиеся на клиента. Мне все равно, когда клиент ушел, потому что мне все еще нужна таблица заказов для других таблиц.

Имеет ли внешний ключ смысл в этом случае, когда я не использую ссылочную целостность с On/Delete Captade?Имеет ли внешний ключ смысл, когда я не использую ссылочную целостность с On Delete/Update Cascade

ответ

4

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

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

Можно, конечно, по-прежнему позволяют для заказов оставаться после удаления клиента. Ключ состоит в том, чтобы сделать столбец Orders.CustomerID нулевым, например.

CREATE TABLE dbo.Customers(CustomerID INT PRIMARY KEY); 

CREATE TABLE dbo.Orders(OrderID INT PRIMARY KEY, CustomerID INT NULL 
    FOREIGN KEY REFERENCES dbo.Customers(CustomerID)); 

Теперь, когда вы хотите удалить клиента, если вы контролировать эти операции с помощью хранимой процедуры, вы можете сделать это таким образом, первым установив их Orders.CustomerID в NULL:

CREATE PROCEDURE dbo.Customer_Delete 
    @CustomerID INT 
AS 
BEGIN 
    SET NOCOUNT ON; 

    UPDATE dbo.Orders SET CustomerID = NULL 
    WHERE CustomerID = @CustomerID; 

    DELETE dbo.Customers 
    WHERE CustomerID = @CustomerID; 
END 
GO 

Если вы можете «т управления специальной удалений из таблицы Customers, то вы можете добиться этого с вместо триггера:

CREATE TRIGGER dbo.Cascade_CustomerDelete 
ON dbo.Customers 
INSTEAD OF DELETE 
AS 
BEGIN 
    SET NOCOUNT ON; 

    UPDATE o SET CustomerID = NULL 
    FROM dbo.Orders AS o 
    INNER JOIN deleted AS d 
    ON o.CustomerID = d.CustomerID; 

    DELETE c 
    FROM dbo.Customers AS c 
    INNER JOIN deleted AS d 
    ON c.CustomerID = d.CustomerID; 
END 
GO 

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

+0

Я совершенно не расстраиваю ваш ответ, потому что, если вы говорите «да», я должен использовать их в своем сценарии, но этот ответ нарушает условие «3»: я хочу удалить клиента, хотя некоторые заказы ссылаются на этого клиента. Исправьте свое решение. – Elisabeth

+0

@Elisa Ваш вопрос: «Имеет ли внешний ключ смысл в этом сценарии, когда я не использую ссылочную целостность с помощью On/Delete Cascade?» Если это не вопрос, на который вы хотите, чтобы люди ответили, пожалуйста, исправьте свой вопрос. –

+0

Возможно, у моего образца заказчик заказов был глупым. Его просто образец, чтобы проиллюстрировать проблему. Я просто хочу разрешить пользователю удалять данные из родительских таблиц, но данные детей все равно могут читать. С помощью каскада delete или внешнего ключа. Я не могу это сделать. Исключение составляет отношение NULL/optional от 1 клиента к * .. N Заказ. Это решение просто препятствует тому, чтобы я получил ограничение внешнего ключа - исключение, исключающее клиента. НО, когда я не использую накладные расходы FK. У меня нет этой проблемы вообще. FK's и индекс на нем полезны только в этом случае: – Elisabeth

0

Таким образом, чтобы быть четкими, у вас есть FK от Заказчика до Заказов в настоящее время. Cascade update/delete не задействовано в этом отношении. Ваш план состоит в том, чтобы удалить клиентов, но разрешить приказы оставаться.

Это будет НАРУШИТЬ ограничение внешнего ключа; и предотвратить удаление. Если вы отключите ограничение, выполните удаление, а затем снова включите, вы можете заставить его работать.

Однако, это оставит в системе остатки орфографических ордеров; что может затруднить поддержку в долгосрочной перспективе. Какой следующий парень должен поддержать это?

Не было бы лучше сохранить записи и добавить статус активных/неактивных или созданных и неактивных дат?

Я борюсь с нарушением целостности базы данных, чтобы уменьшить пространство ...? Или в чем главная причина для удаления?

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

+0

Вы можете удалить клиента и установить 'Orders.CustomerID' в' NULL' (один из вариантов для каскада). Это все еще сиротская строка * в моем определении *, но ничего не нарушает, если столбец имеет значение NULL (например, если в общем случае нормально, чтобы заказ не принадлежал ни одному клиенту). Я склонен согласиться с вами, что не имеет смысла когда-либо удалять клиента, который имел хотя бы одну транзакцию в вашей системе. –

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