如何在 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 直到过程完成)。
- 新建 table (new_table)
- 向 old_table 添加触发器,将更新排队到 new_table。
- 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,取 Col1
和 Col2
值,并添加常量值 '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
我正在尝试将以下 3 个简单任务作为事务完成(即我需要锁定 old_table 和 new_table 直到过程完成)。
- 新建 table (new_table)
- 向 old_table 添加触发器,将更新排队到 new_table。
- 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,取 Col1
和 Col2
值,并添加常量值 '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