有没有办法在一个脚本中创建多个触发器?

Posted

技术标签:

【中文标题】有没有办法在一个脚本中创建多个触发器?【英文标题】:Is there a way to create multiple triggers in one script? 【发布时间】:2011-11-06 04:29:39 【问题描述】:

我正在尝试创建多个触发器,只需将一个脚本上传到 Oracle DB/APEX 工作区并运行一次。

与我尝试使用的脚本相比,这是一个简短的脚本:

    create or replace trigger "BI_TEC_ROLES"   
      before insert on "TEC_ROLES"               
      for each row  
    begin   
      if :NEW."ROLE_ID" is null then 
        select "TEC_ROLES_SEQ".nextval into :NEW."ROLE_ID" from dual; 
      end if; 
    end; 

    create or replace trigger "BI_TEC_STATUSES"   
      before insert on "TEC_STATUSES"               
      for each row  
    begin   
      if :NEW."STATUS_ID" is null then 
        select "TEC_STATUSES_SEQ".nextval into :NEW."STATUS_ID" from dual; 
      end if; 
    end; 

    create or replace trigger "BI_TEC_SUBS"   
      before insert on "TEC_SUBS"               
      for each row  
    begin   
      if :NEW."SUB_ID" is null then 
        select "TEC_SUBS_SEQ".nextval into :NEW."SUB_ID" from dual; 
      end if; 
    end; 

我尝试将 GO 放在每个单独的块之间,但仍然只创建第一个触发器,然后给我第二个说法的错误:

    Error(7,1): PLS-00103: Encountered the symbol "CREATE" 

我希望可以做到这一点。非常感谢您的时间和兴趣 =)

【问题讨论】:

【参考方案1】:

在每次触发后在新行添加一个正斜杠以执行缓冲区中的命令:

create trigger...
...
end;
/

【讨论】:

太棒了!在 APEX 中运行脚本时有效(当然是在上传之后),但在 SQL Developer 中表现得很有趣?哦,好的,谢谢!!! @Kamron K.,在 SQL Developer 中,您需要单击“运行脚本 (F5)”按钮来创建所有触发器(不是主“运行语句”按钮)。【参考方案2】:

在每个触发器语句之间的空白行上放置一个斜杠“/”作为第一个字符。这是 'go' 的 SQL*PLUS 等价物。

【讨论】:

太棒了!在 APEX 中运行脚本时有效(当然是在上传之后),但在 SQL Developer 中表现得很有趣?哦,好的,谢谢!!!【参考方案3】:

放置一个正斜杠

/

在两个语句之间单独一行。

Oracle 将接受它作为新语句

【讨论】:

【参考方案4】:

是的,我们可以使用 SQL 文件中的 FORWARD SLASH / 在单个脚本中执行多个过程/触发器/函数。

如下:

create or replace trigger "BI_TEC_ROLES"   
      before insert on "TEC_ROLES"               
      for each row  
    begin   
      if :NEW."ROLE_ID" is null then 
        select "TEC_ROLES_SEQ".nextval into :NEW."ROLE_ID" from dual; 
      end if; 
    end; 

/
    create or replace trigger "BI_TEC_STATUSES"   
      before insert on "TEC_STATUSES"               
      for each row  
    begin   
      if :NEW."STATUS_ID" is null then 
        select "TEC_STATUSES_SEQ".nextval into :NEW."STATUS_ID" from dual; 
      end if; 
    end; 

/

   create or replace trigger "BI_TEC_SUBS"   
      before insert on "TEC_SUBS"               
      for each row  
    begin   
      if :NEW."SUB_ID" is null then 
        select "TEC_SUBS_SEQ".nextval into :NEW."SUB_ID" from dual; 
      end if; 
    end; 

/

然后oracle会将其视为新语句/块。

【讨论】:

【参考方案5】:
--Parameter: 
--  @InclDrop bit   
--  Possible values 
--    0 - Script to drop the triggers is not generated.   
--    1 - Script to drip the triggers is generated. 

SET ansi_nulls ON 

go 

SET quoted_identifier ON 

go 


ALTER PROCEDURE [dbo].[Createscriptofalltriggers] 

@InclDrop BIT =1

AS 

DECLARE @SQL VARCHAR(8000), 
        @Text            NVARCHAR(4000), 
        @BlankSpaceAdded INT, 
        @BasePos         INT, 
        @CurrentPos      INT, 
        @TextLength      INT, 
        @LineId          INT, 
        @MaxID           INT, 
        @AddOnLen        INT, 
        @LFCR            INT, 
        @DefinedLength   INT, 
        @SyscomText      NVARCHAR(4000), 
        @Line            NVARCHAR(1000), 
        @UserName        SYSNAME, 
        @ObjID           INT, 
        @OldTrigID       INT 

