[英]MSSQL merge with distributed transaction alternative
I have a distributed transaction where I need to merge into the target remote table. 我有一个分布式事务,需要合并到目标远程表中。 Now MERGE INTO isn't allowed according to MSDN: “target_table cannot be a remote table”. 根据MSDN,现在不允许MERGE INTO:“ target_table不能是远程表”。
So my workaround goes as follows: 0. begin distributed transaction 1. define a cursor 2. open it 3. if cursor has at least one record (CURSOR_STATUS()=1) fetch next 4. if exists (select top 1 * from target_remote_table where id = @myCurrentCursorId) -> when true update target_remote_table when false insert into target_remote_table 5. commit/rollback distributed transaction depending on trancount and xact_state 因此,我的解决方法如下:0.开始分布式事务1.定义一个游标2.打开它3.如果游标具有至少一条记录(CURSOR_STATUS()= 1),则取下一条4.如果存在(从target_remote_table中选择top 1 *其中id = @myCurrentCursorId)->当为true时更新target_remote_table,如果为false则将target_remote_table插入5.提交/回滚分布式事务,具体取决于转帐和xact_state
It works but I know that cursors are evil and you shouldn't use them. 它有效,但是我知道游标是邪恶的,您不应使用它们。 So I want to ask if there is any other way I could solve this by not using cursors? 所以我想问一下是否还有其他方法可以通过不使用游标来解决此问题?
USE [My_DB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[my_proc_merge_into_remote_table]
@ID_A INT,
@ID_B INT
AS
BEGIN
SET NOCOUNT ON;
-- CURSOR VALUES
DECLARE @field_A INT
DECLARE @field_B INT
DECLARE @field_C INT
DECLARE @field_D BIT
DECLARE @field_E INT
DECLARE @field_F DATETIME
DECLARE @field_G VARCHAR(20)
DECLARE @field_H DATETIME
DECLARE @field_I VARCHAR(20)
BEGIN TRY
BEGIN DISTRIBUTED TRANSACTION
-- CURSOR !!
DECLARE my_cursor CURSOR FOR
SELECT b.field_A ,
b.field_B,
c.field_C,
a.field_D,
a.field_E,
GETDATE() AS field_F,
a.field_G,
GETDATE() AS field_H,
a.field_I
FROM dbo.source_tbl a
LEFT JOIN dbo.base_element_tbl l
ON a.obj_id = l.obj_id AND a.element_id = l.element_id
INNER JOIN dbo.base_obj_tbl b
ON a.obj_id = b.obj_id
INNER JOIN dbo.element_tbl c
ON a.element_id = c.element_id
WHERE a.ID_B = @ID_B
AND a.ID_A = @ID_A;
OPEN my_cursor;
-- check if cursor result set has at least one row
IF CURSOR_STATUS('global', 'my_cursor') = 1 BEGIN
FETCH NEXT FROM my_cursor
INTO @field_A,
@field_B,
@field_C,
@field_D,
@field_E,
@field_F,
@field_G,
@field_H,
@field_I;
WHILE @@FETCH_STATUS = 0 BEGIN
-- HINT: MY_REMOTE_TARGET_TABLE is a Synonym which already points to the correct database and table
IF EXISTS(SELECT TOP 1 * FROM MY_REMOTE_TARGET_TABLE WHERE field_A = @field_A AND field_B = @field_B AND field_C = @field_C AND field_E = @field_E)
UPDATE MY_REMOTE_TARGET_TABLE SET field_D = @field_D, field_H = @field_H, field_I = @field_I;
ELSE
INSERT INTO MY_REMOTE_TARGET_TABLE (field_A, field_B, field_C, field_D, field_E, field_F, field_G, field_H, field_I) VALUES (@field_A, @field_B, @field_C, @field_D, @field_E, @field_F, @field_G, @field_H, @field_I);
FETCH NEXT FROM my_cursor
INTO @field_A,
@field_B,
@field_C,
@field_D,
@field_E,
@field_F,
@field_G,
@field_H,
@field_I;
END;
END;
CLOSE my_cursor;
DEALLOCATE my_cursor;
IF (@@TRANCOUNT > 0 AND XACT_STATE() = 1)
BEGIN
COMMIT TRANSACTION
END
END TRY
BEGIN CATCH
IF (@@TRANCOUNT > 0 AND XACT_STATE() = -1)
ROLLBACK TRANSACTION
END CATCH;
END
Here you go, first inner join target and source to update, then left join to insert missing. 到这里,首先是内部联接目标和源进行更新,然后是左联接以插入缺失项。
;WITH CTE_Source AS
(
SELECT b.field_A ,
b.field_B,
c.field_C,
a.field_D,
a.field_E,
GETDATE() AS field_F,
a.field_G,
GETDATE() AS field_H,
a.field_I
FROM dbo.source_tbl a
LEFT JOIN dbo.base_element_tbl l
ON a.obj_id = l.obj_id AND a.element_id = l.element_id
INNER JOIN dbo.base_obj_tbl b
ON a.obj_id = b.obj_id
INNER JOIN dbo.element_tbl c
ON a.element_id = c.element_id
WHERE a.ID_B = @ID_B
AND a.ID_A = @ID_A;
)
UPDATE trgt
SET trgt.field_D = src.field_D, trgt.field_H = src.field_H, trgt.field_I = src.field_I
FROM MY_REMOTE_TARGET_TABLE trgt
INNER JOIN CTE_Source src ON src.field_A = trgt.field_A AND src.field_B = trgt.field_B AND src.field_C = trgt.field_C AND src.field_E = trgt.field_E
;WITH CTE_Source AS
(
SELECT b.field_A ,
b.field_B,
c.field_C,
a.field_D,
a.field_E,
GETDATE() AS field_F,
a.field_G,
GETDATE() AS field_H,
a.field_I
FROM dbo.source_tbl a
LEFT JOIN dbo.base_element_tbl l
ON a.obj_id = l.obj_id AND a.element_id = l.element_id
INNER JOIN dbo.base_obj_tbl b
ON a.obj_id = b.obj_id
INNER JOIN dbo.element_tbl c
ON a.element_id = c.element_id
WHERE a.ID_B = @ID_B
AND a.ID_A = @ID_A;
)
INSERT INTO MY_REMOTE_TARGET_TABLE (field_A, field_B, field_C, field_D, field_E, field_F, field_G, field_H, field_I)
SELECT field_A, field_B, field_C, field_D, field_E, field_F, field_G, field_H, field_I
FROM CTE_Soure src
LEFT JOIN MY_REMOTE_TARGET_TABLE trgt ON src.field_A = trgt.field_A AND src.field_B = trgt.field_B AND src.field_C = trgt.field_C AND src.field_E = trgt.field_E
WHERE trgt.field_A IS NULL
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.