sql >> Base de Datos >  >> RDS >> Oracle

Usando SI EXISTE (SELECCIONAR ...) en un disparador ANTES DE INSERTAR (Oracle)

En primer lugar, si está utilizando SQL*Plus, cuando crea un objeto y se le informa que hay errores de compilación, el comando show errors le mostrará los errores.

Si ejecutó show errors , se le diría que IF EXISTS no es una sintaxis válida. Podrías hacer algo como

SELECT COUNT(*)
  INTO l_cnt
  FROM <<rest of query>>

IF( l_cnt > 0 )
THEN
  RAISE_APPLICATION_ERROR ...
END IF;

Sin embargo, una vez que solucione el error de compilación, terminará con errores de tiempo de ejecución. En un disparador de nivel de fila en surveillance , generalmente no puede consultar surveillance (puede hacerlo si todo lo que está haciendo es INSERT VALUES que está garantizado para insertar solo una sola fila). Si lo hace, obtendrá un error de activación de mutación en tiempo de ejecución.

Desde la perspectiva del modelo de datos, cuando se encuentra diseñando una tabla en la que los datos válidos para una fila en particular dependen de los datos almacenados en otras filas de la misma tabla, generalmente ha violado los principios de normalización y, en general, es mejor que corrija el modelo de datos subyacente.

Si realmente está decidido a mantener el modelo de datos, preferiría crear una vista materializada que se actualice al confirmar y que tenga datos solo para las filas que infringen sus criterios. Luego puede poner restricciones en esa vista materializada que arrojan errores en el momento de la confirmación cuando se violan sus criterios. Esto requerirá registros de visualización materializados en su tabla.

Si realmente desea mantener el modelo de datos y quiere aplicar la lógica con disparadores, necesitará la solución clásica de tres disparadores (o un disparador compuesto con tres partes si está usando 11.2 o posterior). Crearía un paquete con una colección de valores de clave principal. Un activador de sentencia before inicializaría la colección. Un activador de nivel de fila insertaría las claves principales de las filas que se insertaron y/o actualizaron en esta colección. Y luego, un disparador de declaración posterior iteraría sobre esta colección e implementaría las comprobaciones que desee. Sin embargo, son muchas piezas en movimiento, por lo que generalmente desaconsejo.

Además, incluso si logra que todas estas piezas funcionen, su lógica no lo protegerá en un entorno multiusuario. Cuando tiene varios usuarios accediendo al sistema al mismo tiempo, es completamente posible que un usuario inserte una fila, el segundo usuario inserte otra fila con un rango superpuesto y luego cada sesión se confirmará. En ese caso, ambos conjuntos de activadores permitirán el cambio, pero seguirá teniendo datos en la tabla que infringen sus requisitos. La vista materializada, dado que se aplica en el momento de la confirmación y no en el momento de la inserción, funcionará correctamente en un entorno multiusuario. Si desea que los activadores funcionen en un entorno multiusuario, deberá complicarlos aún más agregando una lógica adicional que imponga la serialización que bloquearía el insert de la segunda sesión. desde la ejecución hasta la primera sesión confirmada o revertida. Eso agrega complejidad, reduce la escalabilidad y, dependiendo de cómo se implemente, puede convertirse en una pesadilla de soporte.