SET nocount ON 
SET @DefinedLength = 1000 
SET @BlankSpaceAdded = 0 

IF @InclDrop <> 0 
  SET @InclDrop =1 

-- This Part Validated the Input parameters   
DECLARE @Triggers TABLE 
  ( 
     username SYSNAME NOT NULL, 
     trigname SYSNAME NOT NULL, 
     objid    INT NOT NULL 
  ) 
DECLARE @TrigText TABLE 
  ( 
     objid    INT NOT NULL, 
     lineid   INT NOT NULL, 
     linetext NVARCHAR(1000) NULL 
  ) 

INSERT INTO @Triggers 
            (username, 
             trigname, 
             objid) 
SELECT DISTINCT A.NAME, 
                B.NAME, 
                B.id 
FROM   dbo.sysusers A, 
       dbo.sysobjects B, 
       dbo.syscomments C 
WHERE  A.uid = B.uid 
       AND B.type = 'Tr' 
       AND B.id = C.id 
       AND C.encrypted = 0 

IF EXISTS(SELECT C.* 
          FROM   syscomments C, 
                 sysobjects O 
          WHERE  O.id = C.id 
                 AND O.type = 'Tr' 
                 AND C.encrypted = 1) 
  BEGIN 
      PRINT '/*' 

      PRINT 'The following encrypted triggers were found' 

      PRINT 'The procedure could not write the script for it' 

      SELECT DISTINCT A.NAME, 
                      B.NAME, 
                      B.id 
      FROM   dbo.sysusers A, 
             dbo.sysobjects B, 
             dbo.syscomments C 
      WHERE  A.uid = B.uid 
             AND B.type = 'Tr' 
             AND B.id = C.id 
             AND C.encrypted = 1 

      PRINT '*/' 
  END 

DECLARE ms_crs_syscom CURSOR local forward_only FOR 
  SELECT T.objid, 
         C.text 
  FROM   @Triggers T, 
         dbo.syscomments C 
  WHERE  T.objid = C.id 
  ORDER  BY T.objid, 
            C.colid 
  FOR READ only 

SELECT @LFCR = 2 

SELECT @LineId = 1 

OPEN ms_crs_syscom 

SET @OldTrigID = -1 

FETCH next FROM ms_crs_syscom INTO @ObjID, @SyscomText 

WHILE @@fetch_status = 0 
  BEGIN 
      SELECT @BasePos = 1 

      SELECT @CurrentPos = 1 

      SELECT @TextLength = Len(@SyscomText) 

      IF @ObjID <> @OldTrigID 
        BEGIN 
            SET @LineID = 1 
            SET @OldTrigID = @ObjID 
        END 

      WHILE @CurrentPos != 0 
        BEGIN 
            --Looking for end of line followed by carriage return         
            SELECT @CurrentPos = Charindex(Char(13) + Char(10), @SyscomText, 
                                 @BasePos) 

            --If carriage return found         
            IF @CurrentPos != 0 
              BEGIN 

                  WHILE ( Isnull(Len(@Line), 0) + @BlankSpaceAdded 
                          + @CurrentPos - @BasePos + @LFCR ) > 
                        @DefinedLength 
                    BEGIN 
                        SELECT @AddOnLen = @DefinedLength - ( 
                                           Isnull(Len(@Line), 
                                           0 
                                           ) + 
                                           @BlankSpaceAdded ) 

                        INSERT @TrigText 
                        VALUES ( @ObjID, 
                                 @LineId, 
                                 Isnull(@Line, N'') 
                                 + Isnull(Substring(@SyscomText, @BasePos, 
                                 @AddOnLen), 
                                 N'')) 

                        SELECT @Line = NULL, 
                               @LineId = @LineId + 1, 
                               @BasePos = @BasePos + @AddOnLen, 
                               @BlankSpaceAdded = 0 
                    END 

                  SELECT @Line = Isnull(@Line, N'') 
                                 + Isnull(Substring(@SyscomText, @BasePos, 
                                 @CurrentPos 
                                 -@BasePos + 
                                 @LFCR), 
                                        N'') 

                  SELECT @BasePos = @CurrentPos + 2 

                  INSERT @TrigText 
                  VALUES( @ObjID, 
                          @LineId, 
                          @Line ) 

                  SELECT @LineId = @LineId + 1 

                  SELECT @Line = NULL 
              END 
            ELSE 
              --else carriage return not found         
              BEGIN 
                  IF @BasePos <= @TextLength 
                    BEGIN 
                        /*If new value for @Lines length will be > then the         
                        **defined length         
                        */ 
                        WHILE ( Isnull(Len(@Line), 0) + @BlankSpaceAdded 
                                + @TextLength - @BasePos + 1 ) > 
                              @DefinedLength 
                          BEGIN 
                              SELECT @AddOnLen = @DefinedLength - ( 
                                                 Isnull(Len(@Line), 
                                                 0 
                                                 ) + 
                                                 @BlankSpaceAdded ) 

                              INSERT @TrigText 
                              VALUES ( @ObjID, 
                                       @LineId, 
                                       Isnull(@Line, N'') 
                                       + Isnull(Substring(@SyscomText, 
                                       @BasePos, 
                                       @AddOnLen), 
                                       N'')) 

                              SELECT @Line = NULL, 
                                     @LineId = @LineId + 1, 
                                     @BasePos = @BasePos + @AddOnLen, 
                                     @BlankSpaceAdded = 0 
                          END 

                        SELECT @Line = Isnull(@Line, N'') 
                                       + Isnull(Substring(@SyscomText, 
                                       @BasePos, 
                                       @TextLength 
                                       -@BasePos+1 
                                       ), N'') 

                        IF Len(@Line) < @DefinedLength 
                           AND Charindex(' ', @SyscomText, @TextLength + 1) 
                               > 0 
                          BEGIN 
                              SELECT @Line = @Line + ' ', 
                                     @BlankSpaceAdded = 1 
                          END 
                    END 
              END 
        END 

      FETCH next FROM ms_crs_syscom INTO @ObjID, @SyscomText 
  END 

