标签: trigger

删除“登录表”中的许多记录后,服务器登录触发器失败 -SQL 错误 2801

我们定义了一个服务器登录触发器,用于记录每次登录,并在表中记录诸如 windows/sql 用户名、客户端和时间等信息。

该表没有聚集索引,但它有一个“PK_ID”列,它是 bigint 和自动增量。

上周,我们从“登录表”中总共 9000 万条记录中删除了大约 8000 万条记录(带有delete from......,我们没有truncate该表)。

但从那以后我们看到登录触发器失败的多种情况

由于触发器执行,登录 'SQL\xy' 登录失败。
将数据库上下文更改为“master”。
(Microsoft SQL Server,错误:17892)

我们确实重新启动了整个 Windows 服务器几次,之后错误消失了几个小时,但似乎时不时地回来。请注意,这仅在我们删除了这么多记录后才开始出现。

我们发现在用户无法登录之前,我们收到以下错误:

消息 2801,级别 16,状态 1,: 
对象“my_proc”的定义自编译以来已更改。

之后,我们得到了如上所述的错误 17892。

有谁知道可能是什么问题?

触发器定义

    SET ANSI_NULLS ON

    GO

    SET QUOTED_IDENTIFIER ON

    GO

    CREATE TRIGGER [Tr_My_Logon]
     ON ALL SERVER  WITH EXECUTE AS 'xy'
     FOR LOGON
     AS
     BEGIN
        BEGIN TRY
            INSERT INTO mydatabase.myschema.myLogonHistoryTable
                SELECT GETDATE(),
                      ORIGINAL_LOGIN(),
                      EVENTDATA().value('(/EVENT_INSTANCE/LoginType)[1]', 'varchar(500)'),
                      @@SPID,
                      program_name(),
                      HOST_NAME(),
                      EVENTDATA().value('(/EVENT_INSTANCE/ClientHost)[1]', 'varchar(500)')
       END TRY

       BEGIN CATCH
           PRINT ERROR_MESSAGE() …
Run Code Online (Sandbox Code Playgroud)

trigger sql-server-2008 sql-server

5
推荐指数
1
解决办法
614
查看次数

postgresql:从视图中删除

在 Postgresql 9.4 中,我们将视图作为表 A 和 B 的联合进行处理,并且当我们“删除”底层表中的记录时(通过 aa 触发器上的看法)。

这里有更详细的信息。我们的观点看起来像,

A
--
id, name
1, afoo
2, abar

B
--
id, name
3, bfoo
4, bbar
Run Code Online (Sandbox Code Playgroud)

所以我们的视图 C 看起来像

C
--
1, afoo
2, abar
3, bfoo
4, bbar
Run Code Online (Sandbox Code Playgroud)

我们做了一个CREATE TRIGGER delete_trigger INSTEAD OF DELETE C FOR EACH ROW DO delete_trigger(),它通过 id 删除行,这基本上就像

-- our function trigger():
$$
delete from A where id=old.id;
GET DIAGNOSTICS deletedA = ROW_COUNT;

delete from B where id=old.id;
GET DIAGNOSTICS deletedB = …
Run Code Online (Sandbox Code Playgroud)

postgresql trigger view postgresql-9.4

5
推荐指数
1
解决办法
2351
查看次数

防止显式插入串行列

我想防止显式插入串行列。我想到了以下触发器:

drop table test_table;

create table test_table(
id bigserial primary key,
foobar text
);

create or replace function serial_id_check() returns trigger as
$$
begin
    if new.id != currval(TG_TABLE_NAME||'_id_seq') then
        raise exception 'Explicit insert into serial id, currval = %, tried to insert = %', currval(TG_TABLE_NAME||'_id_seq'), new.id;
    end if;
    return new;
end;
$$ language plpgsql;

create trigger test_table_serial_id_check
before insert on test_table
for each row
execute procedure serial_id_check();
Run Code Online (Sandbox Code Playgroud)

也许有更好的方法?也许这种方法被打破了,这根本无法实现?

PS 我也考虑不授予插入和更新的权限,而只授予 pgplsql 插入/更新程序的权限 - 但这种方法现在对我来说是不可能的。

postgresql trigger database-design permissions sequence

5
推荐指数
2
解决办法
4293
查看次数

