SQL-Server, TSQL, TRY-CATCH block



我在尝试/捕获错误处理方面遇到问题。让我们来看看我的(简单)代码:

BEGIN TRY
print 'important'
use myDB1; -- no problem, the myDB1 is in place...
select * from dbo.Tab1;
use myDB2;
--here error, the myDB2 is not there, 
--but error handling doesn't jump into catch-block
select * from dbo.Tab2;
END TRY
BEGIN CATCH
    print 'myDB2 is not there'
END CATCH

我知道,我可以说:

select * from myDB2.dbo.Tab2而不更改为 myDB2,但是当我需要检查(例如..)表是否具有标识时

(((SELECT OBJECTPROPERTY( OBJECT_ID('myDB2.dbo.'+ @TableName), 'TableHasIdentity'))= 1)

我必须从 myDB2 运行它,否则我会得到错误的结果。那么我怎样才能在捕获块中捕获错误呢?

感谢您的帮助

普克洛特

您需要将

测试条件封装在 EXEC 中,以便将错误视为运行时问题。然后,您需要为命中可能不存在的数据库的查询完全限定对象,以便可以避免使用 USE 语句。对于需要本地上下文的函数(如 OBJECTPROPERTY),可以使用 sp_executesql 在不同的数据库上下文中运行查询并返回可用结果。

DECLARE @TableName SYSNAME,
        @SQL NVARCHAR(MAX),
        @Result BIT
BEGIN TRY
    USE [master];
    SELECT TOP 1 * FROM sys.objects
    SET @TableName = N'sysjobhistory'
    SET @Result = 0
    SET @SQL = N'USE [msdb]; DECLARE @Result BIT;
                 SET @TempResult = OBJECTPROPERTY( OBJECT_ID(N''' + @TableName +
                 N'''), ''TableHasIdentity'')'
    EXEC sp_executesql @SQL,
                       N'@TempResult BIT OUTPUT',
                       @TempResult = @Result OUTPUT
    SELECT @Result AS [ResultThatCanBeUsedLocally]
    EXEC('USE [NotHere];')
    SELECT TOP 1 * FROM NotHere.sys.objects
END TRY
BEGIN CATCH
    PRINT 'Error!!'
    PRINT ERROR_MESSAGE()
END CATCH

经过一些闲聊的评论,OP 只需要知道表是否有身份。您可以使用它来列出给定数据库中没有标识的表

SELECT TABLE_NAME
FROM MyDB2.INFORMATION_SCHEMA.TABLES
WHERE Table_NAME NOT IN (
    SELECT c.TABLE_NAME
    FROM MyDB2.INFORMATION_SCHEMA.COLUMNS c
    INNER JOIN MyDB2.sys.identity_columns ic ON c.COLUMN_NAME = ic.NAME
)
AND TABLE_TYPE = 'BASE TABLE'

编辑

经过更多的聊天和挖掘,我发现 OP 真的想在 try catch 块内切换数据库。但是该对象是否存在是在解析时检查的,并且尝试捕获仅在运行时错误时才起作用。此外,对象缺失错误似乎无法获得必要的严重性来被 try catch 块捕获(即使使用完整的限定名也不起作用)

OP必须重新考虑如何完成任务。

最新更新