SQL Server 中的历史表

Posted

技术标签:

【中文标题】SQL Server 中的历史表【英文标题】:Historical Table in SQL Server 【发布时间】:2016-06-29 13:09:32 【问题描述】:

我有两张桌子;第一个名为PAYMENT,第二个是名为RecordPay的历史表。

我有两个触发器,第一个用于插入,以便从Payment 表中插入历史表记录。

代码如下:

ALTER TRIGGER [dbo].[INSERT_HIST]
ON  [dbo].[PAYMENT]
FOR  INSERT
AS 
BEGIN
     DECLARE @User_op varchar(50) 
     DECLARE @RGNO varchar(50)

     DECLARE @PAYEUR varchar(50)
     DECLARE @DATESYS SMALLDATETIME 
     DECLARE @RG_DATE SMALLDATETIME 
     DECLARE @RG_Montant varchar(50)

     SELECT @User_op = cbUserName 
     FROM cbUserSession 
     WHERE cbSession = @@SPID

     SELECT @PAYEUR = CT_NumPayeur FROM INSERTED

     SELECT @DATESYS = GETDATE()
     SELECT @RG_Montant = RG_Montant FROM INSERTED
     SELECT @RG_DATE = RG_DATE FROM INSERTED
     SELECT @RGNO = RG_No FROM INSERTED

     INSERT INTO RecordPay (RG_NO, PAYEUR, CAISSIER, Montant, DATESYS,   DATECAI)
     VALUES (@RGNO, @PAYEUR, @user_op, @RG_Montant, @DATESYS, @RG_DATE)

这很好用,当我从PAYMENT 中删除一行时,我的问题是在RecordPay 中记录存在,然后当我在PAYMENT 中插入另一行时,我有两个RG_NO 具有相同的数字。

例如,我在PAYMENT 中插入一行 RG_NO=1,然后我删除了一行,然后我在 recordPay(历史表)中创建了另一行 RG_NO=2,我得到两行 RG_NO=1。

这是删除的触发器,但它不起作用

 ALTER TRIGGER [dbo].[DEL_HIST]
 ON  [dbo].[PAYMENT]
 AFTER  DELETE
 AS 
 BEGIN


 DECLARE @User_op varchar(50) 
 DECLARE @RGNO varchar(50)

 DECLARE @PAYEUR varchar(50)
 DECLARE @DATESYS SMALLDATETIME 
 DECLARE @RG_DATE SMALLDATETIME 
 DECLARE @RG_Montant varchar(50)


 SELECT @PAYEUR = CT_NumPayeur FROM DELETED

 SELECT @RG_Montant = RG_Montant FROM DELETED
 SELECT @RG_DATE = RG_DATE FROM DELETED
SELECT @RGNO = RG_No FROM DELETED

DELETE FROM RECORDPAY  WHERE  
RG_NO=@RGNO and PAYEUR= @PAYEUR  and CAISSIER=@user_op and Montant=@RG_Montant 
END

【问题讨论】:

你犯了触发器的经典错误;假设INSERTED 中只有 1 行。另一点 - 在支付处理行中从不删除,支付撤销通常是通过另一个支付来否定第一个支付。 感谢您的回复,但您能举个例子吗?我不太明白 如果您想删除5 的付款,您不会从付款中删除该行,您需要输入-5 的新付款来平衡它 你为什么对我们大喊大叫?用大写字母输入你的标题不会让你更快地得到答案,这很烦人,而且非常粗鲁。我们在这里都能很好地阅读,你不必大喊大叫来引起注意。您也不必全部大写寻求帮助。有人会在没有您的请求的情况下提供帮助。请保持礼貌,停止大喊大叫。 你在说什么肯!!!!!!我不粗鲁,我写标题时没有注意。 PS我是来学习的。如果你能帮忙,谢谢你,否则我不会讨论任何超出主题的事情 【参考方案1】:

只要INSERT 语句一次插入多于 1 行,您的触发器就会BREAK - 因为在这种情况下,您的触发器会被调用一次 INSERT 语句,Inserted 将包含多行。

您从这里选择这 10 行中的哪一行??

 SELECT @PAYEUR = CT_NumPayeur FROM INSERTED
 SELECT @RG_Montant = RG_Montant FROM INSERTED
 SELECT @RG_DATE = RG_DATE FROM INSERTED
 SELECT @RGNO = RG_No FROM INSERTED

这是任意且不确定的 - 您将简单地忽略Inserted 中的所有其他行。

您需要重写触发器以考虑到这一点:

ALTER TRIGGER [dbo].[INSERT_HIST]
ON  [dbo].[PAYMENT]
FOR  INSERT
AS 
BEGIN
     DECLARE @User_op varchar(50) 

     SELECT @User_op = cbUserName 
     FROM cbUserSession 
     WHERE cbSession = @@SPID

     -- insert a record for ALL the rows that were inserted into 
     -- your history table in a single, elegant, set-based statement
     INSERT INTO RecordPay (RG_NO, PAYEUR, CAISSIER, Montant, DATESYS,   DATECAI)
         SELECT
             RG_No, CT_NumPayeur, @User_op, RG_Montant, SYSDATETIME(), RG_Date
         FROM
             Inserted

【讨论】:

以上是关于SQL Server 中的历史表的主要内容,如果未能解决你的问题,请参考以下文章

列中的调用历史 SQL SERVER

sql server 2000返回在第一个表中但不在第二个表中的数据

sql 从SQL Server中查找所有表中的列

从oracle表中选择sql server表中的列

SQL Server:复制表中的列

将多用户环境中的表中的 ms 访问数据附加到 sql server 表中