触发数据库创建或附加操作

在我们的开发环境中,我们需要在创建或附加某些数据库时运行一系列操作。诸如清理一些表、重新播种其他表、更改电子邮件等操作。我试图使用 DDL 触发器,实际上在这里发现一个与我类似的问题。从该代码开始,我正在尝试稍微不同的操作,但甚至无法开始。

以下代码取自我提到的问题,我只是添加了一个条件来检查数据库名称,如果对应于我需要的名称,则执行一些操作。问题是没有在 IF BEGIN..END 中运行 SET 语句。最后一个 SELECT 使用fn_listextendedproperty不返回任何数据。

IF EXISTS (SELECT NULL FROM sys.server_triggers WHERE name = 'ddl_trig_database')
BEGIN
    DROP TRIGGER ddl_trig_database
    ON ALL SERVER;
END
GO

CREATE TRIGGER ddl_trig_database 
ON ALL SERVER 
FOR CREATE_DATABASE 
AS 
    DECLARE 
        @DatabaseName NVARCHAR(128)
        , @CreatedBy NVARCHAR(128)
        , @CreatedDate NVARCHAR(23)
        , @SQL NVARCHAR(4000);

    SELECT  @DatabaseName = EVENTDATA().value('(/EVENT_INSTANCE/DatabaseName)[1]','NVARCHAR(128)');

    IF @DatabaseName = N'asd'
    BEGIN
        SET @SQL = '
            USE ' + @DatabaseName + ';
            EXEC sys.sp_addextendedproperty @name = …
Run Code Online (Sandbox Code Playgroud)

trigger sql-server ddl sql-server-2014

5
推荐指数
1
解决办法
3934
查看次数

InnoDB 复合键上的 AUTO_INCREMENT 技巧

与 MySQL MyISAM-Engine 相比,InnoDB-Engine 无法处理复合主键的一列声明为AUTO_INCREMENT. 例如,考虑下表:

CREATE TABLE `ExampleTable` (
     `KeyPartA` mediumint(8) unsigned NOT NULL,
     `KeyPartB` smallint(5) unsigned NOT NULL,
     `Data` text NOT NULL,
     PRIMARY KEY (`KeyPartA`,`KeyPartB`)
) ENGINE=InnoDB;
Run Code Online (Sandbox Code Playgroud)

现在模拟AUTO_INCREMENT,我了解到,可以创建以下触发器

DELIMITER $$

CREATE TRIGGER ExampleAutoIncrement BEFORE INSERT ON ExampleTable
FOR EACH ROW BEGIN
        SET NEW.KeyPartB = (
             SELECT IFNULL(MAX(KeyPartB), 0) + 1
             FROM ExampleTable
             WHERE KeyPartA  = NEW.KeyPartA
        );
END $$

DELIMITER ;
Run Code Online (Sandbox Code Playgroud)

现在插入工作正常,生成自动递增的值。不幸的是,我想不出一种明智的方法来获取新创建的键值。

由于LAST_INSERT_ID()没有实际的AUTO_INCREMENT列,因此它的 C 对应项都不会返回它。也不能LAST_INSERT_ID(IFNULL(MAX(KeyPartB), 0) + 1)在 …

mysql innodb trigger auto-increment

5
推荐指数
1
解决办法
7707
查看次数

触发以创建对称行

我有一个表格,描述了两个项目之间的某种关系。项由 引用ID。我想创建一个触发器,所以每当你创建一行时(a,b),就会创建一个对称的行(b,a)。我试过在触发器之后创建,但它超过了堆栈深度,因为它在插入时调用了它自己。什么是正确的方法呢?

表看起来有点像这样:

CREATE TABLE MY_RELATION(
ID SERIAL,
THING1 INT NOT NULL,
THING2 INT NOT NULL,
PRIMARY KEY (ID)
);

CREATE TABLE MY_THING(
ID SERIAL,
VAL INT NOT NULL
PRIMARY KEY(ID)
);
ALTER TABLE MY_RELATION ADD FOREIGN KEY (THING1) REFERENCES MY_THING(ID);
ALTER TABLE MY_RELATION ADD FOREIGN KEY (THING2) REFERENCES MY_THING(ID);
Run Code Online (Sandbox Code Playgroud)

