Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/75.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
MSSQL合并与分布式事务替代方案_Sql_Sql Server_Tsql - Fatal编程技术网

MSSQL合并与分布式事务替代方案

MSSQL合并与分布式事务替代方案,sql,sql-server,tsql,Sql,Sql Server,Tsql,我有一个分布式事务,需要合并到目标远程表中。 根据MSDN,现在不允许合并到:“目标_表不能是远程表” 因此,我的解决方法如下:0。开始分布式事务1。定义光标2。打开它3。如果游标至少有一条记录,则游标的状态为1,取下4。如果存在,请从target_remote_表中选择top 1*,其中id=@myCurrentCursorId->when true更新target_remote_表when false插入target_remote_表5。根据trancount和xact_状态提交/回滚分布式

我有一个分布式事务,需要合并到目标远程表中。 根据MSDN,现在不允许合并到:“目标_表不能是远程表”

因此,我的解决方法如下:0。开始分布式事务1。定义光标2。打开它3。如果游标至少有一条记录,则游标的状态为1,取下4。如果存在,请从target_remote_表中选择top 1*,其中id=@myCurrentCursorId->when true更新target_remote_表when false插入target_remote_表5。根据trancount和xact_状态提交/回滚分布式事务

它是有效的,但我知道游标是邪恶的,你不应该使用它们。所以我想问,是否有其他方法可以通过不使用游标来解决这个问题

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

在这里,首先是要更新的内部连接目标和源,然后是要插入缺少的左连接

;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 

合并的目标不能是远程表,但源可以是远程表。您可以从远程服务器运行查询。此外,可以使用“合并”写入的任何内容也可以使用“插入/更新/删除”组合重写。我将尝试从远程服务器内启动合并。也可以用INSERT/UPDATE/DELETE重写这正是我所做的,这只是你需要决定我们是否需要插入或更新的部分,这很棘手。到目前为止,我通过光标选择每条记录并逐个检查是否已经存在。我只是想知道是否有比在主机服务器上更好的解决方案。另外,游标解决方案非常慢,这也是另一个原因。如果不查看确切的查询,我无法确定,但您不需要逐行运行INSERT/UPDATE。您应该能够使用一条语句更新所有需要更新的行,然后使用另一条语句插入所有需要插入的行。目标上的内部连接用于更新,左侧连接+其中插入的NULL添加到了我目前为止的内容之上。我要怎么改变这个才能做到你说的?非常感谢!我真的被这件事缠住了。干杯