/* Configuración y procedimientos actuales de la bitácora. La bitácora participa en la transacción ambiental de la operación principal. */ SET NOCOUNT ON; GO IF COL_LENGTH('dbo.Bit_Campos', 'TipoDatoSQL') IS NULL BEGIN ALTER TABLE dbo.Bit_Campos ADD TipoDatoSQL varchar(128) COLLATE Modern_Spanish_CS_AS NULL; END; GO IF COL_LENGTH('dbo.Bit_Campos', 'CveTablaReferencia') IS NULL BEGIN ALTER TABLE dbo.Bit_Campos ADD CveTablaReferencia int NULL; END; GO IF COL_LENGTH('dbo.Bit_Campos', 'CveCampoMostrarReferencia') IS NULL BEGIN ALTER TABLE dbo.Bit_Campos ADD CveCampoMostrarReferencia int NULL; END; GO IF NOT EXISTS ( SELECT 1 FROM sys.check_constraints WHERE parent_object_id = OBJECT_ID('dbo.Bit_Campos') AND name = 'CK_Bit_Campos_ReferenciaCompleta' ) BEGIN ALTER TABLE dbo.Bit_Campos WITH CHECK ADD CONSTRAINT CK_Bit_Campos_ReferenciaCompleta CHECK ( (CveTablaReferencia IS NULL AND CveCampoMostrarReferencia IS NULL) OR (CveTablaReferencia IS NOT NULL AND CveCampoMostrarReferencia IS NOT NULL) ); ALTER TABLE dbo.Bit_Campos CHECK CONSTRAINT CK_Bit_Campos_ReferenciaCompleta; END; GO IF NOT EXISTS ( SELECT 1 FROM sys.foreign_keys WHERE parent_object_id = OBJECT_ID('dbo.Bit_Campos') AND name = 'FK_Bit_Campos_TablaReferencia' ) BEGIN ALTER TABLE dbo.Bit_Campos WITH CHECK ADD CONSTRAINT FK_Bit_Campos_TablaReferencia FOREIGN KEY (CveTablaReferencia) REFERENCES dbo.Bit_Tablas (CveTabla); ALTER TABLE dbo.Bit_Campos CHECK CONSTRAINT FK_Bit_Campos_TablaReferencia; END; GO IF NOT EXISTS ( SELECT 1 FROM sys.foreign_keys WHERE parent_object_id = OBJECT_ID('dbo.Bit_Campos') AND name = 'FK_Bit_Campos_CampoMostrarReferencia' ) BEGIN ALTER TABLE dbo.Bit_Campos WITH CHECK ADD CONSTRAINT FK_Bit_Campos_CampoMostrarReferencia FOREIGN KEY (CveCampoMostrarReferencia) REFERENCES dbo.Bit_Campos (CveCampo); ALTER TABLE dbo.Bit_Campos CHECK CONSTRAINT FK_Bit_Campos_CampoMostrarReferencia; END; GO IF COL_LENGTH('dbo.Bit_BitacoraRelaciones', 'VisibleDesarrollador') IS NULL BEGIN ALTER TABLE dbo.Bit_BitacoraRelaciones ADD VisibleDesarrollador bit NOT NULL CONSTRAINT DF_Bit_BitacoraRelaciones_VisibleDesarrollador DEFAULT (0); END; GO IF NOT EXISTS ( SELECT 1 FROM sys.indexes WHERE object_id = OBJECT_ID('dbo.Bit_BitacoraRelaciones') AND name = 'IX_Bit_BitacoraRelaciones_Filtro' ) BEGIN CREATE NONCLUSTERED INDEX IX_Bit_BitacoraRelaciones_Filtro ON dbo.Bit_BitacoraRelaciones ( CveTablaRelacionada, CveCampoRelacion, ValorRelacionNumero, VisibleDesarrollador, CveBitacora ) INCLUDE ( ValorRelacionTexto, LlaveRegistroRelacionada ); END; GO IF NOT EXISTS ( SELECT 1 FROM sys.indexes WHERE object_id = OBJECT_ID('dbo.Bit_BitacoraRelaciones') AND name = 'IX_Bit_BitacoraRelaciones_FiltroTexto' ) BEGIN CREATE NONCLUSTERED INDEX IX_Bit_BitacoraRelaciones_FiltroTexto ON dbo.Bit_BitacoraRelaciones ( CveTablaRelacionada, CveCampoRelacion, ValorRelacionTexto, VisibleDesarrollador, CveBitacora ) INCLUDE ( ValorRelacionNumero, LlaveRegistroRelacionada ); END; GO DECLARE @Tablas TABLE ( NombreTablaSQL varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, NombreMostrar varchar(150) COLLATE Modern_Spanish_CS_AS NOT NULL, Descripcion varchar(500) COLLATE Modern_Spanish_CS_AS NULL, NombreCampoLlaveSQL varchar(128) COLLATE Modern_Spanish_CS_AS NULL ); INSERT INTO @Tablas ( NombreTablaSQL, NombreMostrar, Descripcion, NombreCampoLlaveSQL ) VALUES ('Clientes', 'Clientes', 'Clientes propietarios de la información.', 'CveCliente'), ('Fraccionamientos', 'Fraccionamientos', 'Catálogo de fraccionamientos.', 'CveFraccionamiento'), ('Fraccionamientos_Estatus', 'Estatus de fraccionamiento', 'Catálogo de estatus de fraccionamientos.', 'CveEstatus'), ('FraccionamientosEtapas', 'Etapas', 'Etapas de los fraccionamientos.', 'CveFraccionamientoEtapa'), ('FraccionamientosEtapasGIS', 'GIS de etapas', 'GIS asociado a las etapas.', 'CveFraccionamientoEtapaGIS'), ('FraccionamientosLotes', 'Lotes', 'Lotes de las etapas.', 'CveFraccionamientoLote'), ('Sis_Usuarios', 'Usuarios', 'Usuarios del sistema.', 'CveUsuario'), ('Sis_UsuariosClientes', 'Clientes por usuario', 'Asignaciones de clientes a usuarios.', NULL); UPDATE T SET T.NombreMostrar = S.NombreMostrar, T.Descripcion = S.Descripcion, T.NombreCampoLlaveSQL = S.NombreCampoLlaveSQL, T.Activo = 1, T.FechaMod = GETDATE() FROM dbo.Bit_Tablas AS T INNER JOIN @Tablas AS S ON S.NombreTablaSQL = T.NombreTablaSQL; INSERT INTO dbo.Bit_Tablas ( NombreTablaSQL, NombreMostrar, Descripcion, NombreCampoLlaveSQL, Activo ) SELECT S.NombreTablaSQL, S.NombreMostrar, S.Descripcion, S.NombreCampoLlaveSQL, 1 FROM @Tablas AS S WHERE NOT EXISTS ( SELECT 1 FROM dbo.Bit_Tablas AS T WHERE T.NombreTablaSQL = S.NombreTablaSQL ); GO DECLARE @Campos TABLE ( NombreTablaSQL varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, NombreCampoSQL varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, NombreMostrar varchar(150) COLLATE Modern_Spanish_CS_AS NOT NULL, MostrarEnBitacora bit NOT NULL ); INSERT INTO @Campos ( NombreTablaSQL, NombreCampoSQL, NombreMostrar, MostrarEnBitacora ) VALUES ('Clientes', 'CveCliente', 'Cliente', 0), ('Clientes', 'Nombre', 'Cliente', 1), ('Fraccionamientos', 'CveFraccionamiento', 'Clave de fraccionamiento', 0), ('Fraccionamientos', 'CveCliente', 'Cliente', 1), ('Fraccionamientos', 'Fraccionamiento', 'Fraccionamiento', 1), ('Fraccionamientos', 'Hectareas', 'Hectáreas', 1), ('Fraccionamientos', 'Ubicacion', 'Ubicación', 1), ('Fraccionamientos', 'CveEstatus', 'Estatus', 1), ('Fraccionamientos', 'EsActivo', 'Activo', 1), ('Fraccionamientos_Estatus', 'CveEstatus', 'Clave de estatus', 0), ('Fraccionamientos_Estatus', 'Estatus', 'Estatus', 1), ('FraccionamientosEtapas', 'CveFraccionamientoEtapa', 'Clave de etapa', 0), ('FraccionamientosEtapas', 'CveFraccionamiento', 'Fraccionamiento', 1), ('FraccionamientosEtapas', 'Etapa', 'Etapa', 1), ('FraccionamientosEtapas', 'Hectareas', 'Hectáreas', 1), ('FraccionamientosEtapas', 'Orden', 'Orden', 1), ('FraccionamientosEtapas', 'Avance', 'Avance', 1), ('FraccionamientosEtapas', 'EsActivo', 'Activo', 1), ('FraccionamientosEtapasGIS', 'CveFraccionamientoEtapaGIS', 'Clave de GIS', 0), ('FraccionamientosEtapasGIS', 'CveFraccionamientoEtapa', 'Etapa', 1), ('FraccionamientosEtapasGIS', 'Nombre', 'GIS', 1), ('FraccionamientosEtapasGIS', 'UrlVisualizacion', 'URL de visualización', 1), ('FraccionamientosLotes', 'CveFraccionamientoLote', 'Clave de lote', 0), ('FraccionamientosLotes', 'CveFraccionamientoEtapa', 'Etapa', 1), ('FraccionamientosLotes', 'Numero', 'Número', 1), ('FraccionamientosLotes', 'Tipo', 'Tipo', 1), ('FraccionamientosLotes', 'Calle', 'Calle', 1), ('FraccionamientosLotes', 'Catastro', 'Catastro', 1), ('FraccionamientosLotes', 'MetrosCuadrados', 'Metros cuadrados', 1), ('FraccionamientosLotes', 'Duplicador', 'Duplicador', 1), ('FraccionamientosLotes', 'EsActivo', 'Activo', 1), ('Sis_Usuarios', 'CveUsuario', 'Clave de usuario', 0), ('Sis_Usuarios', 'NombreUsuario', 'Usuario', 1), ('Sis_Usuarios', 'CorreoElectronico', 'Correo electrónico', 1), ('Sis_Usuarios', 'CveRol', 'Rol', 1), ('Sis_Usuarios', 'Activo', 'Activo', 1), ('Sis_Usuarios', 'DebeCambiarContrasena', 'Debe cambiar contraseña', 1), ('Sis_Usuarios', 'CorreoVerificado', 'Correo verificado', 1), ('Sis_UsuariosClientes', 'CveUsuario', 'Usuario', 1), ('Sis_UsuariosClientes', 'CveCliente', 'Cliente', 1), ('Sis_UsuariosClientes', 'Orden', 'Orden', 1), ('Sis_UsuariosClientes', 'EsPrincipal', 'Principal', 1), ('Sis_UsuariosClientes', 'Activo', 'Activo', 1); UPDATE C SET C.NombreMostrar = S.NombreMostrar, C.MostrarEnBitacora = S.MostrarEnBitacora, C.TipoDatoSQL = TY.name COLLATE Modern_Spanish_CS_AS, C.Activo = 1, C.FechaMod = GETDATE() FROM dbo.Bit_Campos AS C INNER JOIN dbo.Bit_Tablas AS T ON T.CveTabla = C.CveTabla INNER JOIN @Campos AS S ON S.NombreTablaSQL = T.NombreTablaSQL AND S.NombreCampoSQL = C.NombreCampoSQL INNER JOIN sys.schemas AS SC ON SC.name = 'dbo' INNER JOIN sys.tables AS ST ON ST.schema_id = SC.schema_id AND ST.name COLLATE Modern_Spanish_CS_AS = S.NombreTablaSQL INNER JOIN sys.columns AS CO ON CO.object_id = ST.object_id AND CO.name COLLATE Modern_Spanish_CS_AS = S.NombreCampoSQL INNER JOIN sys.types AS TY ON TY.user_type_id = CO.user_type_id; INSERT INTO dbo.Bit_Campos ( CveTabla, NombreCampoSQL, NombreMostrar, MostrarEnBitacora, TipoDatoSQL, Activo ) SELECT T.CveTabla, S.NombreCampoSQL, S.NombreMostrar, S.MostrarEnBitacora, TY.name COLLATE Modern_Spanish_CS_AS, 1 FROM @Campos AS S INNER JOIN dbo.Bit_Tablas AS T ON T.NombreTablaSQL = S.NombreTablaSQL INNER JOIN sys.schemas AS SC ON SC.name = 'dbo' INNER JOIN sys.tables AS ST ON ST.schema_id = SC.schema_id AND ST.name COLLATE Modern_Spanish_CS_AS = S.NombreTablaSQL INNER JOIN sys.columns AS CO ON CO.object_id = ST.object_id AND CO.name COLLATE Modern_Spanish_CS_AS = S.NombreCampoSQL INNER JOIN sys.types AS TY ON TY.user_type_id = CO.user_type_id WHERE NOT EXISTS ( SELECT 1 FROM dbo.Bit_Campos AS C WHERE C.CveTabla = T.CveTabla AND C.NombreCampoSQL = S.NombreCampoSQL ); GO DECLARE @ReferenciasCampos TABLE ( NombreTablaOrigen varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, NombreCampoOrigen varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, NombreTablaReferencia varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, NombreCampoMostrarReferencia varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL ); INSERT INTO @ReferenciasCampos ( NombreTablaOrigen, NombreCampoOrigen, NombreTablaReferencia, NombreCampoMostrarReferencia ) VALUES ('Fraccionamientos', 'CveCliente', 'Clientes', 'Nombre'), ('Fraccionamientos', 'CveEstatus', 'Fraccionamientos_Estatus', 'Estatus'), ('FraccionamientosEtapas', 'CveFraccionamiento', 'Fraccionamientos', 'Fraccionamiento'), ('FraccionamientosEtapasGIS', 'CveFraccionamientoEtapa', 'FraccionamientosEtapas', 'Etapa'), ('FraccionamientosLotes', 'CveFraccionamientoEtapa', 'FraccionamientosEtapas', 'Etapa'), ('Sis_UsuariosClientes', 'CveUsuario', 'Sis_Usuarios', 'NombreUsuario'), ('Sis_UsuariosClientes', 'CveCliente', 'Clientes', 'Nombre'); UPDATE CO SET CO.CveTablaReferencia = TR.CveTabla, CO.CveCampoMostrarReferencia = CM.CveCampo, CO.FechaMod = GETDATE() FROM dbo.Bit_Campos AS CO INNER JOIN dbo.Bit_Tablas AS TOG ON TOG.CveTabla = CO.CveTabla INNER JOIN @ReferenciasCampos AS R ON R.NombreTablaOrigen = TOG.NombreTablaSQL AND R.NombreCampoOrigen = CO.NombreCampoSQL INNER JOIN dbo.Bit_Tablas AS TR ON TR.NombreTablaSQL = R.NombreTablaReferencia AND TR.Activo = 1 INNER JOIN dbo.Bit_Campos AS CM ON CM.CveTabla = TR.CveTabla AND CM.NombreCampoSQL = R.NombreCampoMostrarReferencia AND CM.MostrarEnBitacora = 1 AND CM.Activo = 1; GO CREATE OR ALTER PROCEDURE dbo.PA_Bit_BitacoraAdd @NombreTablaSQL varchar(128), @CveTipoMovimiento tinyint, @CveDefinicionAccion int = NULL, @CveUsuarioAutoriza int = NULL, @FechaAutorizacion datetime = NULL, @LlaveRegistro nvarchar(250), @DescripcionMovimiento nvarchar(1000), @RelacionesXml xml, @CamposXml xml = NULL, @DiscriminarCamposSinCambios bit = 1, @DireccionIP varchar(50) = NULL, @NombreEquipo varchar(150) = NULL, @Modulo varchar(150) = NULL, @CveUsuarioEjecuta int, @ErrorMostrar varchar(max) OUTPUT, @ErrorTipo int OUTPUT, @Return bit OUTPUT AS BEGIN SET NOCOUNT ON; SELECT @ErrorMostrar = NULL, @ErrorTipo = 0, @Return = 0; BEGIN TRY DECLARE @CveTabla int; SELECT @CveTabla = T.CveTabla FROM dbo.Bit_Tablas AS T WHERE T.NombreTablaSQL = @NombreTablaSQL COLLATE Modern_Spanish_CS_AS AND T.Activo = 1; IF @CveTabla IS NULL BEGIN SET @ErrorMostrar = 'La tabla indicada no está configurada para bitácora.'; SET @ErrorTipo = 2; RETURN; END; IF NOT EXISTS ( SELECT 1 FROM dbo.Bit_TiposMovimiento AS M WHERE M.CveTipoMovimiento = @CveTipoMovimiento ) BEGIN SET @ErrorMostrar = 'El tipo de movimiento de bitácora no es válido.'; SET @ErrorTipo = 2; RETURN; END; IF @CveDefinicionAccion IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM dbo.Bit_DefinicionesAccion AS A WHERE A.CveDefinicionAccion = @CveDefinicionAccion AND A.CveTabla = @CveTabla AND A.CveTipoMovimiento = @CveTipoMovimiento AND A.Activo = 1 ) BEGIN SET @ErrorMostrar = 'La definición de la acción no corresponde al movimiento.'; SET @ErrorTipo = 2; RETURN; END; DECLARE @Relaciones TABLE ( Orden int NOT NULL, CveTipoRelacion tinyint NOT NULL, NombreTablaSQL varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, NombreCampoSQL varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, Valor nvarchar(250) COLLATE Modern_Spanish_CS_AS NOT NULL, VisibleDesarrollador bit NOT NULL, DescripcionRelacion nvarchar(500) COLLATE Modern_Spanish_CS_AS NULL ); INSERT INTO @Relaciones ( Orden, CveTipoRelacion, NombreTablaSQL, NombreCampoSQL, Valor, VisibleDesarrollador, DescripcionRelacion ) SELECT R.value('@Orden', 'int'), R.value('@CveTipoRelacion', 'tinyint'), R.value('@NombreTablaSQL', 'varchar(128)'), R.value('@NombreCampoSQL', 'varchar(128)'), R.value('@Valor', 'nvarchar(250)'), R.value('@VisibleDesarrollador', 'bit'), NULLIF(R.value('@DescripcionRelacion', 'nvarchar(500)'), '') FROM @RelacionesXml.nodes('/Relaciones/Relacion') AS X(R); IF NOT EXISTS (SELECT 1 FROM @Relaciones) BEGIN SET @ErrorMostrar = 'La bitácora debe incluir al menos una relación.'; SET @ErrorTipo = 2; RETURN; END; DECLARE @RelacionesResueltas TABLE ( Orden int NOT NULL, CveTipoRelacion tinyint NOT NULL, CveTabla int NOT NULL, CveCampo int NOT NULL, NombreTablaSQL varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, NombreCampoSQL varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, TipoDatoSQL varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, Valor nvarchar(250) COLLATE Modern_Spanish_CS_AS NOT NULL, VisibleDesarrollador bit NOT NULL, DescripcionRelacion nvarchar(500) COLLATE Modern_Spanish_CS_AS NULL ); INSERT INTO @RelacionesResueltas ( Orden, CveTipoRelacion, CveTabla, CveCampo, NombreTablaSQL, NombreCampoSQL, TipoDatoSQL, Valor, VisibleDesarrollador, DescripcionRelacion ) SELECT R.Orden, R.CveTipoRelacion, T.CveTabla, C.CveCampo, R.NombreTablaSQL, R.NombreCampoSQL, C.TipoDatoSQL, R.Valor, R.VisibleDesarrollador, R.DescripcionRelacion FROM @Relaciones AS R INNER JOIN dbo.Bit_Tablas AS T ON T.NombreTablaSQL = R.NombreTablaSQL AND T.Activo = 1 INNER JOIN dbo.Bit_Campos AS C ON C.CveTabla = T.CveTabla AND C.NombreCampoSQL = R.NombreCampoSQL AND C.Activo = 1 INNER JOIN dbo.Bit_TiposRelacion AS TR ON TR.CveTipoRelacion = R.CveTipoRelacion AND TR.Activo = 1 WHERE C.TipoDatoSQL IS NOT NULL; IF (SELECT COUNT(1) FROM @Relaciones) <> (SELECT COUNT(1) FROM @RelacionesResueltas) BEGIN SET @ErrorMostrar = 'Una relación utiliza una tabla, campo o tipo que no está configurado en la bitácora.'; SET @ErrorTipo = 2; RETURN; END; IF EXISTS ( SELECT 1 FROM @RelacionesResueltas WHERE TipoDatoSQL IN ('tinyint', 'smallint', 'int', 'bigint') AND TRY_CONVERT(bigint, Valor) IS NULL ) BEGIN SET @ErrorMostrar = 'El valor de una relación numérica no es válido.'; SET @ErrorTipo = 2; RETURN; END; IF EXISTS ( SELECT 1 FROM @RelacionesResueltas WHERE VisibleDesarrollador = 1 ) AND NOT EXISTS ( SELECT 1 FROM @RelacionesResueltas WHERE NombreTablaSQL = 'Clientes' AND NombreCampoSQL = 'CveCliente' AND VisibleDesarrollador = 1 ) BEGIN SET @ErrorMostrar = 'Una bitácora visible para desarrolladores debe relacionarse con un cliente.'; SET @ErrorTipo = 2; RETURN; END; DECLARE @Campos TABLE ( Orden int NOT NULL, NombreCampoSQL varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, ValorAnteriorEsNulo bit NOT NULL, ValorAnterior nvarchar(max) COLLATE Modern_Spanish_CS_AS NULL, ValorNuevoEsNulo bit NOT NULL, ValorNuevo nvarchar(max) COLLATE Modern_Spanish_CS_AS NULL ); IF @CamposXml IS NOT NULL BEGIN INSERT INTO @Campos ( Orden, NombreCampoSQL, ValorAnteriorEsNulo, ValorAnterior, ValorNuevoEsNulo, ValorNuevo ) SELECT C.value('@Orden', 'int'), C.value('@NombreCampoSQL', 'varchar(128)'), C.value('@ValorAnteriorEsNulo', 'bit'), CASE WHEN C.value('@ValorAnteriorEsNulo', 'bit') = 1 THEN NULL ELSE C.value('@ValorAnterior', 'nvarchar(max)') END, C.value('@ValorNuevoEsNulo', 'bit'), CASE WHEN C.value('@ValorNuevoEsNulo', 'bit') = 1 THEN NULL ELSE C.value('@ValorNuevo', 'nvarchar(max)') END FROM @CamposXml.nodes('/Campos/Campo') AS X(C); END; IF @CveTipoMovimiento IN (1, 2) AND NOT EXISTS (SELECT 1 FROM @Campos) BEGIN SET @ErrorMostrar = 'Las altas y modificaciones deben incluir los campos auditados.'; SET @ErrorTipo = 2; RETURN; END; IF EXISTS ( SELECT 1 FROM @Campos AS F LEFT JOIN dbo.Bit_Campos AS C ON C.CveTabla = @CveTabla AND C.NombreCampoSQL = F.NombreCampoSQL AND C.Activo = 1 WHERE C.CveCampo IS NULL ) BEGIN SET @ErrorMostrar = 'Uno de los campos enviados no está configurado para la tabla auditada.'; SET @ErrorTipo = 2; RETURN; END; INSERT INTO dbo.Bit_Bitacora ( CveTabla, CveTipoMovimiento, CveDefinicionAccion, CveUsuarioEjecuta, CveUsuarioAutoriza, FechaAutorizacion, LlaveRegistro, DescripcionMovimiento, DireccionIP, NombreEquipo, Modulo ) VALUES ( @CveTabla, @CveTipoMovimiento, @CveDefinicionAccion, @CveUsuarioEjecuta, @CveUsuarioAutoriza, @FechaAutorizacion, @LlaveRegistro, @DescripcionMovimiento, @DireccionIP, @NombreEquipo, @Modulo ); DECLARE @CveBitacora bigint = CONVERT(bigint, SCOPE_IDENTITY()); INSERT INTO dbo.Bit_BitacoraRelaciones ( CveBitacora, CveTipoRelacion, CveTablaRelacionada, LlaveRegistroRelacionada, CveCampoRelacion, ValorRelacionNumero, ValorRelacionTexto, DescripcionRelacion, VisibleDesarrollador ) SELECT @CveBitacora, R.CveTipoRelacion, R.CveTabla, R.Valor, R.CveCampo, CASE WHEN R.TipoDatoSQL IN ('tinyint', 'smallint', 'int', 'bigint') THEN TRY_CONVERT(bigint, R.Valor) ELSE NULL END, CASE WHEN R.TipoDatoSQL IN ('tinyint', 'smallint', 'int', 'bigint') THEN NULL ELSE R.Valor END, R.DescripcionRelacion, R.VisibleDesarrollador FROM @RelacionesResueltas AS R; INSERT INTO dbo.Bit_BitacoraCampos ( CveBitacora, CveCampo, ValorAnterior, ValorNuevo ) SELECT @CveBitacora, C.CveCampo, F.ValorAnterior, F.ValorNuevo FROM @Campos AS F INNER JOIN dbo.Bit_Campos AS C ON C.CveTabla = @CveTabla AND C.NombreCampoSQL = F.NombreCampoSQL AND C.Activo = 1 WHERE @DiscriminarCamposSinCambios = 0 OR F.ValorAnteriorEsNulo <> F.ValorNuevoEsNulo OR ( F.ValorAnteriorEsNulo = 0 AND F.ValorNuevoEsNulo = 0 AND F.ValorAnterior <> F.ValorNuevo ); SELECT @CveBitacora AS CveBitacora; SET @Return = 1; END TRY BEGIN CATCH SET @ErrorMostrar = 'Ocurrió un error al registrar la bitácora; favor de contactar a Sistemas.'; SET @ErrorTipo = 1; SET @Return = 0; DECLARE @ErrorTecnico nvarchar(2048) = CONCAT( 'Número: ', ERROR_NUMBER(), '; Procedimiento: ', COALESCE(ERROR_PROCEDURE(), 'PA_Bit_BitacoraAdd'), '; Línea: ', ERROR_LINE(), '; Detalle: ', ERROR_MESSAGE() ); RAISERROR(N'%s', 10, 1, @ErrorTecnico); END CATCH; END; GO CREATE OR ALTER PROCEDURE dbo.PA_Bit_BitacoraList @NombreTablaSQL varchar(128) = NULL, @LlaveRegistro nvarchar(250) = NULL, @CveUsuarioFiltro int = NULL, @FechaInicio datetime = NULL, @FechaFin datetime = NULL, @Modulo varchar(150) = NULL, @CveUsuarioEjecuta int, @ErrorMostrar varchar(max) OUTPUT, @ErrorTipo int OUTPUT, @Return bit OUTPUT AS BEGIN SET NOCOUNT ON; SELECT @ErrorMostrar = NULL, @ErrorTipo = 0, @Return = 0; BEGIN TRY DECLARE @EsAdministrador bit = 0; DECLARE @EsDesarrollador bit = 0; SELECT @EsAdministrador = CASE WHEN R.NombreRol IN ('SuperUsuario', 'Administrador') THEN 1 ELSE 0 END, @EsDesarrollador = CASE WHEN R.NombreRol = 'Empresa' THEN 1 ELSE 0 END FROM dbo.Sis_Usuarios AS U INNER JOIN dbo.Sis_Roles AS R ON R.CveRol = U.CveRol WHERE U.CveUsuario = @CveUsuarioEjecuta AND U.Activo = 1 AND R.Activo = 1; SELECT B.CveBitacora, B.CveTabla, T.NombreTablaSQL, T.NombreMostrar AS NombreTabla, B.CveTipoMovimiento, M.Nombre AS TipoMovimiento, A.NombreAccion, B.CveUsuarioEjecuta, B.CveUsuarioAutoriza, B.FechaAutorizacion, B.LlaveRegistro, B.DescripcionMovimiento, B.FechaMovimiento, B.DireccionIP, B.NombreEquipo, B.Modulo FROM dbo.Bit_Bitacora AS B INNER JOIN dbo.Bit_Tablas AS T ON T.CveTabla = B.CveTabla INNER JOIN dbo.Bit_TiposMovimiento AS M ON M.CveTipoMovimiento = B.CveTipoMovimiento LEFT JOIN dbo.Bit_DefinicionesAccion AS A ON A.CveDefinicionAccion = B.CveDefinicionAccion WHERE (@NombreTablaSQL IS NULL OR T.NombreTablaSQL = @NombreTablaSQL COLLATE Modern_Spanish_CS_AS) AND (@LlaveRegistro IS NULL OR B.LlaveRegistro = @LlaveRegistro COLLATE Modern_Spanish_CS_AS) AND (@CveUsuarioFiltro IS NULL OR B.CveUsuarioEjecuta = @CveUsuarioFiltro) AND (@FechaInicio IS NULL OR B.FechaMovimiento >= @FechaInicio) AND ( @FechaFin IS NULL OR B.FechaMovimiento < DATEADD(day, 1, CONVERT(date, @FechaFin)) ) AND (@Modulo IS NULL OR B.Modulo = @Modulo COLLATE Modern_Spanish_CS_AS) AND ( @EsAdministrador = 1 OR ( @EsDesarrollador = 1 AND EXISTS ( SELECT 1 FROM dbo.Bit_BitacoraRelaciones AS BR INNER JOIN dbo.Bit_Tablas AS RT ON RT.CveTabla = BR.CveTablaRelacionada INNER JOIN dbo.Bit_Campos AS RC ON RC.CveCampo = BR.CveCampoRelacion AND RC.CveTabla = RT.CveTabla INNER JOIN dbo.Sis_UsuariosClientes AS UC ON UC.CveCliente = BR.ValorRelacionNumero AND UC.CveUsuario = @CveUsuarioEjecuta AND UC.Activo = 1 WHERE BR.CveBitacora = B.CveBitacora AND BR.VisibleDesarrollador = 1 AND RT.NombreTablaSQL = 'Clientes' AND RC.NombreCampoSQL = 'CveCliente' ) ) ) ORDER BY B.FechaMovimiento DESC, B.CveBitacora DESC; SET @Return = 1; END TRY BEGIN CATCH SET @ErrorMostrar = 'Ocurrió un error al consultar la bitácora; favor de contactar a Sistemas.'; SET @ErrorTipo = 1; SET @Return = 0; DECLARE @ErrorTecnico nvarchar(2048) = CONCAT( 'Número: ', ERROR_NUMBER(), '; Procedimiento: ', COALESCE(ERROR_PROCEDURE(), 'PA_Bit_BitacoraList'), '; Línea: ', ERROR_LINE(), '; Detalle: ', ERROR_MESSAGE() ); RAISERROR(N'%s', 10, 1, @ErrorTecnico); END CATCH; END; GO SET ANSI_NULLS ON; GO SET QUOTED_IDENTIFIER ON; GO CREATE OR ALTER PROCEDURE dbo.PA_Bit_BitacoraListByRelations @RelacionesXml xml = NULL, @RelacionesMostrarXml xml = NULL, @RegistrosOmitidos int, @RegistrosPorPagina int, @CveUsuarioEjecuta int, @ErrorMostrar varchar(max) OUTPUT, @ErrorTipo int OUTPUT, @Return bit OUTPUT AS BEGIN SET NOCOUNT ON; SELECT @ErrorMostrar = NULL, @ErrorTipo = 0, @Return = 0; BEGIN TRY IF @RegistrosOmitidos < 0 OR @RegistrosPorPagina <= 0 BEGIN SET @ErrorMostrar = 'Los datos de paginación no son válidos.'; SET @ErrorTipo = 2; RETURN; END; DECLARE @EsAdministrador bit = 0; DECLARE @EsDesarrollador bit = 0; SELECT @EsAdministrador = CASE WHEN R.NombreRol IN ('SuperUsuario', 'Administrador') THEN 1 ELSE 0 END, @EsDesarrollador = CASE WHEN R.NombreRol = 'Empresa' THEN 1 ELSE 0 END FROM dbo.Sis_Usuarios AS U INNER JOIN dbo.Sis_Roles AS R ON R.CveRol = U.CveRol WHERE U.CveUsuario = @CveUsuarioEjecuta AND U.Activo = 1 AND R.Activo = 1; DECLARE @Filtros TABLE ( Orden int NOT NULL PRIMARY KEY, NombreTablaSQL varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, NombreCampoSQL varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, Valor nvarchar(250) COLLATE Modern_Spanish_CS_AS NOT NULL, SoloExistencia bit NOT NULL ); IF @RelacionesXml IS NOT NULL BEGIN INSERT INTO @Filtros ( Orden, NombreTablaSQL, NombreCampoSQL, Valor, SoloExistencia ) SELECT R.value('@Orden', 'int'), R.value('@Tabla', 'varchar(128)'), R.value('@Campo', 'varchar(128)'), R.value('@Valor', 'nvarchar(250)'), CASE WHEN R.exist('@SoloExistencia') = 1 THEN R.value('@SoloExistencia', 'bit') ELSE 0 END FROM @RelacionesXml.nodes('/Relaciones/Relacion') AS X(R); END; DECLARE @FiltrosResueltos TABLE ( Orden int NOT NULL PRIMARY KEY, CveTabla int NOT NULL, CveCampo int NOT NULL, TipoDatoSQL varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, Valor nvarchar(250) COLLATE Modern_Spanish_CS_AS NOT NULL, SoloExistencia bit NOT NULL, EsEntero bit NOT NULL ); INSERT INTO @FiltrosResueltos ( Orden, CveTabla, CveCampo, TipoDatoSQL, Valor, SoloExistencia, EsEntero ) SELECT F.Orden, T.CveTabla, C.CveCampo, C.TipoDatoSQL, F.Valor, F.SoloExistencia, CASE WHEN C.TipoDatoSQL IN ( 'tinyint', 'smallint', 'int', 'bigint' ) THEN 1 ELSE 0 END FROM @Filtros AS F INNER JOIN dbo.Bit_Tablas AS T ON T.NombreTablaSQL = F.NombreTablaSQL AND T.Activo = 1 INNER JOIN dbo.Bit_Campos AS C ON C.CveTabla = T.CveTabla AND C.NombreCampoSQL = F.NombreCampoSQL AND C.Activo = 1 INNER JOIN sys.schemas AS SF ON SF.name = 'dbo' INNER JOIN sys.tables AS TF ON TF.schema_id = SF.schema_id AND TF.name COLLATE Modern_Spanish_CS_AS = T.NombreTablaSQL INNER JOIN sys.columns AS CF ON CF.object_id = TF.object_id AND CF.name COLLATE Modern_Spanish_CS_AS = C.NombreCampoSQL WHERE C.TipoDatoSQL IS NOT NULL; IF (SELECT COUNT(1) FROM @Filtros) <> (SELECT COUNT(1) FROM @FiltrosResueltos) BEGIN SET @ErrorMostrar = 'Una relación utiliza una tabla o campo que no está configurado en la bitácora.'; SET @ErrorTipo = 2; RETURN; END; IF EXISTS ( SELECT 1 FROM @FiltrosResueltos WHERE SoloExistencia = 0 AND EsEntero = 1 AND TRY_CONVERT(bigint, Valor) IS NULL ) BEGIN SET @ErrorMostrar = 'El valor de una relación numérica no es válido.'; SET @ErrorTipo = 2; RETURN; END; DECLARE @RelacionesMostrar TABLE ( Orden int NOT NULL, NombreTablaSQL varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, NombreCampoSQL varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL ); IF @RelacionesMostrarXml IS NOT NULL BEGIN INSERT INTO @RelacionesMostrar ( Orden, NombreTablaSQL, NombreCampoSQL ) SELECT R.value('@Orden', 'int'), R.value('@Tabla', 'varchar(128)'), R.value('@Campo', 'varchar(128)') FROM @RelacionesMostrarXml.nodes('/RelacionesMostrar/Relacion') AS X(R); END; IF (SELECT COUNT(1) FROM @RelacionesMostrar) > 10 OR EXISTS ( SELECT 1 FROM @RelacionesMostrar WHERE Orden <= 0 ) OR EXISTS ( SELECT Orden FROM @RelacionesMostrar GROUP BY Orden HAVING COUNT(1) > 1 ) OR EXISTS ( SELECT NombreTablaSQL, NombreCampoSQL FROM @RelacionesMostrar GROUP BY NombreTablaSQL, NombreCampoSQL HAVING COUNT(1) > 1 ) BEGIN SET @ErrorMostrar = 'La configuración de relaciones a mostrar no es válida.'; SET @ErrorTipo = 2; RETURN; END; DECLARE @RelacionesMostrarResueltas TABLE ( Orden int NOT NULL PRIMARY KEY, CveTabla int NOT NULL, NombreTablaSQL varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, NombreTabla varchar(150) COLLATE Modern_Spanish_CS_AS NOT NULL, CveCampoLlave int NOT NULL, NombreCampoLlaveSQL varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, CveCampoMostrar int NOT NULL, NombreCampoSQL varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, NombreCampo varchar(150) COLLATE Modern_Spanish_CS_AS NOT NULL ); INSERT INTO @RelacionesMostrarResueltas ( Orden, CveTabla, NombreTablaSQL, NombreTabla, CveCampoLlave, NombreCampoLlaveSQL, CveCampoMostrar, NombreCampoSQL, NombreCampo ) SELECT R.Orden, T.CveTabla, T.NombreTablaSQL, T.NombreMostrar, CL.CveCampo, CL.NombreCampoSQL, CM.CveCampo, CM.NombreCampoSQL, CM.NombreMostrar FROM @RelacionesMostrar AS R INNER JOIN dbo.Bit_Tablas AS T ON T.NombreTablaSQL = R.NombreTablaSQL AND T.Activo = 1 AND T.NombreCampoLlaveSQL IS NOT NULL INNER JOIN dbo.Bit_Campos AS CL ON CL.CveTabla = T.CveTabla AND CL.NombreCampoSQL = T.NombreCampoLlaveSQL AND CL.Activo = 1 INNER JOIN dbo.Bit_Campos AS CM ON CM.CveTabla = T.CveTabla AND CM.NombreCampoSQL = R.NombreCampoSQL AND CM.MostrarEnBitacora = 1 AND CM.Activo = 1 INNER JOIN sys.schemas AS SC ON SC.name = 'dbo' INNER JOIN sys.tables AS ST ON ST.schema_id = SC.schema_id AND ST.name COLLATE Modern_Spanish_CS_AS = T.NombreTablaSQL INNER JOIN sys.columns AS SCL ON SCL.object_id = ST.object_id AND SCL.name COLLATE Modern_Spanish_CS_AS = CL.NombreCampoSQL INNER JOIN sys.columns AS SCM ON SCM.object_id = ST.object_id AND SCM.name COLLATE Modern_Spanish_CS_AS = CM.NombreCampoSQL; IF (SELECT COUNT(1) FROM @RelacionesMostrar) <> (SELECT COUNT(1) FROM @RelacionesMostrarResueltas) BEGIN SET @ErrorMostrar = 'Una relación a mostrar utiliza una tabla o campo no permitido.'; SET @ErrorTipo = 2; RETURN; END; CREATE TABLE #BitacorasCoincidentes ( CveBitacora bigint NOT NULL PRIMARY KEY, FechaMovimiento datetime NOT NULL ); INSERT INTO #BitacorasCoincidentes ( CveBitacora, FechaMovimiento ) SELECT B.CveBitacora, B.FechaMovimiento FROM dbo.Bit_Bitacora AS B WHERE ( @EsAdministrador = 1 OR ( @EsDesarrollador = 1 AND EXISTS ( SELECT 1 FROM dbo.Bit_BitacoraRelaciones AS BRCliente INNER JOIN dbo.Bit_Tablas AS TCliente ON TCliente.CveTabla = BRCliente.CveTablaRelacionada INNER JOIN dbo.Bit_Campos AS CCliente ON CCliente.CveCampo = BRCliente.CveCampoRelacion AND CCliente.CveTabla = TCliente.CveTabla INNER JOIN dbo.Sis_UsuariosClientes AS UC ON UC.CveCliente = BRCliente.ValorRelacionNumero AND UC.CveUsuario = @CveUsuarioEjecuta AND UC.Activo = 1 WHERE BRCliente.CveBitacora = B.CveBitacora AND BRCliente.VisibleDesarrollador = 1 AND TCliente.NombreTablaSQL = 'Clientes' AND CCliente.NombreCampoSQL = 'CveCliente' ) ) ) AND ( @EsDesarrollador = 0 OR NOT EXISTS ( SELECT 1 FROM @FiltrosResueltos AS FCliente INNER JOIN dbo.Bit_Tablas AS TClienteFiltro ON TClienteFiltro.CveTabla = FCliente.CveTabla INNER JOIN dbo.Bit_Campos AS CClienteFiltro ON CClienteFiltro.CveCampo = FCliente.CveCampo AND CClienteFiltro.CveTabla = TClienteFiltro.CveTabla WHERE TClienteFiltro.NombreTablaSQL = 'Clientes' AND CClienteFiltro.NombreCampoSQL = 'CveCliente' AND FCliente.SoloExistencia = 0 AND NOT EXISTS ( SELECT 1 FROM dbo.Sis_UsuariosClientes AS UCClienteFiltro WHERE UCClienteFiltro.CveUsuario = @CveUsuarioEjecuta AND UCClienteFiltro.CveCliente = TRY_CONVERT(bigint, FCliente.Valor) AND UCClienteFiltro.Activo = 1 ) ) ) AND NOT EXISTS ( SELECT 1 FROM @FiltrosResueltos AS F WHERE NOT EXISTS ( SELECT 1 FROM dbo.Bit_BitacoraRelaciones AS BR WHERE BR.CveBitacora = B.CveBitacora AND BR.CveTablaRelacionada = F.CveTabla AND BR.CveCampoRelacion = F.CveCampo AND ( @EsAdministrador = 1 OR BR.VisibleDesarrollador = 1 ) AND ( F.SoloExistencia = 1 OR ( ( F.EsEntero = 1 AND BR.ValorRelacionNumero = TRY_CONVERT(bigint, F.Valor) ) OR ( F.EsEntero = 0 AND BR.ValorRelacionTexto = F.Valor COLLATE Modern_Spanish_CS_AS ) ) ) ) ); DECLARE @TotalRegistros int; SELECT @TotalRegistros = COUNT(DISTINCT CveBitacora) FROM #BitacorasCoincidentes; CREATE TABLE #BitacorasPagina ( CveBitacora bigint NOT NULL PRIMARY KEY, Orden int NOT NULL ); INSERT INTO #BitacorasPagina ( CveBitacora, Orden ) SELECT C.CveBitacora, ROW_NUMBER() OVER ( ORDER BY C.FechaMovimiento DESC, C.CveBitacora DESC ) FROM #BitacorasCoincidentes AS C ORDER BY C.FechaMovimiento DESC, C.CveBitacora DESC OFFSET @RegistrosOmitidos ROWS FETCH NEXT @RegistrosPorPagina ROWS ONLY; SELECT @TotalRegistros AS TotalRegistros; SELECT B.CveBitacora, B.CveTabla, T.NombreTablaSQL, T.NombreMostrar AS NombreTabla, B.CveTipoMovimiento, M.Nombre AS TipoMovimiento, B.CveDefinicionAccion, A.NombreAccion, A.DescripcionAccion, B.CveUsuarioEjecuta, COALESCE( NULLIF(U.NombreUsuario, ''), CONCAT('(', B.CveUsuarioEjecuta, ') Eliminado') ) AS NombreUsuarioEjecuta, B.CveUsuarioAutoriza, B.FechaAutorizacion, B.LlaveRegistro, B.DescripcionMovimiento, B.FechaMovimiento, B.DireccionIP, B.NombreEquipo, B.Modulo FROM #BitacorasPagina AS P INNER JOIN dbo.Bit_Bitacora AS B ON B.CveBitacora = P.CveBitacora INNER JOIN dbo.Bit_Tablas AS T ON T.CveTabla = B.CveTabla INNER JOIN dbo.Bit_TiposMovimiento AS M ON M.CveTipoMovimiento = B.CveTipoMovimiento LEFT JOIN dbo.Bit_DefinicionesAccion AS A ON A.CveDefinicionAccion = B.CveDefinicionAccion LEFT JOIN dbo.Sis_Usuarios AS U ON U.CveUsuario = B.CveUsuarioEjecuta ORDER BY P.Orden; CREATE TABLE #CamposPagina ( OrdenPagina int NOT NULL, CveBitacoraCampo bigint NOT NULL PRIMARY KEY, CveBitacora bigint NOT NULL, CveCampo int NOT NULL, NombreCampoSQL varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, NombreMostrar varchar(150) COLLATE Modern_Spanish_CS_AS NOT NULL, ValorAnterior nvarchar(max) COLLATE Modern_Spanish_CS_AS NULL, ValorNuevo nvarchar(max) COLLATE Modern_Spanish_CS_AS NULL, ValorAnteriorMostrar nvarchar(max) COLLATE Modern_Spanish_CS_AS NULL, ValorNuevoMostrar nvarchar(max) COLLATE Modern_Spanish_CS_AS NULL ); INSERT INTO #CamposPagina ( OrdenPagina, CveBitacoraCampo, CveBitacora, CveCampo, NombreCampoSQL, NombreMostrar, ValorAnterior, ValorNuevo, ValorAnteriorMostrar, ValorNuevoMostrar ) SELECT P.Orden, BC.CveBitacoraCampo, BC.CveBitacora, BC.CveCampo, C.NombreCampoSQL, C.NombreMostrar, BC.ValorAnterior, BC.ValorNuevo, BC.ValorAnterior, BC.ValorNuevo FROM #BitacorasPagina AS P INNER JOIN dbo.Bit_BitacoraCampos AS BC ON BC.CveBitacora = P.CveBitacora INNER JOIN dbo.Bit_Campos AS C ON C.CveCampo = BC.CveCampo WHERE @EsAdministrador = 1 OR C.MostrarEnBitacora = 1; DECLARE @CveCampoOrigenReferencia int; DECLARE @NombreTablaReferencia varchar(128); DECLARE @NombreCampoLlaveReferencia varchar(128); DECLARE @NombreCampoMostrarReferencia varchar(128); DECLARE @SqlCampoReferencia nvarchar(max); -- Los identificadores del SQL dinámico salen únicamente de metadatos -- activos y se verifican contra sys.tables/sys.columns antes de usarse. DECLARE CursorCamposReferencia CURSOR LOCAL FAST_FORWARD FOR SELECT DISTINCT CO.CveCampo, TR.NombreTablaSQL, CL.NombreCampoSQL, CM.NombreCampoSQL FROM #CamposPagina AS CP INNER JOIN dbo.Bit_Campos AS CO ON CO.CveCampo = CP.CveCampo AND CO.Activo = 1 INNER JOIN dbo.Bit_Tablas AS TR ON TR.CveTabla = CO.CveTablaReferencia AND TR.Activo = 1 AND TR.NombreCampoLlaveSQL IS NOT NULL INNER JOIN dbo.Bit_Campos AS CL ON CL.CveTabla = TR.CveTabla AND CL.NombreCampoSQL = TR.NombreCampoLlaveSQL AND CL.Activo = 1 INNER JOIN dbo.Bit_Campos AS CM ON CM.CveCampo = CO.CveCampoMostrarReferencia AND CM.CveTabla = TR.CveTabla AND CM.MostrarEnBitacora = 1 AND CM.Activo = 1 INNER JOIN sys.schemas AS SC ON SC.name = 'dbo' INNER JOIN sys.tables AS ST ON ST.schema_id = SC.schema_id AND ST.name COLLATE Modern_Spanish_CS_AS = TR.NombreTablaSQL INNER JOIN sys.columns AS SCL ON SCL.object_id = ST.object_id AND SCL.name COLLATE Modern_Spanish_CS_AS = CL.NombreCampoSQL INNER JOIN sys.columns AS SCM ON SCM.object_id = ST.object_id AND SCM.name COLLATE Modern_Spanish_CS_AS = CM.NombreCampoSQL; OPEN CursorCamposReferencia; FETCH NEXT FROM CursorCamposReferencia INTO @CveCampoOrigenReferencia, @NombreTablaReferencia, @NombreCampoLlaveReferencia, @NombreCampoMostrarReferencia; WHILE @@FETCH_STATUS = 0 BEGIN SET @SqlCampoReferencia = N' UPDATE CP SET CP.ValorAnteriorMostrar = CASE WHEN CP.ValorAnterior IS NULL THEN NULL WHEN VA.' + QUOTENAME(@NombreCampoLlaveReferencia) + N' IS NULL THEN CONCAT(N''('', CP.ValorAnterior, N'') Eliminada'') WHEN NULLIF(CONVERT(nvarchar(max), VA.' + QUOTENAME(@NombreCampoMostrarReferencia) + N'), N'''') IS NULL THEN CONCAT(N''('', CP.ValorAnterior, N'')'') ELSE CONVERT(nvarchar(max), VA.' + QUOTENAME(@NombreCampoMostrarReferencia) + N') END, CP.ValorNuevoMostrar = CASE WHEN CP.ValorNuevo IS NULL THEN NULL WHEN VN.' + QUOTENAME(@NombreCampoLlaveReferencia) + N' IS NULL THEN CONCAT(N''('', CP.ValorNuevo, N'') Eliminada'') WHEN NULLIF(CONVERT(nvarchar(max), VN.' + QUOTENAME(@NombreCampoMostrarReferencia) + N'), N'''') IS NULL THEN CONCAT(N''('', CP.ValorNuevo, N'')'') ELSE CONVERT(nvarchar(max), VN.' + QUOTENAME(@NombreCampoMostrarReferencia) + N') END FROM #CamposPagina AS CP LEFT JOIN dbo.' + QUOTENAME(@NombreTablaReferencia) + N' AS VA ON CONVERT(nvarchar(250), VA.' + QUOTENAME(@NombreCampoLlaveReferencia) + N') COLLATE Modern_Spanish_CS_AS = CP.ValorAnterior COLLATE Modern_Spanish_CS_AS LEFT JOIN dbo.' + QUOTENAME(@NombreTablaReferencia) + N' AS VN ON CONVERT(nvarchar(250), VN.' + QUOTENAME(@NombreCampoLlaveReferencia) + N') COLLATE Modern_Spanish_CS_AS = CP.ValorNuevo COLLATE Modern_Spanish_CS_AS WHERE CP.CveCampo = @CveCampoOrigen;'; EXEC sys.sp_executesql @SqlCampoReferencia, N'@CveCampoOrigen int', @CveCampoOrigen = @CveCampoOrigenReferencia; FETCH NEXT FROM CursorCamposReferencia INTO @CveCampoOrigenReferencia, @NombreTablaReferencia, @NombreCampoLlaveReferencia, @NombreCampoMostrarReferencia; END; CLOSE CursorCamposReferencia; DEALLOCATE CursorCamposReferencia; SELECT CveBitacoraCampo, CveBitacora, CveCampo, NombreCampoSQL, NombreMostrar, ValorAnterior, ValorNuevo, ValorAnteriorMostrar, ValorNuevoMostrar FROM #CamposPagina ORDER BY OrdenPagina, CveBitacoraCampo; SELECT BR.CveBitacoraRelacion, BR.CveBitacora, BR.CveTipoRelacion, TR.Nombre AS TipoRelacion, BR.CveTablaRelacionada, T.NombreTablaSQL, BR.CveCampoRelacion, C.NombreCampoSQL, BR.LlaveRegistroRelacionada, BR.ValorRelacionNumero, BR.ValorRelacionTexto, BR.VisibleDesarrollador, BR.DescripcionRelacion FROM #BitacorasPagina AS P INNER JOIN dbo.Bit_BitacoraRelaciones AS BR ON BR.CveBitacora = P.CveBitacora INNER JOIN dbo.Bit_TiposRelacion AS TR ON TR.CveTipoRelacion = BR.CveTipoRelacion INNER JOIN dbo.Bit_Tablas AS T ON T.CveTabla = BR.CveTablaRelacionada LEFT JOIN dbo.Bit_Campos AS C ON C.CveCampo = BR.CveCampoRelacion AND C.CveTabla = T.CveTabla WHERE @EsAdministrador = 1 OR BR.VisibleDesarrollador = 1 ORDER BY P.Orden, BR.CveBitacoraRelacion; CREATE TABLE #RelacionesVisuales ( CveBitacora bigint NOT NULL, Orden int NOT NULL, NombreTablaSQL varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, NombreTabla varchar(150) COLLATE Modern_Spanish_CS_AS NOT NULL, NombreCampoSQL varchar(128) COLLATE Modern_Spanish_CS_AS NOT NULL, NombreCampo varchar(150) COLLATE Modern_Spanish_CS_AS NOT NULL, ValorClave nvarchar(250) COLLATE Modern_Spanish_CS_AS NOT NULL, ValorMostrar nvarchar(max) COLLATE Modern_Spanish_CS_AS NOT NULL ); DECLARE @OrdenRelacionMostrar int; DECLARE @CveTablaRelacionMostrar int; DECLARE @NombreTablaSQLRelacionMostrar varchar(128); DECLARE @NombreTablaRelacionMostrar varchar(150); DECLARE @CveCampoLlaveRelacionMostrar int; DECLARE @NombreCampoLlaveRelacionMostrar varchar(128); DECLARE @NombreCampoSQLRelacionMostrar varchar(128); DECLARE @NombreCampoRelacionMostrar varchar(150); DECLARE @SqlRelacionMostrar nvarchar(max); -- Tabla, llave y campo visible ya fueron resueltos contra la allowlist -- de Bit_Tablas/Bit_Campos y se delimitan nuevamente con QUOTENAME. DECLARE CursorRelacionesMostrar CURSOR LOCAL FAST_FORWARD FOR SELECT Orden, CveTabla, NombreTablaSQL, NombreTabla, CveCampoLlave, NombreCampoLlaveSQL, NombreCampoSQL, NombreCampo FROM @RelacionesMostrarResueltas ORDER BY Orden; OPEN CursorRelacionesMostrar; FETCH NEXT FROM CursorRelacionesMostrar INTO @OrdenRelacionMostrar, @CveTablaRelacionMostrar, @NombreTablaSQLRelacionMostrar, @NombreTablaRelacionMostrar, @CveCampoLlaveRelacionMostrar, @NombreCampoLlaveRelacionMostrar, @NombreCampoSQLRelacionMostrar, @NombreCampoRelacionMostrar; WHILE @@FETCH_STATUS = 0 BEGIN SET @SqlRelacionMostrar = N' INSERT INTO #RelacionesVisuales ( CveBitacora, Orden, NombreTablaSQL, NombreTabla, NombreCampoSQL, NombreCampo, ValorClave, ValorMostrar ) SELECT BR.CveBitacora, @Orden, @NombreTablaSQL, @NombreTabla, @NombreCampoSQL, @NombreCampo, BR.LlaveRegistroRelacionada, CASE WHEN V.' + QUOTENAME(@NombreCampoLlaveRelacionMostrar) + N' IS NULL THEN CONCAT(N''('', BR.LlaveRegistroRelacionada, N'') Eliminada'') WHEN NULLIF(CONVERT(nvarchar(max), V.' + QUOTENAME(@NombreCampoSQLRelacionMostrar) + N'), N'''') IS NULL THEN CONCAT(N''('', BR.LlaveRegistroRelacionada, N'')'') ELSE CONVERT(nvarchar(max), V.' + QUOTENAME(@NombreCampoSQLRelacionMostrar) + N') END FROM #BitacorasPagina AS P INNER JOIN dbo.Bit_BitacoraRelaciones AS BR ON BR.CveBitacora = P.CveBitacora INNER JOIN dbo.Bit_Bitacora AS B ON B.CveBitacora = P.CveBitacora LEFT JOIN dbo.' + QUOTENAME(@NombreTablaSQLRelacionMostrar) + N' AS V ON CONVERT(nvarchar(250), V.' + QUOTENAME(@NombreCampoLlaveRelacionMostrar) + N') COLLATE Modern_Spanish_CS_AS = BR.LlaveRegistroRelacionada COLLATE Modern_Spanish_CS_AS WHERE BR.CveTablaRelacionada = @CveTabla AND BR.CveCampoRelacion = @CveCampoLlave AND NOT ( BR.CveTipoRelacion = 1 AND BR.CveTablaRelacionada = B.CveTabla ) AND ( @EsAdministrador = 1 OR BR.VisibleDesarrollador = 1 );'; EXEC sys.sp_executesql @SqlRelacionMostrar, N'@Orden int, @NombreTablaSQL varchar(128), @NombreTabla varchar(150), @NombreCampoSQL varchar(128), @NombreCampo varchar(150), @CveTabla int, @CveCampoLlave int, @EsAdministrador bit', @Orden = @OrdenRelacionMostrar, @NombreTablaSQL = @NombreTablaSQLRelacionMostrar, @NombreTabla = @NombreTablaRelacionMostrar, @NombreCampoSQL = @NombreCampoSQLRelacionMostrar, @NombreCampo = @NombreCampoRelacionMostrar, @CveTabla = @CveTablaRelacionMostrar, @CveCampoLlave = @CveCampoLlaveRelacionMostrar, @EsAdministrador = @EsAdministrador; FETCH NEXT FROM CursorRelacionesMostrar INTO @OrdenRelacionMostrar, @CveTablaRelacionMostrar, @NombreTablaSQLRelacionMostrar, @NombreTablaRelacionMostrar, @CveCampoLlaveRelacionMostrar, @NombreCampoLlaveRelacionMostrar, @NombreCampoSQLRelacionMostrar, @NombreCampoRelacionMostrar; END; CLOSE CursorRelacionesMostrar; DEALLOCATE CursorRelacionesMostrar; SELECT RV.CveBitacora, RV.Orden, RV.NombreTablaSQL, RV.NombreTabla, RV.NombreCampoSQL, RV.NombreCampo, RV.ValorClave, RV.ValorMostrar FROM #RelacionesVisuales AS RV INNER JOIN #BitacorasPagina AS P ON P.CveBitacora = RV.CveBitacora ORDER BY P.Orden, RV.Orden; SET @Return = 1; END TRY BEGIN CATCH SET @ErrorMostrar = 'Ocurrió un error al consultar la bitácora; favor de contactar a Sistemas.'; SET @ErrorTipo = 1; SET @Return = 0; DECLARE @ErrorTecnico nvarchar(2048) = CONCAT( 'Número: ', ERROR_NUMBER(), '; Procedimiento: ', COALESCE( ERROR_PROCEDURE(), 'PA_Bit_BitacoraListByRelations' ), '; Línea: ', ERROR_LINE(), '; Detalle: ', ERROR_MESSAGE() ); RAISERROR(N'%s', 10, 1, @ErrorTecnico); END CATCH; END; GO