postgresql trigger database-design

5
推荐指数
1
解决办法
408
查看次数

SQL Server 中有没有办法使表只能通过触发器插入?

标题是不言自明的,但如果您对我为什么想要这个感到好奇;我想要这个是因为我有一个存档/日志表来存储活动表的过去值,因此我不希望数据有以任何方式受到损害的风险。唯一应该在表上插入的是我在活动表上创建的触发器以记录其更改。在极少数情况下,我们可能需要手动编辑日志表,我将关闭(如果存在)“插入锁”

我将 SQL Server 2012 Enterprise 与 SQL Management Studio 结合使用

trigger sql-server permissions sql-server-2012

5
推荐指数
2
解决办法
2287
查看次数

分配具有动态列名的列

我得到了要在 ( BEFORE UPDATE) 触发器中设置的列的名称,我想将其设置为该OLD值并忽略传入的任何内容。我尝试了以下操作:

CREATE OR REPLACE FUNCTION prevent_column_update() RETURNS TRIGGER AS $$
  DECLARE
    col TEXT := TG_ARGV[0];
  BEGIN
    EXECUTE format('SELECT ($1).%I INTO ($2).%I', col, col) USING OLD, NEW;
    RETURN NEW;
  END;
  $$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

并使用如下:

CREATE TRIGGER request_protect_date_price_value
  BEFORE UPDATE OF date_price ON requests
  FOR EACH ROW EXECUTE PROCEDURE prevent_column_update('date_price');
Run Code Online (Sandbox Code Playgroud)

但是当更新它失败时:

ERROR:  syntax error at or near "("
LINE 1: SELECT ($1).date_price INTO ($2).date_price
                                    ^
QUERY:  SELECT ($1).date_price INTO ($2).date_price
Run Code Online (Sandbox Code Playgroud)

postgresql trigger dynamic-sql plpgsql postgresql-9.5

5
推荐指数
1
解决办法
6392
查看次数

检查可空数据的约束,如何处理?

这是我数据库中的表之一。为清楚起见,省略了约束。

CREATE TABLE [Person].[Person]
(
    [ID]                     INT           NOT NULL IDENTITY,       
    [Forename]               VARCHAR(16)   NOT NULL,
    [Surname]                VARCHAR(32)   NOT NULL,
    [Gender]                 CHAR(1)       NOT NULL DEFAULT 'U',
    [DateOfBirth]            DATETIME      NULL,
    [HobbiesAndInterests]    VARCHAR(256)  NULL,
    [AdditionalInformation]  VARCHAR(512)  NULL,
    [LocalCentreID]          INT           NOT NULL DEFAULT 0,
    [EmergencyContactID]     INT           NULL, 
)
Run Code Online (Sandbox Code Playgroud)

我的问题涉及出生日期字段。如果提供了值,我需要对日期进行检查。如果未提供值,则无需运行检查。

我基本上需要根据出生日期检查这个人是否年满 18 岁。如果未提供出生日期,则无需对其进行检查。

我想了几种不同的方法来解决这个问题:

第一个显然是在出生日期字段上设置检查约束,但我认为如果日期为空,这将失败。

另一种选择是在检查约束内使用标量 UDF。

我想到的最后一个选项是使用 AFTER INSERT/UPDATE 触发器来检查日期并在日期无效时回滚。

我和一位同事谈过,他说从技术上讲,我正在检查数据库中的业务规则,因此应该将这项检查推送到应用程序。

是否有“正确”的方法来解决这个问题,或者基本上是开发人员认为最好的方法?

trigger null sql-server check-constraints

5
推荐指数
1
解决办法
4843
查看次数

在 SQL Server 中更改禁用的触发器而不启用它

似乎触发器在更改后会自动启用。如何以编程方式更改触发器而不更改其启用/禁用状态?

重现代码:

create trigger trig
on MyTable
after insert
as select 0

go

disable trigger trig on MyTable

go

select is_disabled from sys.triggers where name = 'trig'

go

alter trigger trig
on MyTable
after insert
as select 1

go

select is_disabled from sys.triggers where name = 'trig'
Run Code Online (Sandbox Code Playgroud)

trigger sql-server

5
推荐指数
1
解决办法
734
查看次数