2010-02-04 9 views
5

Estamos realizando una migración de base de datos a SQL Server, y para admitir una aplicación heredada, hemos definido vistas en la tabla de SQL Server que presentan datos como espera la aplicación heredada.Uso de valores predeterminados en un desencadenador INSTEAD OF INSERT

Sin embargo, ahora estamos teniendo problemas con los desencadenadores INSTEAD OF INSERT definidos en esas vistas, cuando los campos pueden tener valores predeterminados.

Trataré de dar un ejemplo.

Una tabla en la base de datos tiene 3 campos, a, b y c. c es nuevo, la aplicación heredada no lo conoce, por lo que también tenemos una vista con 2 campos, a y b.

Cuando la aplicación legado intenta insertar un valor en su opinión, se utiliza un desencadenador INSTEAD OF INSERT para buscar el valor que debe ir en el campo c, algo como esto:

INSERT INTO realTable(a, b, c) SELECT Inserted.a, Inserted.b, Calculated.C FROM... 

(Los detalles de la búsqueda no es relevante.)

Este disparador funciona bien, a menos que el campo b tenga un valor predeterminado. Este es el valor por defecto porque si se ejecuta la consulta

INSERT INTO legacyView(a) VALUES (123) 

, a continuación, en el gatillo, Inserted.b es NULL, no de b. Ahora tengo un problema, porque no puedo decir la diferencia de la consulta anterior, lo que pondría el valor por defecto en b, y esto:

INSERT INTO legacyView(a,b) VALUES (123, NULL) 

Incluso si B era no anulable, no sé cómo escribir la consulta INSERTAR en el desencadenante de modo que si se proporcionó un valor para b, se usa en el desencadenador, pero si no se utiliza el valor predeterminado se utiliza en su lugar.

EDITAR: agregó que preferiría no duplicar los valores predeterminados en el desencadenador. Los valores predeterminados ya están en el esquema de la base de datos, espero que pueda usarlos directamente.

+0

¡Saber que todos sus campos con valores predeterminados no aceptan nulos es enorme! Podría haber tenido una solución para ti si hubiera sabido esta información. – ErikE

+0

Lo siento Emtucifor, no sabía en ese momento que publiqué la pregunta de que no teníamos ningún valor predeterminado en los campos con nulos. ¿Cuál hubiera sido tu solución? Si es bueno, aún puedo votarlo y quizás cambiar la respuesta aceptada. –

Respuesta

1

Paul: He resuelto este; finalmente. Poco de una solución sucia y podría no ser del gusto de todos, pero estoy bastante nuevo en SQL Server y cosas semejantes a estas

En el gatillo Instead_of_INSERT:

  1. Copiar estructura de datos de la tabla virtual insertado a una tabla temporal:

    SELECT * INTO aTempInserted FROM Inserted WHERE 1=2 
    
  2. crear una vista para determinar las restricciones predeterminadas para la tabla subyacente de la vista (de las tablas del sistema) y usarlos para construir declaraciones que duplicar las restricciones en la tabla temporal:

    SELECT 'ALTER TABLE dbo.aTempInserted 
           ADD CONSTRAINT ' + dc.name + 'Temp' + 
           ' DEFAULT(' + dc.definition + ') 
           FOR ' + c.name AS Cmd, OBJECT_NAME(c.object_id) AS Name 
        FROM sys.default_constraints AS dc 
    INNER JOIN sys.columns AS c 
          ON dc.parent_object_id = c.object_id 
         AND dc.parent_column_id = c.column_id 
    
  3. Utilice un cursor para recorrer el conjunto recuperado y ejecutar cada instrucción. Esto le deja una tabla temporal con los mismos valores predeterminados que la tabla en la que se insertará.

  4. inserción de registro por defecto en la tabla temporal (todos los campos son anulable como creado a partir de mesa virtual insertado):

    INSERT INTO aTempInserted DEFAULT VALUES 
    
  5. copia los registros de la tabla virtual insertado en la tabla subyacente de la vista (en la que lo harían se han insertado originalmente, si el activador no lo hubiera impedido), uniéndose a la tabla temporal para proporcionar valores predeterminados. Esto requiere el uso de la función COALESCE para que sólo los valores desabastecidas están predeterminadas:

    INSERT INTO realTable([a], [b], 
          SELECT COALESCE(I.[a], T.[a]), 
            COALESCE(I.[a], T.[b]) 
          FROM Inserted  AS I, 
            aTempInserted AS T 
    
  6. eliminar la tabla temporal

+0

Eso está casi ahí; todavía no se puede distinguir la diferencia (en el paso 5) entre un valor NULL porque el valor no se especificó (por lo tanto, use el valor predeterminado) y un valor NULL porque se especificó un valor NULL (por lo tanto, no use el valor predeterminado. Sin embargo, esto es solo un problema si tiene un campo que admite valores NULL, lo que no creo que hagamos, por lo tanto, esta respuesta es lo suficientemente buena como para ser aceptada. –

+0

Es cierto. Es un enfoque bastante complicado, pero se puede hacer que funcione donde se requieren más uniones/procesamiento en las instrucciones de inserción. –

1

Algunas ideas:

  • Si el uso de la herencia es especificar listas de columnas para las inserciones, y el nombramiento de columnas en lugar de utilizar SELECT *, entonces no puedes simplemente enlazar un valor predeterminado a la columna C y dejar que la aplicación use su tabla original (modificada)?

  • Si hubiera alguna forma de hacer que la aplicación heredada utilizara una vista o tabla diferente para sus INSERTES que para SELECCIONAR o ELIMINAR, podría poner los valores predeterminados requeridos en esa tabla y usar un disparador posterior regular para moverse las nuevas columnas a la mesa real.

  • ¿Qué tal si dejamos solo la tabla original y agregamos sus columnas adicionales en una tabla separada que tiene una relación 1-1 con el original? A continuación, cree una vista que combine estas dos tablas y coloque en su lugar el activador (es) apropiado (s) en esta nueva vista para manejar todas las operaciones de datos divididas entre las dos tablas. Me doy cuenta de que esto tiene implicaciones en el rendimiento, pero podría ser la única forma de solucionar el problema. Este sería un caso ideal para una vista materializada, lo que ralentizaría las actualizaciones pero haría que el resultado funcionara exactamente como una tabla para lecturas. (Las vistas materializadas se prestan mejor a las uniones internas y no requieren agregación. También ponen bloqueos de esquema en las tablas de origen.)

  • Me encontré con un problema similar en el que no podía distinguir entre valores NULL intencionalmente y omitió columnas en un disparador ACTUALIZAR en lugar de en una vista.Eventualmente hice un disparador en lugar de INSERT en la vista para convertir inserciones en actualizaciones (si la clave ya existía, era una actualización, de lo contrario, era una inserción). Aunque esto no te ayudará directamente, podría provocar algunas ideas para ti o para otros.

+0

Gracias por estos comentarios, no puedo señalar nada en particular que haya sido de ayuda, ¡pero nos hizo sentir mucho menos como si hubiéramos chocado contra una pared de ladrillos! –

0

¿Qué pasa con el uso de algo como esto ???:

insert into realtable 
values inserted.a, isnull(inserted.b, DEFAULT), computedC 
from inserted 
Cuestiones relacionadas