Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server SQL Server触发器的问题_Sql Server_Tsql_Triggers - Fatal编程技术网

Sql server SQL Server触发器的问题

Sql server SQL Server触发器的问题,sql-server,tsql,triggers,Sql Server,Tsql,Triggers,我创建了一个SQL Server触发器,如下所示 create trigger testtrigger on testdb for insert as declare @sql varchar(8000) SELECT @sql = 'bcp "select * from testdb" queryout c:/test.txt -c -t -T -S localhost' exec xp_cmdshell @sql go 但是,当在testdb中插入一行时,将创建文

我创建了一个SQL Server触发器,如下所示

create trigger testtrigger on testdb
for insert
as
declare @sql varchar(8000)

SELECT @sql = 'bcp "select * from testdb" queryout c:/test.txt -c -t -T -S localhost'

exec xp_cmdshell @sql

go

但是,当在testdb中插入一行时,将创建文本文件,但没有内容。有人能帮我解决这个问题吗。

尝试在插入后触发,然后从“插入的”psuedo表而不是实际的表“testdb”导出。将导出新插入的行

create trigger testtrigger on testdb
after insert
as
if exists (select * from inserted)
    begin
        declare @sql        varchar(8000),
                @guidName   char(36)=newid();
        
        SELECT @sql = concat('bcp "select * from inserted" queryout c:/',
                             @guidName, '.txt -c -t -T -S localhost');

        exec xp_cmdshell @sql
    end
go

除了关于不使用这种方法的建议之外,我想问你是否确定插入已经完成

最有可能的情况是您面临死锁,并且是一种SQL无法处理的死锁,因为所涉及的一个资源超出了SQL范围(命令行)

问题是,当您完成插入时,触发器会被激活,而不会释放在
testtrigger
中获取的独占锁。然后尝试select over
testtrigger
,但由于仍然存在锁,因此select需要等待这些锁被释放,这将永远不会发生,因为在等待select时您没有关闭事务

因此创建了文件,但由于死锁,插入和选择从未完成。 通过将命令添加到以下位置,您将看到它可以正常工作:

'bcp "select * from inserted with(nolock)" queryout c:/test.txt -c -t -T -S localhost'

当然,不建议使用整个方法,但我希望它能帮助您了解情况。

触发器应该非常小、快速和灵活-您绝对不应该从触发器调用外部服务,如
bcp
实用程序!您需要重新考虑您的设计,因此触发器应该处理在一条语句中插入的多行(是的,可能,请阅读sql语法)。@TomTom尽管存在其他问题,但此触发器确实支持多行插入。因此,您建议为每次插入将行导出到文本文件的解决方案是什么。这永远不会起作用。插入的表在触发器外部不可见。查询在触发器范围内执行。这当然有效。触发器内执行的动态SQL可以引用psuedo表。我可以给你举个例子,但你应该自己试试。它没有锁定命令。因此,当行满足某个条件时,您能否建议将行导出为文本文件的建议解决方案。@Subu,上面您写道:“……对于每个行插入,将行导出为文本的解决方案是什么?”代码已从引用“testdb”表切换到“inserted”表。“inserted”表只包含新插入的行,因此它应该满足要求。要进一步筛选要导出的行,可以向动态SQL添加连接条件或WHERE子句。”“插入”被称为“虚拟(或psuedo)表”,因为它不是永久分配的,并且只能在触发器的范围内访问。我创建了一个触发器,将所需的行移动到另一个表中,如下所示。在将INSERT作为INSERT插入testtable2后,在testtable1上使用test go alter trigger2,从插入的位置选择*FROM inserted where leaf='test22'go。现在,我如何将每一行导出到路径中的文本文件中。一旦插入新行,我就能够将它们导出到文本文件中。但是文本文件包含以前插入的所有行。我只需要插入的新行,每个文本文件只需要一行。我将尝试此命令。但是,对于每一行插入,将行导出为文本的解决方案是什么呢?谢谢,它与添加的nolock一起工作。那么,为了达到这一要求,您推荐什么样的解决方案呢?这取决于这样做的目的。如果只是为了跟踪更改而使用SQL 2016或更高版本,则可以启用时态表()。如果确实需要对文件进行导出,但可以按需运行(而不是在表获得新行时生成文件),则可以指定特定的日期/时间并在该时间具有表的精确快照。当满足特定条件时,我需要立即将行导出为文本文件。例如,当有人在特定的门上刷卡时,我需要导出该行。不需要所有的行。好的,但是该文件的用途是什么,用于审计,用于某人读取它,用于在文件出现时触发另一个进程?如果这是一个流量和数据量都很小的小型解决方案,我会继续使用这种方法。但是,如果您需要更健壮、更可扩展的东西,等等,我会:-实现ServiceBroker-使用插入后触发器只发送插入到ServiceBroker中队列的信息-使用CLR存储过程编写文件,只插入新数据