SQL Server:查询中错误捕获

时间:2017-07-18 08:23:31

标签: sql-server try-catch

在我的查询中,我必须连接不受我控制的db表。这让我很生气,因为有时这个数据库无法访问(请不要问我为什么)这会打破我的疑问。我加入的字段不是我操作的基础,我希望我的应用程序正常工作,即使这些字段一次无法访问。

这是我不拥有的数据结构:

[DBOutOfControl].[dbo].[Table1]:
[Field1]
[Field2]

[DBOutOfControl].[dbo].[Table2]:
[Field1]
[Field2]
[Field3]

这是我的表:

[DBInMyControl].[dbo].[Table3]:
[Field1]

我的原始查询看起来像这样:

SELECT [Table3].[MyID],
       [ForeignDataQry].[A],
       [ForeignDataQry].[B]
FROM [DBInMyControl].[dbo].[Table3]
LEFT JOIN
  (SELECT [Table1].[Field1] AS [MyID],
          [Table1].[Field2] AS [A],
          [SubQry].[Field2] AS [B]
   FROM [DBOutOfControl].[dbo].[Table1]
   LEFT JOIN
     (SELECT [Table2].[Field1],
             [Table2].[Field2]
      FROM [DBOutOfControl].[dbo].[Table2]
      WHERE [Table2].[Field3] = 'Where') AS [SubQry] ON [Table1].[Field1] = [SubQry].[Field1]) AS [ForeignDataQry] ON [Table3].[MyID]=[ForeignDataQry].[MyID]

如何防止此查询,以便在[ForeignDataQry]生成错误时结果如下:

[MyID]  [A]  [B]
1       NULL NULL

否则

[MyID]  [A]  [B]
1       Va1  Val2

服务器方面有什么可以做的吗?

3 个答案:

答案 0 :(得分:0)

只需指定COUNT的预期结果,即三个名称,您可以事先检查表格。轻微的重写可以允​​许它检查除表之外的对象,如果需要,可以使用EXISTS,跳过或添加更多检查等等:

IF 0 = ( -- Specify how many records you expect to come.
    SELECT COUNT(C.[name]) AS [COUNT]
    FROM sys.objects AS O
    LEFT JOIN sys.schemas AS S ON S.schema_id = O.schema_id
    LEFT JOIN sys.columns AS C ON C.object_id = O.object_id
    WHERE O.[name] = 'tablename'
      AND S.[name] = 'schemaname'
      AND C.[name] = 'columnname'
)
    SELECT 1 AS A -- Do some code.
ELSE
    SELECT 2 AS B -- Do some other code.

答案 1 :(得分:0)

我将有问题的查询包装在动态代码中,以便能够捕获编译错误(我们无法在同一范围内捕获),如下所示:

    begin try
    declare @sql varchar(4000) =

        'SELECT [Table3].[MyID],
               [ForeignDataQry].[A],
               [ForeignDataQry].[B]
        FROM [DBInMyControl].[dbo].[Table3]
        LEFT JOIN
          (SELECT [Table1].[Field1] AS [MyID],
                  [Table1].[Field2] AS [A],
                  [SubQry].[Field2] AS [B]
           FROM [DBOutOfControl].[dbo].[Table1]
           LEFT JOIN
             (SELECT [Table2].[Field1],
                     [Table2].[Field2]
              FROM [DBOutOfControl].[dbo].[Table2]
              WHERE [Table2].[Field3] = ''Where'') AS [SubQry] ON [Table1].[Field1] = [SubQry].[Field1]) AS [ForeignDataQry] ON [Table3].[MyID]=[ForeignDataQry].[MyID]'
       exec(@sql)
    end try
    begin catch
        SELECT [Table3].[MyID],
               cast(null as ... )as [A],
               cast(null as ...) as [B]
        FROM [DBInMyControl].[dbo].[Table3]
    end catch

在这里,我使用cast(null as ... )as [A]获取与[ForeignDataQry].[A]相同的类型,例如,如果[ForeignDataQry].[A]为int,则应该为int:cast(null as int )as [A]

答案 2 :(得分:0)

我以不同的方式解决了这个问题,但最后还是:

我创建了一个[Table4]来保存外来表中记录的副本 - 字段匹配[ForeignDataQry] + timestamp。我创建了程序:

CREATE PROCEDURE [dbo].[CopyForeignData] 
AS

DECLARE @Timestamp datetime
SET @Timestamp = getdate()

BEGIN
    INSERT INTO [DBInMyControl].[dbo].[Table4] ([MyID], [A], [B], [Timestamp])
    SELECT [Table1].[Field1] AS [MyID],
          [Table1].[Field2] AS [A],
          [SubQry].[Field2] AS [B],
          @Timestamp
   FROM [DBOutOfControl].[dbo].[Table1]
   LEFT JOIN
     (SELECT [Table2].[Field1],
             [Table2].[Field2]
      FROM [DBOutOfControl].[dbo].[Table2]
      WHERE [Table2].[Field3] = 'Where') AS [SubQry] ON [Table1].[Field1] = [SubQry].[Field1]

    DELETE FROM [DBInMyControl].[dbo].[Table4] WHERE [Timestamp] <> @Timestamp
END

每当我启动应用程序并在那里处理错误并修改我的主LEFT JOIN以参考[表4]

时,我会调用它