【问题标题】:sp_rename failing when called from inside another stored procedure从另一个存储过程内部调用 sp_rename 失败
【发布时间】:2018-01-31 22:40:04
【问题描述】:

来自自学成才的数据仓库人员的第一篇文章。我做了大量的搜索和阅读以了解我现在的位置,但无法超越这个症结所在。

背景:作为我们夜间 ETL 工作的一部分,我们必须将许多表从许多远程 DB(链接服务器)复制到暂存区 DB。表副本完成后,我继续将暂存区 DB 转换为生产表。

由于远程数据库都具有相同的架构,我在生产数据库中创建了一个存储过程来完成这项工作。存储过程接受远程数据库名称和表名称的参数。在夜间作业中,SQL Server Agent 运行一个 SSIS 包;该包包含每个远程数据库的一个(重试循环)SSIS 任务;所有任务同时运行;每个任务使用一个变量将数据库名称传递给 SQL 文件;然后 SQL 文件为每个表调用一次存储过程。

远程表和本地暂存区表示例:

远程:[FLTA].[cstone].[csdbo].[CLIENT]
本地:[FLTAL].dbo.[FLTA CLIENT]

存储过程非常简单,删除旧表并使用 SELECT 从远程数据库创建新副本。大概是这样的:

CREATE PROCEDURE dbo.spTableCopyNew 
     (@p VARCHAR(50), @Tablename VARCHAR(50))
AS

-- Drop the existing table
EXEC('IF OBJECT_ID(''[' + @p + 'L].dbo.[' + @p + ' ' + @Tablename +']'', ''U'') IS NOT NULL
    DROP TABLE [' + @p + 'L].dbo.[' + @p + ' ' + @Tablename +']'
)

-- Copy the new table
EXEC('SELECT * into [' + @p + 'L].dbo.[' + @p + ' ' + @Tablename +']
    FROM [' + @p + '].[cstone].[csdbo].[' + @Tablename +']'
)
GO

SQL 大致如下:

-- Set local variables for the remote server connection, the local database name, and the table prefix
DECLARE @Prefix varchar(50)

-- Accept the variables passed in from the SSIS task
SET @Prefix = ?

-- Copy the two tables
EXEC Datawarehouse.dbo.spTableCopy @Prefix, 'CLIENT'
EXEC Datawarehouse.dbo.spTableCopy @Prefix, 'PATIENT'

维护轻而易举:当我们需要从所有远程数据库中获取新表时,我只需将其添加到“productionLoad.sql”文件中即可。

效果真的很好......除非它不起作用。

由于未知的原因,有时无法复制表。而且由于我在复制新表之前删除了现有表,因此有时这会进一步破坏事情的发展。我的 SSIS 任务将在每个远程 DB 上重试多达 3 次,因此偶尔的失败没什么大不了的。但是如果同一个远程数据库在一个晚上出现三个故障,我会很糟糕的。

我当前的解决方案尝试是将远程表复制到临时表,然后仅在复制成功后,删除本地表并将临时表重命名为“真实”表。这让我想到了这个问题:

当从存储过程调用时,我无法让sp_rename 工作,以重命名存在于与存储过程不同的数据库中的表。我创建了新变量来解析表达式,然后将这些变量发送到sp_rename,因为我无法将表达式传递到该存储过程中。

这是我对新存储过程的尝试:

CREATE PROCEDURE dbo.spTableCopy 
     (@p VARCHAR(50), @Tablename VARCHAR(50))
AS
BEGIN

EXEC('USE [' + @p + 'L]')

-- Create variables for schema and table names
-- Since sp_rename can accept variables, but not expresssions containing variables.
DECLARE @RemoteTable VARCHAR(50) = '[' + @p + '].[cstone].[csdbo].[' + @Tablename +']'
DECLARE @LocalTableTemp VARCHAR(50) = '[' + @p + 'L].dbo.[' + @p + ' ' + @Tablename +'_temp]'
DECLARE @LocalTable VARCHAR(50) = '' + @p + ' ' + @Tablename + ''

-- Check for previous temp table and drop it
EXEC('IF OBJECT_ID(''[' + @p + 'L].dbo.[' + @p + ' ' + @Tablename +'_temp]'', ''U'') IS NOT NULL
    DROP TABLE [' + @p + 'L].dbo.[' + @p + ' ' + @Tablename +'_temp]'
)

-- Copy the new table
EXEC('SELECT * into ' + @LocalTableTemp + '
    FROM ' + @RemoteTable + ''
)

-- Drop the existing table
EXEC('IF OBJECT_ID(''[' + @p + 'L].dbo.[' + @p + ' ' + @Tablename +']'', ''U'') IS NOT NULL
    DROP TABLE [' + @p + 'L].dbo.[' + @p + ' ' + @Tablename +']'
)

-- Rename temp table to real table
EXEC sp_rename @LocalTableTemp, @LocalTable

END
GO

当它作为普通 SQL 代码执行时,这一切都有效,但是当我将它变成存储过程时,sp_rename 失败(其他一切都有效)。最终表格 [FLTAL CLIENT_temp] 在那里,包含正确的数据。

sp_rename 返回以下错误:

消息 290,级别 16,状态 2,过程 sp_rename,第 318 行
使用对象“Object”、方法“LockMatchID”的 EXECUTE 语句无效。

我已经用这种方式战斗了太久了。

我只是搞砸了语法吗?

我可以让sp_rename 使用“USE”在其他数据库上工作吗?

如果没有,如果我在每个暂存区域数据库中复制我的sp_tableCopy 是否有效?

如果不是,即使我同时多次调用此存储过程,catch-try 是否会在此存储过程中工作?

我还能做些什么来从失败的表副本中恢复?

我尚未采用的替代解决方案:成功创建临时表后,TRUNC 现有表并将临时表中的所有内容插入到真实表中。不过这看起来很乱。

附:我们的 IT 人员正在“调查”复制失败的性质。

【问题讨论】:

  • Can I get sp_rename to work on other DBs with "USE?" 不是您当前的方式(因为在 EXEC('USE...') 部分之后,您只需返回默认数据库。EXEC 部分仅适用于括号),但你可以做类似exec somedb.dbo.sp_rename的东西。
  • 如果您将 spTableCopy 放入目标数据库,您的生活会轻松很多。
  • 关于您在这里进行的大量转义,QUOTENAMEFORMATMESSAGE 会让您(以及您未来的维护者)的生活更加愉快。 SQL Server 2012 之前的版本,在此类字符串上使用 REPLACE 仍然比串联更容易阅读。

标签: sql-server tsql stored-procedures


【解决方案1】:

试试这个...

使用 EXEC ..sp_rename '..', ''

【讨论】:

  • 嗨,布伦达...只需一个答案即可。你能删除这个(或你想保留的那个)吗?
  • 您好,欢迎来到 Stack Overflow!请拨打tour。感谢您的回答,但您是否还可以添加有关您的代码如何解决问题的解释?查看help center 了解如何格式化代码。
【解决方案2】:
USE sourcedb
EXEC targetdatabase..sp_rename 'schema.oldtable', 'target_table'

【讨论】:

  • 请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助,质量更高,更有可能吸引投票。
猜你喜欢
  • 2014-09-17
  • 1970-01-01
  • 1970-01-01
  • 2011-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多