2009-06-15 37 views
32

¿Alguna versión de SQL Server admite restricciones diferibles (DC)?Restricciones diferibles en SQL Server

Desde aproximadamente la versión 8.0, Oracle has supported deferrable constraints - restricciones que solo se evalúan cuando se compromete un grupo de instrucciones, no cuando se insertan o actualizan tablas individuales. Las restricciones diferibles difieren de las restricciones de inhabilitación/habilitación, ya que las restricciones siguen activas: se evalúan más adelante (cuando se confirma el lote).

El beneficio de DC es que permiten que las actualizaciones que individualmente serían ilegales se evalúen y que cummulativamente resulten en un estado final válido. Un ejemplo es crear referencias circulares en una tabla entre dos filas donde cada fila requiere que exista un valor. Ninguna instrucción de inserción individual pasaría la restricción, pero el grupo sí.

Para aclarar mi objetivo, busco portar una implementación de ORM en C# a SQLServer - lamentablemente la implementación se basa en Oracle DC para evitar el cálculo de insertar/actualizar/eliminar pedidos entre filas.

+0

¿Básicamente está pidiendo una variante de [esta pregunta] (http://stackoverflow.com/questions/998267/deferred-constraint-checking)? –

Respuesta

9

Hasta ahora, SQL Server no los admite. ¿Cuál es el problema que estás resolviendo?

+0

Tenemos una capa ORM en nuestro sistema de negocios que aprovecha DC en Oracle que podemos desear para el puerto a SQL Server. Desafortunadamente, DC no parece ser compatible, lo que complica el esfuerzo de portar la implementación. En particular, la red de registros de cambios deberá procesarse de una manera muy particular (y difícil de calcular) para evitar violar cualquier restricción de RI. Solo buscando una forma de evitar tener que hacer esto. – LBushkin

+2

Escribí una pequeña publicación sobre esto hace algún tiempo. Básicamente, guarda las filas de los borradores en todas sus tablas, luego de marcarlas como terminadas, en cuyo momento se enciende RI. Google up "Imitando restricciones diferidas con columnas calculadas persistentes." –

3

Aparentemente no.

Encontré unas cinco publicaciones de blog diferentes, todas diciendo que SQLServer (en varias versiones) no es compatible con Restricciones Diferibles.

Por otro lado, también encontré un post que trata de imitar esta característica mediante el uso de "persisted computed columns," (desplazarse a la última entrada), pero caveat.emptor

+1

¿Parece que el enlace está roto? –

3

Parece que el problema que tiene es que SQL no admite lo que Date y Darwen llaman 'asignación múltiple'. La respuesta estándar de SQL a esto fue 'restricciones diferibles', que SQL Server no admite. Una restricción SQL Server FK o CHECK se puede marcar con NOCHECK pero no es lo mismo. Para obtener más detalles, consulte MSDN: ALTER TABLE (Transact-SQL).

21

OT: Hay en mi humilde opinión un buen número de cosas de SQL Server no es compatible, pero tendría sentido en un entorno empresarial:

  • limitaciones DEFERRABLE como se ha mencionado aquí
  • MARS: El por qué es lo que necesita establecer una opción para algo completamente natural?
  • Restricciones de CASCADE DELETE: SQL Server solo permite una única ruta de cascada para una determinada restricción CASCADE DELETE. Una vez más, no veo una razón por la cual no se debe permitir la cascada en la eliminación a través de múltiples caminos posibles: al final, en el momento en que realmente se ejecuta, siempre habrá una sola ruta que se usa realmente, entonces ¿por qué? es esta restricción?
  • Prevención de transacciones paralelas en una sola conexión ADO.NET.
  • Forzar cada comando ejecutado en una conexión que tiene una transacción que se ejecutará dentro de esta transacción.
  • Al crear un índice ÚNICO, NULL se trata como si fuera un valor real, y se le permite aparecer solo una vez en el índice. La noción de SQL NULL como un "valor desconocido" sería, sin embargo, indican, que los valores NULL ser ignorado por completo al crear el índice ...

Todas estas pequeñas cosas hacen que muchos de la integridad referencial y transaccionales características que se esperar de un RDBMS de tamaño completo casi inútil en SQL Server.Por ejemplo, dado que las restricciones diferibles no son compatibles, la noción de una "transacción" como una Unidad de Trabajo externamente consistente es parcialmente negada, la única solución viable -excepto por algunas soluciones sucias- es no definir en absoluto las restricciones de integridad referencial. Yo esperaría que el comportamiento natural de una transacción sea que usted puede trabajar dentro de ella en la forma y el orden de las operaciones que le gustan, y el sistema se asegurará de que sea consistente en el momento en que la cometa. Problemas similares surgen de la restricción de que una restricción de integridad referencial con ON DELETE CASCADE solo se puede definir de forma que solo una restricción individual pueda conducir a la eliminación en cascada de un objeto. Esto realmente no se ajusta a la mayoría de los escenarios del mundo real.

+2

Ahora puede tener índices únicos que contengan nulos utilizando un índice filtrado. – LMK

1

Si tiene su propia capa ORM, una solución a su problema podría ser separar la actualización del objeto de la actualización de referencia por la lógica de su capa ORM. Su ORM entonces trabajar con transacciones basadas en el cambio del lado del cliente establecido en varios pasos:

  1. borrar todas las referencias de clave externa definidas por su cambio establecido como el borrado, es decir, conjunto correspondiente columnas de clave externa a NULL, o , para las relaciones que utilizan tablas de asignación, ELIMINE las entradas de las tablas de asignación, según corresponda.
  2. Eliminar todos los objetos definidos como "borrado" por su cambio fija
  3. Crear todos los objetos nuevos en el conjunto de cambios, pero que aún no columnas del conjunto de claves externas
  4. Actualizar todos los cambios de valor "primitivos" en cualquier objetos actualizados en el conjunto de cambios, es decir, no actualiza las columnas de clave externa
  5. Establezca los valores de la columna de clave externa como se define en su conjunto de cambios.
  6. agregar asignaciones de la tabla de correspondencia de relaciones basadas en la tabla de asignación
  7. comprometerse

Esto debería resolver su problema, ya que existen todos los objetos que se hace referencia en ningún momento se establece un valor de clave externa ...

+0

O use un procedimiento almacenado y conéctelo a la Actualización de Insert() de esa Entidad en el ORM (Entity Framework y Linq to SQL permite esto http://stackoverflow.com/questions/5346601/stored-procedures-and- orms) –

1

Existe un método para evitar la aplicación de restricción aplazada faltante bajo ciertas condiciones (a partir de enero de 2017, no hay soporte para restricciones diferidas en SQL Server). Considere el siguiente esquema de base de datos:

exención de responsabilidad: La calidad del esquema, o el caso de uso, no es objeto de un debate aquí, se da como un ejemplo básico para la solución

CREATE TABLE T (Id TYPE NOT NULL PRIMARY KEY, NextId TYPE NOT NULL); 

ALTER TABLE T WITH CHECK ADD CONSTRAINT FK_T2T 
FOREIGN KEY (NextId) REFERENCES T (Id); 

CREATE UNIQUE NONCLUSTERED INDEX UC_T ON T (NextId); 

Donde TYPE es un tipo de datos adecuado para una clave sustituta. La suposición es que el valor de la clave sustituta es asignado por el RDBMS durante la operación INSERTAR (es decir, IDENTIDAD).

El caso de uso es mantener la "última" versión de la entidad T con NextId = NULL, y almacenar las versiones anteriores manteniendo una lista de enlaces únicos T.NextId -> T.Id.

Obviamente, el esquema dado está sujeto al problema de restricción diferida porque la inserción de la nueva "última versión" debe preceder a la actualización de la anterior "última" y durante ese tiempo habrá dos registros en la base de datos con el mismo valor de NextId.

Ahora, si:

El tipo de datos de la clave primaria no tiene que ser numéricas, y se puede calcular de antemano (es decir,UNIQUEIDENTIFIER), entonces el problema restricción diferida se evitó el uso de MERGE, así:

DECLARE TABLE @MergeTable TABLE (Id UNIQUEIDENTIFIER); 

DECLARE @NewLatestVersion UNIQUEIDENTIFIER = NEWID(); 

INSERT INTO @MergeTable (Id) VALUES (@NewLatestVersion); 
INSERT INTO @MergeTable (Id) VALUES (@OldLatestVersion); 

MERGE INTO T 
USING @MergeTable m ON T.Id = m.Id 
WHEN MATCHED THEN UPDATE SET T.NextId = @NewLatestVersion 
WHEN NOT MATCHED THEN INSERT (Id) VALUES (@NewLatestVersion); 

Al parecer, MERGE completa todas las manipulaciones de datos antes de comprobar las restricciones.