【问题标题】:How to store the results of a stored procedure without requiring a distributed transaction?如何在不需要分布式事务的情况下存储存储过程的结果?
【发布时间】:2017-05-23 14:53:33
【问题描述】:

我有一个正在运行的远程存储过程:

EXECUTE Contoso.Frob.dbo.Grobber @StartDate='20140513', @EndDate='20140518'

这个远程存储过程返回一个行集:

EmployeeID  EmployeeName    StartDateTime            EndDateTime
----------  --------------  -------------            -----------------------
619         Guyer, Kirsten  2014-05-13 19:00:00.000  2014-05-13 19:00:00.000
...

非常好。完美的。好的。甜蜜。

现在我有了这些结果,我需要将它们存储在一个表中。任何类型的桌子。我不在乎什么样的桌子:

  • 物理表
  • 临时表
  • 全局临时表
  • 表变量

我只需要存储它们以便我可以处理它们。问题是当我尝试将结果插入表格时,是否是:

  • 物理表

    INSERT INTO EmployeeSchedule
    EXECUTE Contoso.Frob.dbo.Grobber @StartDate='20140513', @EndDate='20140518'
    
  • 临时表

    INSERT INTO #EmployeeSchedule
    EXECUTE Contoso.Frob.dbo.Grobber @StartDate='20140513', @EndDate='20140518'
    
  • 全局临时表

    INSERT INTO ##EmployeeSchedule
    EXECUTE Contoso.Frob.dbo.Grobber @StartDate='20140513', @EndDate='20140518'
    
  • 一个表变量

    INSERT INTO @EmployeeSchedule
    EXECUTE Contoso.Frob.dbo.Grobber @StartDate='20140513', @EndDate='20140518'
    

SQL Server 坚持(不,要求)它开始一个分布式事务

链接服务器“Contoso”的 OLE DB 提供程序“SQLNCLI10”返回消息“合作伙伴事务管理器已禁用其对远程/网络事务的支持。”。
消息 7391,第 16 层,状态 2,第 41 行
无法执行该操作,因为链接服务器“Contoso”的 OLE DB 提供程序“SQLNCLI10”无法开始分布式事务。

为什么不...

现在,不能对Contoso 服务器进行更改。为什么?没关系。假设 Jack Bauer 会出现,而任何试图修改 Contoso 的人都会出现在关塔那摩。这意味着我无法在\\Contoso 上启用或重新配置 MSDTC。

您是否尝试过使用READ UNCOMMITTED

是的。

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
INSERT INTO @EmployeeSchedule 
EXECUTE wclnightdb.NGDemo.dbo.tbtGetSchedule @StartDate, @EndDate 

合作伙伴事务管理器已禁用对远程/网络事务的支持。

还有:

INSERT INTO #EmployeeSchedule 
WITH (NOLOCK)
EXECUTE wclnightdb.NGDemo.dbo.tbtGetSchedule @StartDate, @EndDate 

对不起。没有锁。 Nolock 是不可以的:

消息 1065,第 15 级,状态 1,第 15 行
对于 INSERT、UPDATE、DELETE 或 MERGE 语句的目标表,不允许使用 NOLOCK 和 READUNCOMMITTED 锁提示。

我总是可以放弃 SQL Server

如果我在编程环境中执行此操作,修复将相当容易:

using (IDataReader rdr = ADOHelper.Execute(conn, "EXECUTE Contoso.Frob.dbo.Grobber @StartDate='20140513', @EndDate='20140518'")
{
   while (rdr.Read())
   {
       InsertRowIntoTable(conn, rdr);
   }
}

虽然这需要我创建一个二进制文件、发布它并安排它。我正在寻找适用于 SQL Server 的选项(以便 SQL 代理可以安排作业)。

阅读奖励

【问题讨论】:

  • 您不能更改过程并让它返回 TABLE 类型的输出变量?
  • 在 SQL SERVER 中使用 C#,启用 .Net 框架。
  • 如何在 SQL Server 中创建一个调用存储过程的函数?
  • 一个格式很好的问题,抱歉我帮不上忙。
  • @TMcKeown 只要您确保从不按行调用它们,它们就会很有用;确保它们在 T-SQL 语句中只被调用一次。

标签: sql-server sql-server-2008-r2


【解决方案1】:

SQL Server 坚持(不,要求)它开始一个分布式 交易:

如果您出于某种原因无法将服务器配置为使用分布式事务,您可以告诉它不要这样做。

USE [master]
GO

EXEC master.dbo.sp_serveroption 
    @server   = N'Contoso', 
    @optname  = N'remote proc transaction promotion', 
    @optvalue = N'false'
GO

或者在 SSMS GUI 中:

我不知道关闭此选项的所有含义,但至少现在我的INSERT ... EXEC [LinkedServer]... 有效。

【讨论】:

    【解决方案2】:

    有两种选择:

    1. 由于您已经设置了链接服务器,请将其与 OPENQUERY 一起使用,如:
      SELECT column1, column2 FROM OPENQUERY(Contoso, 'EXECUTE Frob.dbo.Grobber @StartDate=''20140513'', @EndDate=''20140518''')

    2. 如果返回的列保持一致,则创建 SQLCLR 表值函数。这假定远程 proc 是只读的(即 SELECT-only)。但与 T-SQL 函数不同的是,SQLCLR 函数可以使用连接字符串“Context Connection = True;”执行存储过程。只要存储过程是 SELECT-only(即不通过 DML、DDL 等更改 DB 的状态)。

    【讨论】:

      【解决方案3】:

      这个怎么样:

      -- 要么创建一个通过 SQLSMD 命令运行远程 sql 的作业,要么只运行如下内容: EXEC master..xp_cmdshell 'SQLCMD -S Server\SQLSERVERDEV2005 -i"c:\DML.sql"' (作业可能更容易,因为您可以通过 sp_update_jobstep 轻松修改作业步骤,以便为您的参数获取正确的值)

      -- 将sqlcmd的结果输出到文件中

      -- 通过批量导入将文件加载到表中。

      【讨论】:

        猜你喜欢
        • 2016-06-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-02
        • 2019-07-06
        • 1970-01-01
        • 2010-10-20
        • 1970-01-01
        相关资源
        最近更新 更多