我们定义了一个服务器登录触发器,用于记录每次登录,并在表中记录诸如 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) 在 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) 我想防止显式插入串行列。我想到了以下触发器:
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 插入/更新程序的权限 - 但这种方法现在对我来说是不可能的。
在我们的开发环境中,我们需要在创建或附加某些数据库时运行一系列操作。诸如清理一些表、重新播种其他表、更改电子邮件等操作。我试图使用 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) 与 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)在 …
我有一个表格,描述了两个项目之间的某种关系。项由 引用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) 标题是不言自明的,但如果您对我为什么想要这个感到好奇;我想要这个是因为我有一个存档/日志表来存储活动表的过去值,因此我不希望数据有以任何方式受到损害的风险。唯一应该在表上插入的是我在活动表上创建的触发器以记录其更改。在极少数情况下,我们可能需要手动编辑日志表,我将关闭(如果存在)“插入锁”
我将 SQL Server 2012 Enterprise 与 SQL Management Studio 结合使用
我得到了要在 ( 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) 这是我数据库中的表之一。为清楚起见,省略了约束。
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 触发器来检查日期并在日期无效时回滚。
我和一位同事谈过,他说从技术上讲,我正在检查数据库中的业务规则,因此应该将这项检查推送到应用程序。
是否有“正确”的方法来解决这个问题,或者基本上是开发人员认为最好的方法?
似乎触发器在更改后会自动启用。如何以编程方式更改触发器而不更改其启用/禁用状态?
重现代码:
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 ×10
sql-server ×5
postgresql ×4
permissions ×2
ddl ×1
dynamic-sql ×1
innodb ×1
mysql ×1
null ×1
plpgsql ×1
sequence ×1
view ×1