遗憾的是,对于 SQL-Server 中的此限制,没有 100% 的解决方法。
很遗憾 MSSQL 开发团队在十多年后没有纠正这个问题。
它应该像添加一个新函数一样简单,如 ERROR_ProcedureSchema() 或 ERROR_PROCID()。
这是 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 和触发器),那么您可能不知道 Schema,因为它的来源可能很明显。
但是,如果不是这种情况,那么您可能需要:
- 更改存储过程/触发器的名称以使其唯一。
这种选择违背了我的本质。
- 如果您使用高级错误处理,则使用
OBJECT_SCHEMA_NAME(@@PROCID) 手动添加 Sproc/Trigger 的架构
记录错误时在您的 Catch-Block 中。
注意:由于使用了 3rd Party Sproc,因此这些选项可能无法使用。
当使用多个具有相同名称的 Sproc/触发器进行故障排除时,您可以编写一个自定义 Wrapper-Sproc 来调用您的 3rd Party Sproc,然后记录您的 Wrapper 中抛出的任何异常,以准确了解是哪个 Schema/Sproc 引起的。
代码味道:
如果您有多个同名的 Sprocs/Triggers 分布在各种架构中
那么我将其称为“代码气味”。
意思是,您的架构存在缺陷。
您可能没有正确封装您的逻辑以供重用。
有时名称会与 Schema 重叠,但这应该很少见,而且只是巧合。
用于处理多租户/用户组访问的盗用架构:
如果您正在尝试多租户(将来自不同组织/用户组的数据存储在同一数据库中并防止他们看到彼此的信息)并在共享对象名称的每个模式中运行几乎相同的逻辑,那么这是一个设计问题。
如果用户将直接访问数据,您应该将数据保存在不同的数据库中
或者有一个TenantID 或UserGroupID,当用户从自定义应用程序访问时,您总是在任何地方传递和过滤。