Регистрация добавить ограничения, после проверочного ограничения и добавить ограничение
Я смотрю на образец базы данных AdventureWorks для SQL Server 2008, и я вижу в их сценарии создания, что они, как правило, используют следующее:
ALTER TABLE [Production].[ProductCostHistory] WITH CHECK ADD
CONSTRAINT [FK_ProductCostHistory_Product_ProductID] FOREIGN KEY([ProductID])
REFERENCES [Production].[Product] ([ProductID])
GO
сразу же после этого:
ALTER TABLE [Production].[ProductCostHistory] CHECK CONSTRAINT
[FK_ProductCostHistory_Product_ProductID]
GO
Я вижу это для внешних ключей (как здесь), уникальных ограничений и регулярных CHECK
ограничения; DEFAULT
ограничения используют обычный формат, с которым я больше знаком, например:
ALTER TABLE [Production].[ProductCostHistory] ADD CONSTRAINT
[DF_ProductCostHistory_ModifiedDate] DEFAULT (getdate()) FOR [ModifiedDate]
GO
в чем разница, если таковая имеется, между тем, чтобы сделать это первым способом по сравнению со вторым?
7 ответов:
первый синтаксис является избыточным - проверка WITH используется по умолчанию для новых ограничений, и ограничение также включено по умолчанию.
этот синтаксис генерируется SQL management studio при создании сценариев sql - я предполагаю, что это какая-то дополнительная избыточность, возможно, чтобы гарантировать, что ограничение включено, даже если поведение ограничения по умолчанию для таблицы изменено.
чтобы продемонстрировать, как это работает--
CREATE TABLE T1 (ID INT NOT NULL, SomeVal CHAR(1)); ALTER TABLE T1 ADD CONSTRAINT [PK_ID] PRIMARY KEY CLUSTERED (ID); CREATE TABLE T2 (FKID INT, SomeOtherVal CHAR(2)); INSERT T1 (ID, SomeVal) SELECT 1, 'A'; INSERT T1 (ID, SomeVal) SELECT 2, 'B'; INSERT T2 (FKID, SomeOtherVal) SELECT 1, 'A1'; INSERT T2 (FKID, SomeOtherVal) SELECT 1, 'A2'; INSERT T2 (FKID, SomeOtherVal) SELECT 2, 'B1'; INSERT T2 (FKID, SomeOtherVal) SELECT 2, 'B2'; INSERT T2 (FKID, SomeOtherVal) SELECT 3, 'C1'; --orphan INSERT T2 (FKID, SomeOtherVal) SELECT 3, 'C2'; --orphan --Add the FK CONSTRAINT will fail because of existing orphaned records ALTER TABLE T2 ADD CONSTRAINT FK_T2_T1 FOREIGN KEY (FKID) REFERENCES T1 (ID); --fails --Same as ADD above, but explicitly states the intent to CHECK the FK values before creating the CONSTRAINT ALTER TABLE T2 WITH CHECK ADD CONSTRAINT FK_T2_T1 FOREIGN KEY (FKID) REFERENCES T1 (ID); --fails --Add the CONSTRAINT without checking existing values ALTER TABLE T2 WITH NOCHECK ADD CONSTRAINT FK_T2_T1 FOREIGN KEY (FKID) REFERENCES T1 (ID); --succeeds ALTER TABLE T2 CHECK CONSTRAINT FK_T2_T1; --succeeds since the CONSTRAINT is attributed as NOCHECK --Attempt to enable CONSTRAINT fails due to orphans ALTER TABLE T2 WITH CHECK CHECK CONSTRAINT FK_T2_T1; --fails --Remove orphans DELETE FROM T2 WHERE FKID NOT IN (SELECT ID FROM T1); --Enabling the CONSTRAINT succeeds ALTER TABLE T2 WITH CHECK CHECK CONSTRAINT FK_T2_T1; --succeeds; orphans removed --Clean up DROP TABLE T2; DROP TABLE T1;
В дополнение к вышеизложенным замечательным комментариям о доверенных ограничениях:
select * from sys.foreign_keys where is_not_trusted = 1 ; select * from sys.check_constraints where is_not_trusted = 1 ;
ненадежному ограничению, как и предполагает его название, нельзя доверять, чтобы точно представлять состояние данных в таблице прямо сейчас. Он может, однако, но можно доверять, чтобы проверить данные, добавленные и измененные в будущем.
кроме того, оптимизатор запросов игнорирует ненадежные ограничения.
код для включения проверочных ограничений и внешнего ключа ограничения довольно плохие, с тремя значениями слова "проверка".
ALTER TABLE [Production].[ProductCostHistory] WITH CHECK -- This means "Check the existing data in the table". CHECK CONSTRAINT -- This means "enable the check or foreign key constraint". [FK_ProductCostHistory_Product_ProductID] -- The name of the check or foreign key constraint, or "ALL".
WITH NOCHECK
используется также, когда у вас есть существующие данные в таблице, которая не соответствует ограничению, как определено, и вы не хотите, чтобы он нарушал новое ограничение, которое вы реализуете...
WITH CHECK
действительно поведение по умолчанию, однако это хорошая практика, чтобы включить в вашем кодировании.альтернативное поведение, конечно, использовать
WITH NOCHECK
, поэтому хорошо явно определить ваши намерения. Это часто используется, когда вы играете с/изменение/переключение встроенных разделов.
ограничения внешнего ключа и проверки имеют концепцию доверия или недоверия, а также включения и отключения. См. страницу MSDN для
ALTER TABLE
для полной информации.
WITH CHECK
является значением по умолчанию для добавления новых ограничений внешнего ключа и проверки,WITH NOCHECK
по умолчанию для повторного включения внешних ключей и ограничений. Важно осознавать разницу.сказав это, любые явно избыточные операторы, генерируемые утилитами, являются просто там для безопасности и/или простоты кодированием. Не беспокойся о них.
вот код, который я написал, чтобы помочь нам определить и исправить ненадежные ограничения в базе данных. Он генерирует код для каждого вопроса.
;WITH Untrusted (ConstraintType, ConstraintName, ConstraintTable, ParentTable, IsDisabled, IsNotForReplication, IsNotTrusted, RowIndex) AS ( SELECT 'Untrusted FOREIGN KEY' AS FKType , fk.name AS FKName , OBJECT_NAME( fk.parent_object_id) AS FKTableName , OBJECT_NAME( fk.referenced_object_id) AS PKTableName , fk.is_disabled , fk.is_not_for_replication , fk.is_not_trusted , ROW_NUMBER() OVER (ORDER BY OBJECT_NAME( fk.parent_object_id), OBJECT_NAME( fk.referenced_object_id), fk.name) AS RowIndex FROM sys.foreign_keys fk WHERE is_ms_shipped = 0 AND fk.is_not_trusted = 1 UNION ALL SELECT 'Untrusted CHECK' AS KType , cc.name AS CKName , OBJECT_NAME( cc.parent_object_id) AS CKTableName , NULL AS ParentTable , cc.is_disabled , cc.is_not_for_replication , cc.is_not_trusted , ROW_NUMBER() OVER (ORDER BY OBJECT_NAME( cc.parent_object_id), cc.name) AS RowIndex FROM sys.check_constraints cc WHERE cc.is_ms_shipped = 0 AND cc.is_not_trusted = 1 ) SELECT u.ConstraintType , u.ConstraintName , u.ConstraintTable , u.ParentTable , u.IsDisabled , u.IsNotForReplication , u.IsNotTrusted , u.RowIndex , 'RAISERROR( ''Now CHECKing {%i of %i)--> %s ON TABLE %s'', 0, 1' + ', ' + CAST( u.RowIndex AS VARCHAR(64)) + ', ' + CAST( x.CommandCount AS VARCHAR(64)) + ', ' + '''' + QUOTENAME( u.ConstraintName) + '''' + ', ' + '''' + QUOTENAME( u.ConstraintTable) + '''' + ') WITH NOWAIT;' + 'ALTER TABLE ' + QUOTENAME( u.ConstraintTable) + ' WITH CHECK CHECK CONSTRAINT ' + QUOTENAME( u.ConstraintName) + ';' AS FIX_SQL FROM Untrusted u CROSS APPLY (SELECT COUNT(*) AS CommandCount FROM Untrusted WHERE ConstraintType = u.ConstraintType) x ORDER BY ConstraintType, ConstraintTable, ParentTable;