使用Sybase触发器使用所有旧值和新值编写动态语句来创建自己的复制事务语句日志?

问题描述 投票:0回答:1

PROBLEM SUMMARY

我必须在Sybase ADS和Postgresql 11组节点之间为bucardo / symmetricDS启发的自制双向复制系统编写I / U / D语句生成触发器,在创建插入/更新的任何Postgresql和Sybase DB上使用BEFORE触发器/根据在复制源表中输入的命令删除命令:例如一个INSERT INTO PERSON (first_name,last_name,gender,age,ethnicity) Values ('John','Doe','M',42,'C')并将它们操作到相应的Insert语句中,UPDATE通过获取OLD和NEW值来动态生成UPDATE语句,同时获取OLD值以生成DELETE命令,所有这些都在某个时间间隔内在目标上运行。

我知道这很困难,没有人这样做,但这是一份工作,我没有其他选择,也不能反对提供不同的解决方案。我没有其他队友或人力资源来帮助SO之外以及像Codementors这样的东西,这些都没那么有用。我的想法/策略是在插入OLD和NEW值时复制部分bucardo / SymmetricDS,以生成在目标上运行的语句/命令。现在,我正在将整个表快照到CSV而不是单独执行命令,但通过命令和循环生成并保存命令的表将使工作更容易。

一个大问题是它们来自Sybase ADS并且具有混合的键/索引结构(许多表没有PK)并且正在Postgresql中镜像,所以我试图编写无PK语句或全列命令来获取在no-pk表周围。它们也只会复制某些表的某些列,因此我在表中有一列用于插入由';'分隔的列名称然后将其拆分为一个数组,并将列名链接到每个语句的值,以生成I / U / D的完整命令,希望如此。我对其他策略持开放态度,但这是一个很大的独奏项目,我在很多方面遇到了很多困难。

我主要来自DBA背景,并且具有一些基础知识的编程经验,所以我主要是对每个主要序列进行伪编码,通过部分搜索语法,以及随着时间调整或遇到语言无能力。我感谢任何帮助,因为我有点绝望和沮丧。

WHAT I HAVE TRIED

我必须为Sybase ADS和Postgresql执行此操作,但这个问题最初是针对ADS的,因为它更具挑战性和更老。

一个“Log”表跟踪每个复制表和记录的行更改,并最终动态生成命令是两个平台的目标。我正在尝试制作触发器语句,如:

CREATE TRIGGER PERSON_INSERT
ON PERSON
BEFORE 
INSERT
BEGIN
INSERT INTO Backlog (SourceTableID, TriggerType, Status, CreateTimeDate, NewValues) select ID, 'INSERT','READY', NOW(),''first_name';'last_name';'gender';'age';'ethnicity'' from __new;
END;

CREATE TRIGGER PERSON_UPDATE
   ON PERSON
   BEFORE 
   UPDATE 
BEGIN 
INSERT INTO Backlog (SourceTableID, TriggerType, Status, CreateTimeDate, NewValues) select ID, 'U','UPDATE','READY', NOW(),''first_name';'last_name';'gender';'age';'ethnicity'' from __new;
UPDATE Backlog SET OldValues=select ''first_name';'last_name';'gender';'age';'ethnicity'' from __old where SourceTableID=select ID from __old;
END;

CREATE TRIGGER PERSON_DELETE
   ON PERSON
   BEFORE 
   DELETE 
BEGIN 
INSERT INTO Backlog (SourceTableID, TriggerType, Status, CreateTimeDate, OldValues) select ID, 'D','DELETE','READY', NOW(),''first_name';'last_name';'gender';'age';'ethnicity'' from __old;
END;

但我希望“''first_name';'last_name';'gender';'age';'ethnicity''”来自另一个表作为一个值,使其成为动态,因为多个表将写出它们的值和语句信息到单个日志表。然后,它可以变成一个变量,然后可能会拆分为链接到相应的值,因此可以制作IUD语句,这些语句将一次在目标语句上执行。

ATTEMPTED INCOMPLETE SAMPLE TRIGGER CODE

CREATE TRIGGER PERSON_INSERT
   ON PERSON
   BEFORE 
