如何在 SQL 服务器事务中执行这三件事 - 1. 在 table 上创建 table、2.create 触发器,3. 从另一个 [=13] select =]

How to do these three things in a SQL Server transaction - 1. create table, 2.create trigger on table, 3. select from another table

我正在尝试将以下 3 个简单任务作为事务完成(即我需要锁定 old_table 和 new_table 直到过程完成)。

  1. 新建 table (new_table)
  2. 向 old_table 添加触发器,将更新排队到 new_table。
  3. Select 来自 old_table 和 return 的所有数据。

请注意,我希望在单个事务中处理这些。我不允许在触发器创建和 old_table 上的 select 之间插入 old_table(因此触发插入 new_table)。

我目前最接近的尝试是这个,但说实话我觉得我离用这个代码实现我的目标还很远。我添加代码只是为了参考我正在尝试的内容,但我最感兴趣的是非特定答案,这些答案布局了如何在事务中完成上述三个命令。

DROP PROCEDURE IF EXISTS dbo.BuildAll;

CREATE PROCEDURE dbo.BuildAll
AS
BEGIN
    BEGIN TRANSACTION
    DECLARE @TriggerCode VARCHAR(MAX)
   
    CREATE TABLE dbo.new_table
    (
        status nvarchar(5),
        type   char(1),
        col1   nvarchar(50),
        col2   smallint
    )

    SELECT @TriggerCode = 'CREATE TRIGGER myTrigger
                           ON dbo.old_table FOR INSERT  
                           AS
                              DECLARE @col1_new nvarchar(50)
                              DECLARE @col2_new  smallint 
    
                              SELECT @col1_new = col1 FROM inserted
                              SELECT @col2_new = col2 FROM inserted
        
                              IF @col1_new IS NOT NULL
                              BEGIN
                                  INSERT INTO new_table (status, type, col1, col2)
                                  SELECt "Q", "A", @col1, @col2 FROM inserted
                              END'
       
    EXEC(@TriggerCode)
  
    SELECT * FROM old_table

    COMMIT
END

你的这个触发器代码有点奇怪....你对所有三个操作都有触发器 - 但看起来好像你从未使用过从 deleted 伪 table,并且如果 inserted table 的值是 NULL,则您没有在触发器内执行任何操作 - 因此您可以真正避免 DELETE 的情况- 那永远不会做任何事情....

此外,正如我在评论中提到的 - 你 Inserted 伪 table 可以轻松包含 多行 - 但你是 select从中读取它,就好像您只希望它包含一行。

你应该真的重写你的触发器代码来处理Inserted中多行的情况,并使整个事情正确地基于设置 - 像这样:

CREATE TRIGGER myTrigger
ON dbo.old_table 
FOR INSERT, UPDATE
AS
    INSERT INTO new_table (status, type, col1, col2)
        SELECT 'Q', 'A', i.col1, i.col2
        FROM Inserted i

UPDATE 案例中您是否需要这个 - 我不知道,您需要决定这个。但基本上:只是 Inserted table 中的 select,取 Col1Col2 值,并添加常量值 'Q''A' 到您的插入以正确处理多行。应该这样做。

将建议这是一个您可以尝试的可能的解决方案。这并没有解决您实际触发器的正确​​性,您真的有两个不同的问题。

您不需要将整个过程封装在事务中。

  • 创建新的 table。

  • 在旧 table 上创建触发器,但已禁用。

set transaction isolation level serializable
begin tran
go
create trigger <Name> on <Table> etc
go
disable trigger <Name> on <Table>
go
commit
  • 现在在交易中,您可以在工作时将旧 table 与其他 activity 锁定

begin tran

update oldtable with(tablockx) set column=column where id=0 /* block other processes from updating table, id=0 row doesn't exist */

query your data and process as required

enable trigger <Name> on <Table>

commit