在postgresql中创建以下触发器(以执行与以下代码中定义的sqlserver触发器相同的逻辑)
CREATE TABLE IF NOT EXISTS lookup_dbo.finlstatassetdesignation(
finlstatassetdesignation CHAR(10) NOT NULL,
finlstatassetdesignationdesc VARCHAR(50) NOT NULL,
updoperation NUMERIC(5,0) NOT NULL DEFAULT (0),
upddate TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CLOCK_TIMESTAMP()
);
CREATE OR REPLACE FUNCTION TR_FinlStatAssetDesignation_U_TrFunc()
RETURNS TRIGGER LANGUAGE plpgsql
AS $$
DECLARE
AtDateTime TIMESTAMP;
SWV_error INTEGER;
SWV_RowCount INTEGER;
BEGIN
SWV_error := 0;
GET DIAGNOSTICS SWV_RowCount = ROW_COUNT;
IF (SWV_RowCount = 0) then
RETURN NULL;
end if;
AtDateTime := LOCALTIMESTAMP;
if OLD.FinlStatAssetDesignation IS DISTINCT FROM NEW.FinlStatAssetDesignation then
RAISE EXCEPTION 'Invalid attempt to update OID FinlStatAssetDesignation in FinlStatAssetDesignation';
-- Rollback
RETURN NULL;
end if;
if not OLD.UpdDate IS DISTINCT FROM NEW.UpdDate then
SWV_error := 0;
begin
UPDATE lookup_dbo.finlstatassetdesignation
SET UpdDate = AtDateTime
WHERE a.FinlStatAssetDesignation = NEW.FinlStatAssetDesignation;
EXCEPTION
WHEN OTHERS
THEN
SWV_error := -1;
RETURN NULL;
end;
if SWV_error <> 0 then
-- RollBack
RETURN NULL;
end if;
SWV_error := 0;
end if;
RETURN NULL;
END; $$;
CREATE Trigger tr_finlstatassetdesignation_u
AFTER Update on lookup_dbo.finlstatassetdesignation FOR EACH ROW
EXECUTE PROCEDURE lookup_dbo.tr_finlstatassetdesignation_u_trfunc();
SQL Server原始触发代码:-
-- Add Update Trigger to FinlStatAssetDesignation
CREATE Trigger TR_FinlStatAssetDesignation_U on FinlStatAssetDesignation for Update NOT FOR REPLICATION as
IF (@@RowCount = 0) return
DECLARE @AtDateTime datetime
SELECT @AtDateTime = GETDATE()
if Update(FinlStatAssetDesignation)
Begin
RaisError( 'Invalid attempt to update OID FinlStatAssetDesignation in FinlStatAssetDesignation', 16, 1 )
Rollback Tran
return
end
if not Update(UpdDate)
begin
Update a
set UpdDate = @AtDateTime
from FinlStatAssetDesignation a, Inserted i
where a.FinlStatAssetDesignation = i.FinlStatAssetDesignation
if @@ERROR<>0
begin
RollBack tran
return/* Execution stops here! */
end
end
go
在postgresql甚至原始sqlserver中转换的触发器有两个部分...对于第一个部分..似乎在postgresql中可以进行后期转换,但是第二部分似乎不起作用...请帮助
答案 0 :(得分:2)
这是您的问题:
GET DIAGNOSTICS SWV_RowCount = ROW_COUNT;
IF (SWV_RowCount = 0) THEN
RETURN NULL;
END IF;
由于您是在函数开头执行此操作,并且函数中没有先前的SQL语句 ,因此该值将始终为零,并且触发器将立即退出。
您似乎假设ROW_COUNT
将包含触发该函数的语句中修改的行数,但事实并非如此。它包含该函数本身中最后一个SQL语句修改的行数。
您只需删除此支票即可。触发函数将针对被修改的每一行进行调用,因此,如果未修改任何一行,则根本不会调用该函数。
最后,除非有充分的理由阻止在该函数上执行其他RETURN NEW;
触发器,否则从触发器函数中AFTER UPDATE
是一个好习惯。
答案 1 :(得分:1)
如果要阻止某些更新并且要更改更新(或插入)行的值,请不要使用AFTER触发器。使用BEFORE
触发器,只需分配所需的值即可。另外,您不能真正在AFTER触发器中停止UPDATE。
在行级触发器中检查受影响的行数完全没有用。 如果触发了触发器,则该数字始终为 1
。
如果我正确理解了您的意图,则简化后的代码应为:
CREATE OR REPLACE FUNCTION tr_finlstatassetdesignation_u_trfunc()
RETURNS TRIGGER
LANGUAGE plpgsql
AS
$$
BEGIN
if old.finlstatassetdesignation IS DISTINCT FROM new.finlstatassetdesignation then
RAISE EXCEPTION 'Invalid attempt to update FinlStatAssetDesignation in FinlStatAssetDesignation';
-- Rollback
RETURN NULL;
end if;
if not old.upddate IS DISTINCT FROM new.upddate then
new.upddate := clock_timestamp();
end if;
-- this is important in a BEFORE trigger!
RETURN new;
END
$$;
连同以下触发器定义:
CREATE Trigger tr_finlstatassetdesignation_u
BEFORE Update on lookup_dbo.finlstatassetdesignation
FOR EACH ROW
EXECUTE PROCEDURE lookup_dbo.tr_finlstatassetdesignation_u_trfunc();