首页 > 解决方案 > BEGIN TRY and EXECUTE 动态简单查询错误

问题描述

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

消息 0,级别 11,状态 0,行 0 当前命令发生严重错误。结果,如果有的话,应该丢弃。

当 try-catch 被注释时,它会起作用,在使用其他列时也是如此。当 partition by 被删除时,它也可以工作。

有人可以说这里的错误根源在哪里还是一些 sql server 错误?

询问:

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

标签: sql-serverdatabase-metadata

解决方案


这是一个错误。我已经在这里报告了

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

以下查询返回两个 object_id-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 Server 无法解析其排序规则。由于这些对象仅与并行数据仓库相关,甚至在产品的其他版本中都不存在,这通常不是问题。

sys.all_columns引用sys.system_columns使用以下表达式的视图collation_nameconvert(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')

两者都返回

消息 0,级别 11,状态 0,第 33 行

当前命令发生严重错误。结果,如果有的话,应该丢弃。

TRY块外运行时返回NULLXACT_ABORT关闭时)。在幕后,它抛出一个内部处理的异常,最终用户不知道。抛出异常时的调用堆栈显示该GetColumnCollate函数最终使用 Algebrizer 尝试解析列,但最终失败CAlgTableMetadata::RaiseBadTableException(可能是因为某处缺少相关的对象定义)。

在此处输入图像描述

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

因此,解决问题的一种方法是将引用包装collation_name在一个表达式中,这样当在块内运行时CASE,它永远不会针对这两个问题进行评估。object_idTRY

  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

这并不能保护您免受将来将有问题的元数据添加到产品中的不同情况。然而,我再次质疑这个查询的必要性。您提供的查询非常奇怪,很难告诉您应该用什么替换它。


推荐阅读