После обновления триггер в postgresql не работает должным образом - PullRequest
0 голосов
/ 18 сентября 2018

Создано ниже триггера в 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 one состоит из 2 частей ... для первой ... кажется, что после конвертации в postgresql работает, но вторая часть не работает ... помогите

Ответы [ 2 ]

0 голосов
/ 18 сентября 2018

Если вы хотите запретить определенные обновления и хотите изменить значения строки обновления (или вставленной), не используйте триггер AFTER.Используйте триггер BEFORE и просто назначьте желаемое значение.Кроме того, вы не можете остановить UPDATE в триггере AFTER.

Проверка количества затронутых строк совершенно бесполезна в триггере уровня строки. Если срабатывает триггер, то это число всегда 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
    <b>BEFORE</b> Update on lookup_dbo.finlstatassetdesignation 
    FOR EACH ROW
    EXECUTE PROCEDURE lookup_dbo.tr_finlstatassetdesignation_u_trfunc();

Онлайн пример: http://rextester.com/EWILW61724

0 голосов
/ 18 сентября 2018

Это ваша проблема:

GET DIAGNOSTICS SWV_RowCount = ROW_COUNT;
IF (SWV_RowCount = 0) THEN 
   RETURN NULL;
END IF;

Поскольку вы выполняете это в начале функции, и в функции не было никакого предшествующего оператора SQL , значение всегда будет равно нулю, и триггер немедленно завершится.

Кажется, вы предполагаете, что ROW_COUNT будет содержать количество строк, измененных в операторе, вызвавшем функцию, но это не так. Он содержит количество строк, измененных последним оператором SQL в самой функции .

Вы можете просто удалить эту проверку. Функция триггера будет вызываться для каждой изменяемой строки, поэтому она не будет вызываться вообще, если не изменена ни одна строка.

Наконец, это хорошая привычка RETURN NEW; использовать функцию триггера, если только у вас нет веской причины препятствовать выполнению других триггеров AFTER UPDATE для этой функции.

...