Pregunta

Historia de fondo

En el trabajo en el que está pensando en la desaprobación de una columna clave natural en una de las tablas principales. El proyecto consta de más de 100 aplicaciones que enlazan con esta tabla / columna; 400+ procedimientos que hacen referencia a esta columna directamente almacenado; y una amplia gama de mesas comunes entre estas aplicaciones que también hacen referencia a esta columna.

El Big Bang y de inicio de los métodos de Scratch están fuera de la imagen. Vamos a despreciar esta columna una aplicación a la vez, certificar los cambios y pasar a la siguiente ... y tenemos un objetivo propuesto largo para hacer este esfuerzo práctico.

El problema que tengo es que muchas de estas aplicaciones han compartido procedimientos almacenados y tablas. Cuando se modifica por completo todas las tablas / procedimientos almacenados de aplicación una aplicación B y C se romperá hasta que convertido. Estos a su vez pueden romper las aplicaciones D, E, F ... Etc. Ya tengo una estrategia implementada para las clases de códigos y procedimientos almacenados, la parte que estoy atascado en la transición es el estado de la base de datos.

Aquí hay un básica ejemplo de lo que tenemos:

Users
---------------------------
Code          varchar(32) natural key

Access
---------------------------
UserCode      varchar(32) foreign key
AccessLevel   int

Y estamos apuntando ahora sólo para el estado de transición de esta manera:

Users
---------------------------
Code          varchar(32) 
Id            int         surrogate key

Access
---------------------------
UserCode      varchar(32)   
UserID        int         foreign key      
AccessLevel   int

La idea bienestar durante las aplicaciones de la ONU-migrado fase de transición y los procedimientos almacenados aún podrán acceder a todos los datos pertinentes y los nuevos se pueden empezar a empujar a las columnas correctas - Una vez completada la migración de todos los procedimientos y aplicaciones almacenadas por fin podemos soltar las columnas adicionales.

quería utilizar disparadores de SQL Server de forma automática interceptar cualquier nueva Insertar / Actualizar de y hacer algo como lo siguiente en cada una de las tablas afectadas:

CREATE TRIGGER tr_Access_Sync
ON Access
INSTEAD OF INSERT(, UPDATE)
AS
BEGIN
  DIM @code as Varchar(32)
  DIM @id as int

  SET @code = (SELECT inserted.code FROM inserted)
  SET @id = (SELECT inserted.code FROM inserted)

  -- This is a migrated application; find the appropriate legacy key
  IF @code IS NULL AND @id IS NOT NULL
     SELECT Code FROM Users WHERE Users.id = @id

  -- This is a legacy application; find the appropriate surrogate key
  IF @id IS NULL AND @code IS NOT NULL
     SELECT Code FROM Users WHERE Users.id = @id

  -- Impossible code:
  UPDATE inserted SET inserted.code=@code, inserted.id=@id
END

Pregunta

Los 2 problemas enormes que estoy teniendo hasta el momento son:

  1. No se puede hacer un "después INSERT" debido a las restricciones NULL hará que el inserto falle.
  2. El "código imposible" que he mencionado es como me gustaría proxy de forma limpia la consulta original; Si la consulta original tiene x, y, z columnas en ella o simplemente x, que idealmente quisiera el mismo gatillo para hacer esto. Y si añadir / eliminar otra columna, me gustaría que el gatillo para seguir funcionando.

Alguien tiene un ejemplo de código donde esto podría ser posible, o incluso una solución alternativa para mantener adecuadamente estas columnas rellenas, incluso cuando sólo uno de los valores se pasa a SQL?

¿Fue útil?

Solución 3

Después de dormir en el problema, esto parece ser la solución más genérica / reutilizable que podía llegar a dentro de la sintaxis SQL. Funciona bien incluso si ambas columnas tienen una restricción NOT NULL, incluso si no se hace referencia en la columna "otros" en absoluto en su inserción.

CREATE TRIGGER tr_Access_Sync
ON Access
INSTEAD OF INSERT
AS 
BEGIN

    /*-- Create a temporary table to modify because "inserted" is read-only */
    /*-- "temp" is actually "#temp" but it throws off stackoverflow's syntax highlighting */
    SELECT * INTO temp FROM inserted

    /*-- If for whatever reason the secondary table has it's own identity column */
    /*-- we need to get rid of it from our #temp table to do an Insert later with identities on */
    ALTER TABLE temp DROP COLUMN oneToManyIdentity

    UPDATE temp 
    SET 
        UserCode = ISNULL(UserCode, (SELECT UserCode FROM Users U WHERE U.UserID = temp.UserID)),
        UserID = ISNULL(UserID, (SELECT UserID FROM Users U WHERE U.UserCode = temp.UserCode))

    INSERT INTO Access SELECT * FROM temp

END

Otros consejos

negocio difícil ...

Aceptar, en primer lugar: este disparador no trabajo en muchas circunstancias:

SET @code = (SELECT inserted.code FROM inserted)
SET @id = (SELECT inserted.code FROM inserted)

El disparador puede ser llamada con un conjunto de filas de la tabla Inserted pseudo - cuál vas a recoger aquí ?? Usted tiene que escribir su disparador de tal manera que va a trabajar incluso cuando se obtiene 10 filas en la tabla Inserted. Si un SQL comando inserta 10 filas, su disparador no se dispararon diez veces - una para cada fila - pero sólo una vez para todo el lote - es necesario tener esto en cuenta!

Segundo punto: Me gustaría tratar de hacer que los campos IDENTITY de la identificación - entonces ellos siempre obtendrá un valor - incluso para aplicaciones "legacy". Esos "viejos" aplicaciones deben proporcionar una clave legado lugar - por lo que debe estar bien allí. El único problema que veo y no saben cómo manejar esas son las inserciones de una aplicación ya convertida - ¿Proporcionan una clave legado "viejo estilo", así? Si no es así - ¿Con qué rapidez se necesita tener una clave tales?

Lo que estoy pensando que sería un "trabajo de limpieza" que funcionaría sobre la mesa y conseguir todas las filas con una clave NULL legado y luego proporcionar un valor significativo para él. Hacer de este un procedimiento almacenado regular y ejecutar cada ejemplo día, cuatro horas, 30 minutos - lo que se adapte a sus necesidades. Entonces usted no tiene que lidiar con las causas y todas las limitaciones que tienen.

¿No sería posible hacer los cambios de esquema 'bigbang', sino crear vistas de la parte superior de las tablas que 'esconder' el cambio?

Creo que es posible encontrar simplemente está posponiendo las roturas a un punto posterior en el tiempo: "Vamos a despreciar esta columna una aplicación a la vez" - que podría ser mi ingenuidad, pero no puedo ver cómo que alguna vez va a trabajar.

Sin duda, una peor desastre puede ocurrir cuando diferentes aplicaciones están haciendo las cosas de manera diferente?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top