当前位置: 首页 > 面试题库 >

当目标数据库处于还原模式时(SQL准备),防止出现错误

后化
2023-03-14
问题内容

我有一个每晚运行的存储过程。它从链接的服务器中提取一些数据,并将其插入运行sql
agent作业的服务器上的表中。在运行INSERT语句之前,该过程将检查链接服务器上的数据库是否在线(STATE =
0)。如果不是,则不运行INSERT语句。

IF EXISTS(
SELECT *
FROM OPENQUERY(_LINKEDSERVER,'
SELECT name, state FROM sys.databases
WHERE name = ''_DATABASENAME'' AND state = 0')
)
BEGIN
INSERT INTO _LOCALTABLE (A, B)
SELECT A, B FROM _LINKEDSERVER._DATABASENAME.dbo._REMOTETABLE
END

但是,当远程数据库处于还原模式时,该过程将给出错误消息(延迟的准备工作无法完成)。这是因为BEGIN和END之间的语句是 运行整个脚本
之前 求值的。同样,如果IF评估不正确。并且因为_DATABASENAME处于还原模式,这已经给出了错误。

解决方法是将INSERT语句放在execute函数中:

EXECUTE('INSERT INTO _LOCALTABLE (A, B) 
SELECT A, B FROM _LINKEDSERVER._DATABASENAME.dbo._REMOTETABLE')

但是,在使用这部分sql之前,还有另一种更优雅的解决方案可以阻止对此语句的求值吗?

我的方案涉及一个链接服务器。当然,当数据库位于同一服务器上时,同样的问题也是。

我希望获得一些我尚不知道的命令,以防止IF内的评估语法:

IF(Evaluation)
BEGIN
    PREPARE THIS PART ONLY IF Evaluation IS TRUE.
END

编辑有关答案:

我测试了:

IF(EXISTS
(
SELECT *
FROM sys.master_files F WHERE F.name = 'Database'
AND state = 0
))
BEGIN
    SELECT * FROM Database.dbo.Table
END
ELSE
BEGIN
    SELECT 'ErrorMessage'
END

仍然会产生此错误:消息942,级别14,状态4,行8数据库’数据库’无法打开,因为它处于脱机状态。


问题答案:

我认为没有一种方法可以有条件地仅准备t-sql语句的一部分(至少不是您所询问的方式)。

原始查询的根本问题不是远程数据库有时处于脱机状态,而是远程数据库处于脱机状态时查询优化器无法创建执行计划。从这种意义上讲,离线数据库实际上就像语法错误一样,即,它是阻止创建查询计划的条件,因此整个事情在有机会执行之前就失败了。

之所以EXECUTE对您有用,是因为它推迟了传递给它的查询的编译,直到调用它的查询的运行时为止,这意味着您现在可能有两个查询计划,一个用于您的主查询,用于检查是否查看远程数据库。是可用的,并且只有在EXECUTE实际执行该语句之前,才会创建另一个。

因此,当您以这种方式考虑时,使用EXECUTE(或选择sp_executesql)并不是一种替代方法,它是一种可能的解决方案。这只是一种将查询分为两个单独的执行计划的机制。

考虑到这一点,您不一定必须使用动态SQL来解决您的问题。您可以使用第二个存储过程来达到相同的结果。例如:

-- create this sp (when the remote db is online, of course)
CREATE PROCEDURE usp_CopyRemoteData 
AS
BEGIN
  INSERT INTO _LOCALTABLE (A, B)
  SELECT A, B FROM _LINKEDSERVER._DATABASENAME.dbo._REMOTETABLE;
END
GO

然后,您的原始查询如下所示:

IF EXISTS(
  SELECT *
  FROM OPENQUERY(_LINKEDSERVER,'
  SELECT name, state FROM sys.databases
  WHERE name = ''_DATABASENAME'' AND state = 0')
  )
BEGIN
  exec usp_CopyRemoteData;
END

另一个解决方案是不用费心检查远程数据库是否可用,而只是尝试运行该INSERT INTO _LOCALTABLE语句,并在失败时忽略该错误。我在这里有点滑稽,但是除非您有一个ELSEfor IF EXISTS,即除非远程db脱机时您做一些不同的事情,否则您基本上只是抑制(或忽略)该错误。功能结果相同,因为没有数据被复制到本地表。

您可以在t-sql中使用try / catch进行操作,如下所示:

BEGIN TRY
  /* Same definition for this sp as above. */
  exec usp_CopyRemoteData;

  /* You need the sp; this won't work:
  INSERT INTO _LOCALTABLE (A, B)
  SELECT A, B FROM _LINKEDSERVER._DATABASENAME.dbo._REMOTETABLE
  */
END TRY
BEGIN CATCH
  /* Do nothing, i.e. suppress the error. 
    Or do something different?
  */
END CATCH

公平地说,这将抑制sp引发的所有错误,而不仅仅是远程数据库脱机引起的错误。而且您仍然具有与原始查询相同的根本问题,并且将需要存储的proc或动态SQL来正确捕获问题中的错误。BOL有一个很好的例子。有关详细信息,请参见此页的“不受TRY-
ATCH构造影响的错误”部分:http ://technet.microsoft.com/zh-
cn/library/ms175976(v=sql.105) .aspx

最重要的是,您需要将原始查询分为多个批次,并且有很多方法可以做到这一点。最佳解决方案取决于您的特定环境和要求,但是如果您的实际查询与本问题中提出的查询一样简单,那么您的原始解决方法可能就是一个好的解决方案。



 类似资料:
  • 本文向大家介绍SQL Server 2008 备份数据库、还原数据库的方法,包括了SQL Server 2008 备份数据库、还原数据库的方法的使用技巧和注意事项,需要的朋友参考一下 SQL Server 2008 备份数据库: 1.打开SQL , 找到要备份的数据库 , 右键 >> 任务 >>备份 2.弹出 [ 备份数据库对话框 ] ,如图: 3.点击添加 [ 按钮 ] . 如下图: 4.选择要

  • 问题内容: 我对MySQL非常陌生,并且正在Windows上运行它。我正在尝试从MySQL中的转储文件还原数据库,但是出现以下错误: 我尝试放入ini文件,但它仍然给出相同的错误。我该怎么办?请帮忙。 更新 正如Nick在评论中所建议的那样,我尝试了一下,但它给了我以下内容 这是一个500 Mb的转储文件,当我使用gVIM查看其内容时,我只能看到表达式和数据,这些表达式和数据是无法理解的。 问题答

  • 本文向大家介绍xtrabackup备份还原MySQL数据库,包括了xtrabackup备份还原MySQL数据库的使用技巧和注意事项,需要的朋友参考一下 mysqldump 备份鉴于其自身的某些特性(锁表,本质上备份出来insert脚本或者文本,不支持差异备份),不太适合对实时性要求比较高的情况 Xtrabackup可以解决mysqldump存在的上述的一些问题,生产环境应用的也会更多一些。 本文简

  • 我正在尝试备份/还原一个PostgreSQL数据库,正如Docker网站上解释的那样,但是数据没有还原。 数据库映像使用的卷为: CMD为: 然后创建tar存档: 现在,我删除用于db的容器并创建另一个同名容器,并尝试恢复之前插入的数据: 但表是空的,为什么数据没有正确还原?

  • 本文向大家介绍sql server 2005数据库备份还原图文教程,包括了sql server 2005数据库备份还原图文教程的使用技巧和注意事项,需要的朋友参考一下 首先、点击桌面的“SQL Server Management Studio”打开,sql2005的管理器,点击“连接”登录,如图: 一、新建数据库 1、新建数据库 右键点击“数据库”——“新建数据库”,如图: MSSQL2005备份

  • 本文向大家介绍sqlserver还原数据库的时候出现提示无法打开备份设备的解决方法(设备出现错误或设备脱),包括了sqlserver还原数据库的时候出现提示无法打开备份设备的解决方法(设备出现错误或设备脱)的使用技巧和注意事项,需要的朋友参考一下 【问题描述】 在系统管理进行手工备份时,出现提示“无法打开备份设备'E:\自动备份\ufidau8xTmp\UFDATA.BAK'。设备出现错误或设备脱