BEGIN TRY 和 EXECUTE 动态简单查询错误

BEGIN TRY and EXECUTE dynamic simple query error

当我执行附加查询时出现错误:

Msg 0, Level 11, State 0, Line 0 A severe error occurred on the current command. The results, if any, should be discarded.

当try-catch被注释时,它就起作用了,当使用其他列时也是如此。 当分区依据被删除时,它也有效。

有人能说出这里的错误根源在哪里还是一些 sql 服务器错误?

查询:

BEGIN TRY 
    DECLARE  @vSqlCmd NVARCHAR(MAX) = N'
    SELECT TOP 1 V = d.collation_name, C = COUNT(1) OVER (PARTITION BY d.collation_name)
    FROM sys.all_columns d;';
    SELECT @vSqlCmd;

    EXECUTE (@vSqlCmd);
END TRY
BEGIN CATCH
    PRINT 'CATCH!!!';

    THROW;
END CATCH

这是一个错误。 I have reported it here

不清楚您为什么需要这个查询,下面解释了这个问题以及如果有一些合理的理由需要这个查询如何避免它。

下面查询returns两个object_ids-103085222-593

SELECT object_id ,name
FROM sys.system_columns
where system_type_id in (35,99,167,175,231,239) and collation_name IS NULL

这些与下面的对象有关

+------------+----------------------------------+
|     id     |               name               |
+------------+----------------------------------+
| -103085222 | pdw_nodes_pdw_physical_databases |
|       -593 | pdw_table_mappings               |
+------------+----------------------------------+

出于某种原因,这两个都有一个字符串列(称为 physical_name),SQL 服务器无法为其解析排序规则。由于这些对象仅与并行数据仓库相关,甚至不存在于产品的其他版本中,这通常不是问题。

sys.all_columns 引用 sys.system_columns 视图,该视图对 collation_name 使用以下表达式:convert(sysname, ColumnPropertyEx(object_id, name, 'collation'))

重现该问题的一个更简单的案例是

BEGIN TRY
    SELECT columnpropertyex(-593, 'physical_name', 'collation')
END TRY
BEGIN CATCH
END CATCH 

SET XACT_ABORT ON;
SELECT columnpropertyex(-593, 'physical_name', 'collation')

两者都return

Msg 0, Level 11, State 0, Line 33

A severe error occurred on the current command. The results, if any, should be discarded.

When 运行 outside the TRY block this returns NULL (当 XACT_ABORT 关闭时)。在幕后,它抛出一个内部处理的异常,而最终用户并不知道。抛出异常时的调用堆栈显示 GetColumnCollate 函数最终使用 Algebrizer 尝试解析列并最终在 CAlgTableMetadata::RaiseBadTableException 中失败(可能是因为某处缺少相关对象定义)。

当 运行 在 TRY ... CATCH 上下文中或使用 XACT_ABORT ON 时,本应静默忽略错误的位出现问题并且 return NULL.使用 ignore_dup_key ON 将重复键插入索引也会引发一个内部错误,该错误被忽略但没有相同的问题。

因此,解决该问题的一种方法是将对 collation_name 的引用包装在 CASE 表达式中,这样当 运行 在 TRY 块内。

  BEGIN TRY 
    DECLARE  @vSqlCmd NVARCHAR(MAX) = N'
    SELECT TOP 1 V = ca.safe_collation_name, C = COUNT(1) OVER (PARTITION BY ca.safe_collation_name)
    FROM sys.all_columns d
    CROSS APPLY (SELECT CASE WHEN object_id NOT IN (-593,-103085222) THEN collation_name END) ca(safe_collation_name);
    ';
    SELECT @vSqlCmd;

    EXECUTE (@vSqlCmd);
END TRY
BEGIN CATCH
    PRINT 'CATCH!!!';

    THROW;
END CATCH

这并不能保护您免受将来向产品中添加有问题的元数据的不同情况的影响。但是,我再次质疑此查询的必要性。您提供的查询太奇怪了,很难建议您应该用什么来替换它。