Si alguna vez te encuentras en la situación en la que necesitas volver a habilitar un CHECK
restricción que se ha deshabilitado previamente, definitivamente debe asegurarse de saber lo que está haciendo.
En particular, debe comprender la diferencia entre WITH NOCHECK
y WITH CHECK
argumentos.
Estos argumentos se pueden utilizar en el momento de habilitar la restricción. Especifican si los datos existentes se validan o no contra su CHECK
rehabilitado (o recién agregado) restricción. Básicamente, tiene la opción de verificar todos los datos existentes en busca de violaciones de la restricción. Si no especifica nada, los datos existentes no ser revisado Por eso es importante entender cómo funciona.
Por cierto, estos argumentos también se aplican a las restricciones de clave externa.
Como era de esperar, WITH CHECK
especifica que los datos existentes se validan y WITH NOCHECK
especifica que no lo es. El valor predeterminado es WITH NOCHECK
.
Si usa WITH NOCHECK
, la restricción se marcará como no confiable. En realidad, se marca como no confiable cuando deshabilita la restricción. Pero cuando lo vuelva a habilitar, seguirá sin ser de confianza a menos que use WITH CHECK
. En otras palabras, si desea reafirmar su "confiabilidad", debe especificarlo explícitamente.
En otras palabras:
- Cuando usas
WITH NOCHECK
, la restricción seguirá sin ser de confianza. - Cuando usas
WITH CHECK
se volverá confiable, pero solo si todos los datos existentes se ajustan a la restricción. Si algún dato existente viola la restricción, entonces la restricción no se habilitará y recibirá un mensaje de error.
Por supuesto, cuando digo "todos los datos existentes" solo me refiero a los datos a los que se aplica la restricción.
Puede haber escenarios en los que deshabilitó intencionalmente una restricción porque tuvo que ingresar datos que violan la restricción. En tales casos, si los datos no válidos deben permanecer en la base de datos, deberá usar WITH NOCHECK
si desea volver a habilitar la restricción. Esto le permitirá habilitar la restricción sin que ningún dato existente se interponga.
A continuación hay ejemplos que demuestran esto.
Ejemplo 1:revisar las restricciones CHECK
Primero, usemos sys.check_constraints
para echar un vistazo a todos CHECK
restricciones en la base de datos actual.
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Resultado:
+-----------------+---------------+------------------+----------------------------------------+ | name | is_disabled | is_not_trusted | definition | |-----------------+---------------+------------------+----------------------------------------| | chkPrice | 0 | 0 | ([Price]>(0)) | | chkValidEndDate | 0 | 0 | ([EndDate]>=[StartDate]) | | chkTeamSize | 0 | 0 | ([TeamSize]>=(5) AND [TeamSize]<=(20)) | | chkJobTitle | 0 | 0 | ([JobTitle]<>'Digital Nomad') | +-----------------+---------------+------------------+----------------------------------------+
Podemos ver que todos están habilitados y son confiables (porque todos tienen ceros en is_disabled y no_es_de_confianza columnas).
Para este artículo, deshabilitaré y volveré a habilitar chkJobTitle restricción.
Ejemplo 2:deshabilitar la restricción
Aquí, deshabilito el chkJobTitle restricción:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Listo.
Ahora revisemos todas las restricciones nuevamente:
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Resultado:
+-----------------+---------------+------------------+----------------------------------------+ | name | is_disabled | is_not_trusted | definition | |-----------------+---------------+------------------+----------------------------------------| | chkPrice | 0 | 0 | ([Price]>(0)) | | chkValidEndDate | 0 | 0 | ([EndDate]>=[StartDate]) | | chkTeamSize | 0 | 0 | ([TeamSize]>=(5) AND [TeamSize]<=(20)) | | chkJobTitle | 1 | 1 | ([JobTitle]<>'Digital Nomad') | +-----------------+---------------+------------------+----------------------------------------+
Podemos ver que ha sido deshabilitado (porque is_disabled la columna se establece en 1 ).
Puede notar que
is_not_trusted
la columna también se establece en
1
. Esto indica que el CHECK
el sistema no ha verificado la restricción para todas las filas.
Como se mencionó, un CHECK
solo se puede confiar en la restricción si todos los datos han superado con éxito las condiciones de la restricción. Cuando deshabilitamos una restricción, esto abre la posibilidad de que datos no válidos ingresen a la base de datos. Por lo tanto, no podemos estar 100% seguros de que todos los datos sean válidos, por lo que la restricción se marca como no confiable.
La forma de garantizar que la restricción sea confiable nuevamente es volver a habilitarla usando WITH CHECK
argumento. Esto hará que la restricción verifique todos los datos antes de que se vuelva a habilitar. Si algún dato no es válido, no se podrá volver a habilitar. Deberá actualizar los datos para que sean válidos o volver a habilitar la restricción mediante WITH NOCHECK
argumento en su lugar (lo que hará que la restricción no sea de confianza).
Ejemplo 3:habilite la restricción usando la configuración predeterminada (SIN COMPROBACIÓN)
Volvamos a habilitar la restricción y ejecutemos la consulta nuevamente.
Para habilitar la restricción, seré perezoso y usaré la configuración predeterminada:
ALTER TABLE Occupation CHECK CONSTRAINT chkJobTitle;
Ahora verifica el cambio:
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Resultado:
+-----------------+---------------+------------------+----------------------------------------+ | name | is_disabled | is_not_trusted | definition | |-----------------+---------------+------------------+----------------------------------------| | chkPrice | 0 | 0 | ([Price]>(0)) | | chkValidEndDate | 0 | 0 | ([EndDate]>=[StartDate]) | | chkTeamSize | 0 | 0 | ([TeamSize]>=(5) AND [TeamSize]<=(20)) | | chkJobTitle | 0 | 1 | ([JobTitle]<>'Digital Nomad') | +-----------------+---------------+------------------+----------------------------------------+
¿Viste lo que acaba de pasar? Aunque volví a habilitar la restricción, todavía no es de confianza.
Esto se debe a que fui perezoso (o tal vez simplemente olvidadizo) cuando habilité la restricción. Cuando habilité la restricción, olvidé especificar WITH CHECK
. El valor predeterminado es WITH NOCHECK
lo que significa que los datos existentes no se comprueban al volver a habilitar la restricción.
Esta es la razón por la que definitivamente debe saber lo que está haciendo al habilitar CHECK
(y FOREIGN KEY
) restricciones. Al ser perezosos y no especificar explícitamente una configuración potencialmente importante, le damos permiso a SQL Server para hacer la vista gorda ante cualquier problema con los datos existentes.
Sin embargo, si la única razón por la que necesita deshabilitar la restricción es para insertar datos que violan la restricción, entonces el valor predeterminado WITH NOCHECK
es probablemente lo que quieres.
Por cierto, para nuevas restricciones, el valor predeterminado es WITH CHECK
.
Pero en mi caso, no inserté ni actualicé ninguna datos después de deshabilitar la restricción, por lo que si antes era confiable, debería seguir siéndolo ahora.
Entonces, ¿cómo puedo volver a confiar en mi restricción?
Ejemplo 4:habilite la restricción usando WITH CHECK
Si quiero que se vuelva a confiar en mi restricción, necesito especificar explícitamente WITH CHECK
al volver a habilitarlo.
Desactivemos la restricción nuevamente:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Así que ahora vuelvo a donde estaba antes de volver a habilitarlo.
Lo que debería haber hecho cuando volví a habilitarlo fue esto:
ALTER TABLE Occupation WITH CHECK CHECK CONSTRAINT chkJobTitle;
Ahora echa otro vistazo a la restricción:
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Resultado:
+-----------------+---------------+------------------+----------------------------------------+ | name | is_disabled | is_not_trusted | definition | |-----------------+---------------+------------------+----------------------------------------| | chkPrice | 0 | 0 | ([Price]>(0)) | | chkValidEndDate | 0 | 0 | ([EndDate]>=[StartDate]) | | chkTeamSize | 0 | 0 | ([TeamSize]>=(5) AND [TeamSize]<=(20)) | | chkJobTitle | 0 | 0 | ([JobTitle]<>'Digital Nomad') | +-----------------+---------------+------------------+----------------------------------------+
¡Uf! Mi restricción es confiable una vez más.
Ejemplo 5:habilite la restricción CHECK con datos no válidos
Por supuesto, solo se vuelve a confiar en mi restricción porque no inserté datos no válidos mientras estaba deshabilitada. Si hubiera hecho esto, no podría habilitarlo usando WITH CHECK
, como se demuestra a continuación.
Si lo deshabilito de nuevo:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Ahora inserte datos no válidos (y devuelva los resultados):
INSERT INTO Occupation VALUES ( 7, 'Digital Nomad' ); SELECT OccupationId, JobTitle FROM Occupation;
Resultado:
+----------------+-----------------+ | OccupationId | JobTitle | |----------------+-----------------| | 1 | Engineer | | 2 | Accountant | | 3 | Cleaner | | 4 | Attorney | | 5 | Sales Executive | | 6 | Uber Driver | | 7 | Digital Nomad | +----------------+-----------------+
Así que insertamos con éxito datos no válidos (última fila).
Esto no es válido porque la definición de restricción es la siguiente:([JobTitle]<>'Digital Nomad')
Esto significa que el
JobTitle
la columna no debe contener el texto Digital Nomad
.
Ahora intentemos volver a habilitar el CHECK
restricción usando WITH CHECK
y ver qué pasa.
ALTER TABLE Occupation WITH CHECK CHECK CONSTRAINT chkJobTitle;
Resultado:
Msg 547, Level 16, State 0, Line 1 The ALTER TABLE statement conflicted with the CHECK constraint "chkJobTitle". The conflict occurred in database "Test", table "dbo.Occupation", column 'JobTitle'.
Entonces no podemos volver a habilitar la restricción usando WITH CHECK
mientras tenemos datos en la tabla que violan el CHECK
restricción. O necesitamos actualizar los datos o necesitamos usar WITH NOCHECK
(o simplemente omítalo por completo).
Intentémoslo de nuevo usando WITH NOCHECK
.
ALTER TABLE Occupation WITH NOCHECK CHECK CONSTRAINT chkJobTitle;
Resultado:
Commands completed successfully. Total execution time: 00:00:00.015
Entonces podemos habilitar con éxito la restricción si no verificamos los datos existentes.
Por supuesto, en este caso el CHECK
la restricción aún no es de confianza. Si queremos que se confíe en la restricción, necesitaremos actualizar los datos para que no violen la restricción.
Ejemplo:
UPDATE Occupation SET JobTitle = 'Unemployed' WHERE OccupationId = 7; SELECT OccupationId, JobTitle FROM Occupation;
Resultado:
+----------------+-----------------+ | OccupationId | JobTitle | |----------------+-----------------| | 1 | Engineer | | 2 | Accountant | | 3 | Cleaner | | 4 | Attorney | | 5 | Sales Executive | | 6 | Uber Driver | | 7 | Unemployed | +----------------+-----------------+
Ahora podemos modificar el CHECK
restricción para volver a ser confiable.
Hagamos los tres juntos:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle; ALTER TABLE Occupation WITH CHECK CHECK CONSTRAINT chkJobTitle; SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Resultado:
+-----------------+---------------+------------------+----------------------------------------+ | name | is_disabled | is_not_trusted | definition | |-----------------+---------------+------------------+----------------------------------------| | chkPrice | 0 | 0 | ([Price]>(0)) | | chkValidEndDate | 0 | 0 | ([EndDate]>=[StartDate]) | | chkTeamSize | 0 | 0 | ([TeamSize]>=(5) AND [TeamSize]<=(20)) | | chkJobTitle | 0 | 0 | ([JobTitle]<>'Digital Nomad') | +-----------------+---------------+------------------+----------------------------------------+
¡Así que ahora nuestra restricción está habilitada y es confiable una vez más, y nuestra base de datos está libre de nómadas digitales!