IF @Line IS NOT NULL 
  INSERT @TrigText 
  VALUES( @ObjID, 
          @LineId, 
          @Line ) 

CLOSE ms_crs_syscom 

PRINT '-- You should run this result under dbo if your triggers belong to multiple users' 

PRINT '' 

IF @InclDrop = 1 
  BEGIN 
      PRINT '-- Dropping the Triggers' 

      PRINT '' 

      SELECT 'If exists(Select * from sysObjects where id =Object_ID(''[' 
             + username + '].[' + trigname 
             + ']'') and ObjectProperty(Object_ID(''[' 
             + username + '].[' + trigname + ']''), ''ISTRIGGER'')=1)   Drop Trigger [' 
             + username + '].[' + trigname + '] ' + Char(13) 
             + Char(10) + 'GO' + Char(13) + Char(10) + Char(13) 
             + Char(10) 
      FROM   @Triggers 
  END 

PRINT '----------------------------------------------' 

PRINT '-- Creation of Triggers' 

PRINT '' 

PRINT '' 

DECLARE ms_users CURSOR local forward_only FOR 
  SELECT T.username, 
         T.objid, 
         Max(D.lineid) 
  FROM   @Triggers T, 
         @TrigText D 
  WHERE  T.objid = D.objid 
  GROUP  BY T.username, 
            T.objid 
  FOR READ only 

OPEN ms_users 

FETCH next FROM ms_users INTO @UserName, @ObjID, @MaxID 

WHILE @@fetch_status = 0 
  BEGIN 
      PRINT 'SetUser N''' + @UserName + '''' + Char(13) 
            + Char(10) 

      SELECT '-- Text of the Trigger'= CASE lineid 
                                         WHEN 1 THEN 'GO' + Char(13) + Char( 
                                                     10) 
                                                     + 
                                                     linetext 
                                         WHEN @MaxID THEN linetext + 'GO' 
                                         ELSE linetext 
                                       END 
      FROM   @TrigText 
      WHERE  objid = @ObjID 
      ORDER  BY lineid 

      PRINT 'Setuser' 

      FETCH next FROM ms_users INTO @UserName, @ObjID, @MaxID 
  END 

CLOSE ms_users 

PRINT 'GO' 

PRINT '------End ------' 

DEALLOCATE ms_crs_syscom 

DEALLOCATE ms_users 

SET nocount ON 

DECLARE @return_value INT 

如何执行:

EXEC @return_value = [dbo].[Createscriptofalltriggers] 
  @InclDrop = 1 

SELECT 'Return Value' = @return_value 

go 

【讨论】:

我很困惑这是对所提问题的回答?

以上是关于有没有办法在一个脚本中创建多个触发器?的主要内容,如果未能解决你的问题,请参考以下文章

在事件侦听器中创建数据库触发器

mysql在存储过程中创建触发器

有没有办法在 C++ 中创建一个循环数组

在 phpMyAdmin 中创建一个约束作为触发器

如何在插入时在 SQL Server 中创建触发器?

创建一个监听多个表的全局触发器