INSERT
BEGIN
--Declare @Columns string
--@Columns=select Columns from metatable where tablename='PERSON'
--String Split(@Columns,';') into array to correspond to new and old VALUES
--@NewValues=@['@Columns='+NEW.@Columns+'']
INSERT INTO Backlog (SourceTableID, TriggerType, Status, CreateTimeDate, NewValues) select ID, 'INSERT','READY', NOW(),''first_name';'last_name';'gender';'age';'ethnicity'' from __new;
END;

CREATE TRIGGER PERSON_UPDATE
   ON PERSON
   BEFORE 
   UPDATE 
BEGIN 
--Declare @Columns string
--@Columns=select Columns from metatable where tablename='PERSON'
--String Split(@Columns,';') into array to correspond to new and old VALUES
--@NewValues=@['@Columns='+NEW.@Columns+'']
--@OldValues=@['@Columns='+OLD.@Columns+'']
INSERT INTO Backlog (SourceTableID, TriggerType, Status, CreateTimeDate, NewValues) select ID, 'U','UPDATE','READY', NOW(),''first_name';'last_name';'gender';'age';'ethnicity'' from __new;
UPDATE Backlog SET OldValues=select ''first_name';'last_name';'gender';'age';'ethnicity'' from __old where SourceTableID=select ID from __old;
END;

CREATE TRIGGER PERSON_DELETE
   ON PERSON
   BEFORE 
   DELETE 
BEGIN 
--Declare @Columns string
--@Columns=select Columns from metatable where tablename='PERSON'
--String Split(@Columns,',') into array to correspond to new and old VALUES
--@OldValues=@['@Columns='+OLD.@Columns+'']
INSERT INTO Backlog (SourceTableID, TriggerType, Status, CreateTimeDate, OldValues) select ID, 'D','DELETE','READY', NOW(),''first_name';'last_name';'gender';'age';'ethnicity'' from __old;
END;

CONCLUSION

对于插入,更新或删除的每一行;在日志表的COMMAND列中,我试图生成相应的'INSERT INTO PERSON('+ @ Columns +')VALUES('+ @ NewValues +')'类型语句,或UPDATE或DELETE。然后,Foreach服务将运行按创建时间排序的每个命令值作为主复制服务。

为了清楚起见,我试图使我的示例代码触发器以动态方式将所有旧值和新值写入列,而不对每个触发器中的列进行硬编码,因为它将用于多个表,并将值写入单个以逗号或分号分隔的列。

这背后更大的愿望或目标是找到一种方法来保存/编写每个IUD命令,然后能够在postgresql和Sybase平台的订阅服务器.DB上运行它们,从而从日志中创建自己的复制

loops triggers sybase dynamic-sql advantage-database-server
1个回答
0
投票

这是一个复杂但可解决的问题,需要花时间和仔细的计划来编写。我认为您正在寻找的是ADS SQL语法中的“Execute Immediate”命令。使用此命令,您可以创建一个动态语句,然后在SQL语句的构造终止后执行。通过仔细地将语句构造为字符串,然后使用Execute Immediate执行它,将每个所需的列值保存到临时表。例如:

DECLARE TableColumns Cursor ; 
DECLARE FldName Char(100) ;
...
OPEN TableColumns AS SELECT * 
                       FROM system.columns 
                      WHERE parent = @cTableName 
                        AND field_type < 21 //ADS_ROWVERSION
                        AND field_type <> 6 //ADS_BINARY 
                        AND field_type <> 7; //ADS_IMAGE

While Fetch TableColumns DO

    FldName = Trim( TableColumns.Name) ;

    StrSql = 'SELECT New.[' + Trim( FldName ) + '] newVal' +
             'INTO #myTmpTable FROM ___New n' ;

在将语句构造为字符串之后,可以像这样执行:

EXECUTE IMMEDIATE STRSQL ; 

您可以从始终可用于触发器的__old和__new临时表中拾取旧值和新值。将值插入临时表myTmpTable,然后使用它来更新目标。记得最后放下myTmpTable。

此外,我认为您可以在DD上创建一个函数,该函数实际上可以从您要跟踪的表上的每个触发器调用,而不是为每个表写一个长触发器,而cTableName可以是发送到该函数的参数。这将使维护更容易一些。

© www.soinside.com 2019 - 2024. All rights reserved.