IT *_*her 9 sql-server sql-server-2008-r2 functions
我有一个在十几个数据库中使用的函数。我希望这个函数只写一次就可以在所有数据库中访问,所以我想把这个函数写在 master 数据库中,以便我的函数可以轻松访问。
在master db中编写用户定义的函数有什么问题吗?
上网时,有人建议将功能转换为系统功能。(使用“EXEC sp_ms_marksystemobject 'fn_db_name'”)。
是否有必要将master db中创建的函数转换为系统函数?如果是,为什么?
Aar*_*and 10
我同意 Jonathan - 只要该函数不应该根据调用数据库上下文返回本地数据,将该函数放在实用程序数据库中(这也是我放置数字和日历表、拆分函数等内容的地方) ):
USE UtilityDB;
GO
CREATE FUNCTION dbo.whatever() RETURNS ...
GO
Run Code Online (Sandbox Code Playgroud)
现在,在需要访问该函数的每个数据库中,只需创建一个同义词:
CREATE SYNONYM dbo.whatever() FOR UtilityDB.dbo.whatever();
Run Code Online (Sandbox Code Playgroud)
这样,每个数据库仍然可以使用一个简单的 2 部分名称引用该函数 - 他们不必知道或关心它实际存在的位置。而且您只需要维护该函数的一个副本。
(实际上,您可以将同义词放在model
数据库中,以便在新数据库中自动创建它。)
我不喜欢把用户的原因对象master
-除非他们真的需要在全球范围内提供和上下文的调用数据库,就像你自己的定制版sp_spaceused
或sp_helpindex
-是人们是不是在找用户对象master
,他们就不太在那里可以发现。它们还使得将您的用户数据库迁移到其他地方变得更加困难,因为您还需要记住您放入的用户资料master
。如果您绝对反对为此创建或使用实用程序数据库,我认为这msdb
是一个更实用的中心位置选择。
虽然我同意@Jonathan 和@Aaron 的观点,即您应该使用“实用程序”数据库(我什至命名为我的Utility
),并且我同意 Aaron 关于使用同义词的意见,但我想提请注意 Aaron 提到的警告,因为它是重要的:
只要函数不应该根据调用数据库上下文返回本地数据......
意思是,如果您确实需要“当前数据库”上下文(而不是在它实际存在的数据库中运行的代码,无论是master
还是Utility
),那么使用任何东西但master
都不起作用。
因此,如果您确实需要函数在调用它的数据库的上下文中运行,那么使用函数的计划无论如何都不会起作用,因为master
数据库中的代码可以在当前数据库上下文之外master
运行对于存储过程,即使您使用未记录的sp_ms_marksystemobject
系统存储过程将您的函数标记为系统对象。事实上,在没有完全限定对象名称的情况下,在函数名称前加上前缀fn_
甚至sp_
不允许在 master 之外找到它。然后,即使您确实完全限定了名称,它仍然仅在master
数据库的上下文中运行,即使在被标记为系统对象之后也是如此。
所以你有三个选择:
Utility
为对象使用数据库,并在需要使用 Function 指向数据库的数据库中使用同义词Utility
。如果您确实需要当前的数据库上下文:
sp_
,并在其sp_ms_marksystemobject
上运行系统存储过程以将其标记为系统存储过程(否则它不会反映查询的当前数据库上下文,即使它会为某些内置-in 函数如DB_NAME()
)。我不是这种方法的忠实粉丝,但它确实有效。使用 SQLCLR 创建一个函数,该函数可以放入Utility
数据库并将当前数据库名称(或任何数据库名称)传递给它,以用于创建将作为提交查询的动态 SQL。我在以下答案中发布了一个使用 SQLCLR 执行此类操作的示例,也在 DBA.StackExchange 上:
这种方式也可以使用同义词,然后在传入的同时调用函数DB_NAME()
,自动传入当前数据库名。