获取返回错误的存储过程的模式

Get schema of stored procedure which returned error

我有几个名称相同但模式不同的过程。当这些过程引发错误时,父过程(调用这些嵌套存储过程)是否有可能获得引发错误的过程的模式?例如,我可以从 ERROR_PROCEDURE() 获取名称,但是是否有一些选项可以获取 SCHEMA ?因为否则我不确定如果有很多同名的程序会引发错误。

我想这个功能仍然缺失 https://connect.microsoft.com/SQLServer/feedback/details/124627/schema-not-reported-in-the-error-procedure-function

但是有什么解决方法吗?

我能想到的一些可能的解决方案:

  • 重命名每个存储过程,使它们在不同的架构中具有不同的名称。
  • 向存储过程添加一些调试输出,以便在执行它们时,您可以看到发生错误时正在执行的过程。
  • 运行 SQL Profiler 以查看在您的错误发生时正在调用什么。

但是,这些更多是从尝试解决您现在遇到的问题的角度出发的,而不是为将来可能的故障排除构建一些错误处理。您总是可以让这些存储过程将一些日志文件写入磁盘的某个地方,这样您就可以在遇到错误时查询这些日志。

遗憾的是,SQL-Server 中没有针对此限制的 100% 解决方法。
MSSQL 开发团队很遗憾没有纠正这个问题,十年后。
它应该像添加 ERROR_ProcedureSchema()ERROR_PROCID().
这样的新函数一样简单 这是一个复活的 Post 从 2005 年 5 月开始请求此功能:
https://feedback.azure.com/forums/908035-sql-server/suggestions/32894584-schema-not-reported-in-the-error-procedure-functio

我更喜欢尽可能详细地记录我在自定义错误处理逻辑中捕获的异常。
这是我能找到的最好的架构名称:

DECLARE @Error_ProcSchemaName nVarChar(128)--Leave as Null if found in more than 1 Schema.
--Only Populate the @Error_ProcSchemaName if it Belongs to 1 Schema. - 04/08/2019 - MCR.
SELECT @Error_ProcSchemaName = S.name
  FROM sys.objects as O
  JOIN sys.schemas as S
    ON S.schema_id = O.schema_id
  JOIN
  (
    SELECT O.name[ObjectName], COUNT(*)[Occurrences]
      FROM sys.objects as O
     GROUP BY O.name
  ) AS Total
    ON Total.ObjectName = O.name
 WHERE O.name = ERROR_PROCEDURE()
   AND Total.Occurrences = 1

避免 使用类似 OBJECT_SCHEMA_NAME(OBJECT_ID(ERROR_PROCEDURE())) 的任何东西作为您传递给 OBJECT_ID() 的字符串应该已经包含架构(ERROR_PROCEDURE()不是)。
否则它将默认为您的默认架构,(在大多数情况下)是 dbo.

运行 此查询用于查看跨架构重用的所有对象名称:

--View Object Names that Exist in Multiple Schemas: - 04/08/2019 - MCR.
SELECT S.name[SchemaName], O.name[ObjectName], Total.Occurrences,
       O.type[Type], O.type_desc[TypeDesc],
       O.object_id[ObjectID], O.principal_id[PrincipalID], O.parent_object_id[ParentID],
       O.is_ms_shipped[MS], O.create_date[Created], O.modify_date[Modified]
  FROM sys.objects as O
  JOIN sys.schemas as S
    ON S.schema_id = O.schema_id
  JOIN
  (
    SELECT O.name[ObjectName], COUNT(*)[Occurrences]
      FROM sys.objects as O
     GROUP BY O.name
  ) AS Total
    ON Total.ObjectName = O.name
 WHERE Total.Occurrences > 1
 ORDER BY [ObjectName], [SchemaName]

如果您只有几个重叠的对象(Sproc 和触发器),那么您可能不知道架构,因为它的来源可能很明显。
但是,如果不是这种情况,那么您可能需要:

  1. 更改 Sproc/Trigger 的名称,使其独一无二。
    这个选项违背了我的本性。
  2. 如果您使用的是高级错误处理,请手动添加 Sproc/Trigger 的架构和 OBJECT_SCHEMA_NAME(@@PROCID) 在记录错误时在您的 Catch-Block 中。

注意:由于使用了不允许编辑的第 3 方存储过程,这些选项可能无法使用。
当对共享相同名称的多个 Sprocs/Triggers 进行故障排除时,您可以编写一个自定义包装器存储过程来调用您的第 3 方存储过程,然后记录包装器中抛出的任何异常以确切知道哪个 Schema/Sproc导致它。

代码味道:
如果您有多个具有相同名称的 Sprocs/Triggers 分布在各种模式
那么我会称之为“Code Smell”。
意思是,你的架构有缺陷。
您可能没有正确封装您的逻辑以供重用。
名称有时会与架构重叠,但这种情况应该很少见,而且只是巧合。

用于处理多租户/用户组访问的盗用模式:
如果您正在尝试多租户(将来自不同 Organizations/UserGroups 的数据存储在同一个数据库中并防止他们看到彼此的信息)和 运行 在共享对象名称的每个模式中几乎相同的逻辑,那么那是一个设计问题。
如果用户将直接访问数据,您应该将数据放在不同的数据库中
或者有一个 TenantIDUserGroupID 当用户从自定义应用程序访问时,你总是传入并在任何地方过滤。