主数据库中的用户定义函数 (UDF)

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_spaceusedsp_helpindex-是人们是不是在找用户对象master,他们就不太在那里可以发现。它们还使得将您的用户数据库迁移到其他地方变得更加困难,因为您还需要记住您放入的用户资料master。如果您绝对反对为此创建或使用实用程序数据库,我认为这msdb是一个更实用的中心位置选择。


Sol*_*zky 5

虽然我同意@Jonathan 和@Aaron 的观点,即您应该使用“实用程序”数据库(我什至命名为我的Utility),并且我同意 Aaron 关于使用同义词的意见,但我想提请注意 Aaron 提到的警告,因为它是重要的:

只要函数不应该根据调用数据库上下文返回本地数据......

意思是,如果您确实需要“当前数据库”上下文(而不是在它实际存在的数据库中运行的代码,无论是master还是Utility),那么使用任何东西但master都不起作用。

因此,如果您确实需要函数在调用它的数据库的上下文中运行,那么使用函数的计划无论如何都不会起作用,因为master数据库中的代码可以在当前数据库上下文之外master运行对于存储过程,即使您使用未记录的sp_ms_marksystemobject系统存储过程将您的函数标记为系统对象。事实上,在没有完全限定对象名称的情况下,在函数名称前加上前缀fn_甚至sp_不允许在 master 之外找到它。然后,即使您确实完全限定了名称,它仍然仅在master数据库的上下文中运行,即使在被标记为系统对象之后也是如此。

所以你有三个选择:

  1. 如果您不需要当前的 DB 上下文,则按照 Aaron 的建议Utility为对象使用数据库,并在需要使用 Function 指向数据库的数据库中使用同义词Utility
  2. 如果您确实需要当前的数据库上下文:

    1. 将函数更改为存储过程,重命名以 开头sp_,并在其sp_ms_marksystemobject上运行系统存储过程以将其标记为系统存储过程(否则它不会反映查询的当前数据库上下文,即使它会为某些内置-in 函数如DB_NAME())。我不是这种方法的忠实粉丝,但它确实有效。
    2. 使用 SQLCLR 创建一个函数,该函数可以放入Utility数据库并将当前数据库名称(或任何数据库名称)传递给它,以用于创建将作为提交查询的动态 SQL。我在以下答案中发布了一个使用 SQLCLR 执行此类操作的示例,也在 DBA.StackExchange 上:

      在调用数据库上下文中执行的中央存储过程

      这种方式也可以使用同义词,然后在传入的同时调用函数DB_NAME(),自动传入当前数据库名。