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 中的历史表的主要内容,如果未能解决你的问题,请参考以下文章