Hola de nuevo...
Cita:
Iniciado por amtzva Gracias por contestar... te cuento:
Tengo 2 bases de datos con tablas identicas en estructura, la primera bd es producción y la segunda es una réplica utilizada para reportes, estoy trabajando en la plataforma de SQL2000
Estoy utilizando una query sql en un store procedure para detectar los registros que se crean borran o modifican en la bd1 y replicar estos cambios en la bd2, para ello estoy utilizando ckecksum_agg(binary_checksum(*)) from tabla x aplicado tanto en la tabla fuente como en la tabla destino....
Todo iba muy bien... pero recientemente en datos modificados no me está detectando un cambio que se hizo en un valor, a pesar de que está demostrado que si existe el cambio, los valores son:
Produccion: E700 79899186 40 22OP 01 NO .50
Replica: E700 79899186 40 22OP 01 NO 5.00
El valor que originalmente se capturó fue 5.00, por un error de captura, luego se modifica el valor a 0.50 en producción, sin embargo al correr la instrucción de verificación del cambio no detecta este cambio y por tanto lo pasa por alto sin afectar en la bd2 de la réplica...
observaciones...
puede cambiar cualquier campo de la tabla, tengo tablas que tiene mas de 200 campos con 1 solo campo llave...
estas tablas pertenecen a un ERP por lo tanto no puedo migrar de version de sql .
Leyendo la documentación del Binary_checksum me dice que es mejor utilizar el hashbytes... pero no he encontrado como aplicarlo a mi necesidad...
De nuevo gracias por el aporte y estoy atento a tus comentarios
Ahora si lo tengo más claro, sin embargo, mi ayuda se va a ver limitada por lo siguiente:
- Hace años que no uso SQL Server 2000. Actualmente uso mucho más PostgreSQL y en menor medida, SQL Server 2008.
- No conozco tu estructura de datos ni como funciona tu procedimiento almacenado
- Nota: No quiero tampoco que me pases información sensible de tu ERP, ni de la Base de datos, sólo te aclaro que con las limitaciones que tengo puede que la ayuda que te preste no sea la más óptima.
Aclarado los puntos anteriores vamos a ver el problema, lo diagramé, porque siempre es mejor verlo con imágenes que con palabras:
Uploaded with
ImageShack.us
Supongo que sabes como funciona HASHBYTES, si no, te lo explico:
Esta función se encarga de tomar los datos de un campo y lo encripta en algún algoritmo como por ejemplo SHA1 o MD5 entre otros.
Esto quiere decir que un texto cualquiera como por ejemplo el siguiente: "E700 79899186 40 22OP 01 NO 5.00" al usar Hashbytes con SHA1 se transforma en lo siguiente: "57A50D8AD69FE716DEFE744BDC56CDE980AB24CE"
Los algoritmos de encriptación como SHA1 o MD5 son CASE SENSITIVE, o sea, marcan diferencia entre "A" y "a", dando resultados diferentes de encriptación entre uno y otro aunque sea la misma letra.
Para tu caso en concreto se procedería de forma análoga, te lo coloco como pseudocódigo para mayor claridad:
- Obtener el valor del campo modificado de la Base de datos primaria.
- Aplicar la función HASHBYTES y guardar el resultado en una variable temporal.
- Obtener el valor del mismo campo en la Base de datos secundaria y del registro equivalente.
- Aplicar la función HASHBYTES y guardar el resultado en una variable temporal.
- Comparar los dos resultados.
- Si son distintos entonces actualizar el campo de la base de datos secundaria con el valor del campo de la base de datos primaria.
Aquí te dejo el ejemplo que desarrollé en SQL Server 2008:
Cree una base de datos para hacer la prueba, el nombre de la base de datos es "Test", sin las comillas.
Tabla "Primaria":
Código SQL:
Ver originalUSE [Test]
GO
/****** Object: Table [dbo].[Primaria] Script Date: 08/26/2010 21:53:59 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Primaria](
[id] [BIGINT] NOT NULL,
[campo] [nvarchar](50) NULL,
CONSTRAINT [PK_Primaria] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
Tabla "Secundaria":
Código SQL:
Ver originalUSE [Test]
GO
/****** Object: Table [dbo].[Secundaria] Script Date: 08/26/2010 21:54:45 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Secundaria](
[id] [BIGINT] NOT NULL,
[campo] [nvarchar](50) NULL,
[fid] [BIGINT] NOT NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Secundaria] WITH CHECK ADD CONSTRAINT [FK_Secundaria_Primaria] FOREIGN KEY([fid])
REFERENCES [dbo].[Primaria] ([id])
GO
ALTER TABLE [dbo].[Secundaria] CHECK CONSTRAINT [FK_Secundaria_Primaria]
GO
Datos de la tabla "Primaria":
Código SQL:
Ver originalINSERT INTO [Test].[dbo].[Primaria] ([id],[campo]) VALUES (1,'E700 79899186 40 22OP 01 NO .50');
INSERT INTO [Test].[dbo].[Primaria] ([id],[campo]) VALUES (2,'E700 79899186 40 22OP 01 NO .40');
INSERT INTO [Test].[dbo].[Primaria] ([id],[campo]) VALUES (3,'E700 79899186 40 22OP 01 NO .30');
INSERT INTO [Test].[dbo].[Primaria] ([id],[campo]) VALUES (4,'E700 79899186 40 22OP 01 NO .20');
Datos de la tabla "Secundaria":
Código SQL:
Ver originalINSERT INTO [Test].[dbo].[Secundaria] ([id],[campo],[fid]) VALUES (1,'E700 79899186 40 22OP 01 NO 5.00',2);
INSERT INTO [Test].[dbo].[Secundaria] ([id],[campo],[fid]) VALUES (1,'E700 79899186 40 22OP 01 NO 5.00',1);
INSERT INTO [Test].[dbo].[Secundaria] ([id],[campo],[fid]) VALUES (1,'E700 79899186 40 22OP 01 NO 5.00',1);
INSERT INTO [Test].[dbo].[Secundaria] ([id],[campo],[fid]) VALUES (1,'E700 79899186 40 22OP 01 NO 5.00',1);
INSERT INTO [Test].[dbo].[Secundaria] ([id],[campo],[fid]) VALUES (1,'E700 79899186 40 22OP 01 NO 5.00',2);
Procedimiento almacenado "Modificar", se encarga de modificar el campo usando la función HASHBYTES:
Código SQL:
Ver originalUSE [Test]
GO
/****** Object: StoredProcedure [dbo].[Modificar] Script Date: 08/26/2010 22:00:56 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Xdrtas, http://xdrtas.coolpage.biz/>
-- Create date: <26 de Agosto del 2010>
-- Description: <Comparar campos mediante HASHBYTES>
-- =============================================
ALTER PROCEDURE [dbo].[Modificar]
AS
BEGIN
SET NOCOUNT ON;
--Se declaran las variables que se van a usar para comparar los resultados de los campos...
--@pri_pri: Contiene el valor encriptado en "SHA1" del campo "campo" de la tabla "Primaria"...
--@sec_pri: Contiene el valor encriptado en "SHA1" del campo "campo" de la tabla "Secundaria"...
--@texto_P: (Tabla Primaria). Contiene el valor del campo obtenido mediante un query, este valor NO está encriptado.
--@texto_S: (Tabla Secundaria). Contiene el valor del campo obtenido mediante un query, este valor NO está encriptado.
DECLARE @pri_pri AS nvarchar(64),
@sec_pri AS nvarchar(64),
@texto_P AS nvarchar(64),
@texto_S AS nvarchar(64)
SELECT @texto_P = p.campo FROM Primaria p WHERE id = 1;
SET @pri_pri = CONVERT(nvarchar(64), HASHBYTES('SHA1',@texto_P),2);
SELECT @texto_S = s.campo FROM Test.dbo.Secundaria s WHERE fid = 1;
SET @sec_pri = CONVERT(nvarchar(64), HASHBYTES('SHA1',@texto_S),2);
--Se compara los resultados, si son distintos, entonces se tiene que modificar el campo de la tabla "Secundaria"
--Se usa la variable @texto_P que contiene el valor del campo modificado de la tabla "Primaria"...
IF @pri_pri <> @sec_pri
UPDATE Secundaria SET campo = @texto_P WHERE fid = 1;
END
Si @pri_pri es distinto de @sec_pri entonces se hace el UPDATE a la tabla "Secundaria" con el valor actual de la tabla "Primaria" que se guardó en la variable @texto_P, fíjate que este valor NO está encriptado, es el valor original del campo modificado.
Si son iguales las variables @pri_pri y @sec_pri entonces no hace falta la actualización.
NOTA: fid, es la clave foránea en la tabla "Secundaria" con relación al id de la tabla "Primaria", es para relacionar las tablas de 1 a N.
Soy conciente de que tu tienes que hacer la actualización de una base de datos a otra, no de una tabla a otra, sin embargo, por lo que he leído, eso ya lo tienes cubierto, así que la idea de este ejercicio es ilustrarte como hacer la comparación en Transact-SQL y como funciona.
Lo que queda es adaptarlo a tus necesidades, cosa que no he podido hacer porque no tengo todos lo datos ni siquiera la misma versión de bases de datos, pero eso ya te queda a tí hacerlo.
Recuerda hacer primero las pruebas en un base de datos independiente y cuando estés seguro del resultado lo lleves a la base de datos de producción.
Bueno, eso es todo, espero que se aclare tu duda y lo puedas adaptar sin muchos problemas a tú código.
Un cordial saludo.