How to create a UDF or View in another database that references the correct sys.objects table in the caller?
Using SQL Server 2008, I'd like to create a UDF that gives me the create date of an object. This is the code:
create function dbo.GetObjCreateDate(@objName sysname) returns datetime as
begin
declare @result datetime
select @result = create_date from sys.objects where name = @objname
return @result
end
go
I'd like to p开发者_开发百科ut this UDF in the master database or some other shared database so that it is accessible from anywhere, except that if I do that then the sys.objects
reference pulls from the master
database instead of the database that I'm initiating my query from. I know you can do this as the information_schema
views sit in master
and just wrap calls to local instances of sys.objects, so I'm hoping there's a simple way to do that with my UDF as well.
Try this:
CREATE FUNCTION dbo.GetObjCreateDate(@objName sysname, @dbName sysname)
RETURNS datetime AS
BEGIN
DECLARE @createDate datetime;
DECLARE @params nvarchar(50);
DECLARE @sql nvarchar(500);
SET @params = '@createDate datetime OUTPUT';
SELECT @sql = 'SELECT @createDate = create_date FROM ' + @dbName + '.sys.objects WHERE name = ''' + @objname + '''';
EXEC sp_executesql @sql, @params, @createDate = @createDate OUTPUT;
RETURN @createDate
END
;
Why not do this instead?
- Create a stored procedure that creates a view in the master database containing all of the information in
sys.objects
from each database on the server. - Create a DDL Trigger that gets fired whenever a
CREATE
,ALTER
orDROP
statement is executed for a database. The trigger would then execute the stored procedure in step #1. This allows the view to be automatically updated. - (Optional) Create a user defined function that queries the view for the creation date of a given object.
Stored Procedure DDL:
USE [master];
GO
CREATE PROCEDURE dbo.BuildAllServerObjectsView
AS
SET NOCOUNT ON;
IF OBJECT_ID('master.dbo.AllServerObjects') IS NOT NULL
EXEC master..sp_SQLExec 'DROP VIEW dbo.AllServerObjects;';
IF OBJECT_ID('tempdb..Databases') IS NOT NULL
DROP TABLE #Databases;
DECLARE @CreateView varchar(8000);
SET @CreateView = 'CREATE VIEW dbo.AllServerObjects AS' + CHAR(13)+CHAR(10) + CHAR(13)+CHAR(10);
SELECT name COLLATE SQL_Latin1_General_CP1_CI_AS AS 'name'
INTO #Databases
FROM sys.databases
ORDER BY name;
DECLARE @DatabaseName nvarchar(100);
WHILE (SELECT COUNT(*) FROM #Databases) > 0
BEGIN
SET @DatabaseName = (SELECT TOP 1 name FROM #Databases ORDER BY name);
SET @CreateView +='SELECT N'+QUOTENAME(@DatabaseName, '''')+' AS ''database_name''' + CHAR(13)+CHAR(10)
+ ' ,name COLLATE SQL_Latin1_General_CP1_CI_AS AS ''object_name''' + CHAR(13)+CHAR(10)
+ ' ,object_id' + CHAR(13)+CHAR(10)
+ ' ,principal_id' + CHAR(13)+CHAR(10)
+ ' ,schema_id' + CHAR(13)+CHAR(10)
+ ' ,parent_object_id' + CHAR(13)+CHAR(10)
+ ' ,type' + CHAR(13)+CHAR(10)
+ ' ,type_desc' + CHAR(13)+CHAR(10)
+ ' ,create_date' + CHAR(13)+CHAR(10)
+ ' ,modify_date' + CHAR(13)+CHAR(10)
+ ' ,is_ms_shipped' + CHAR(13)+CHAR(10)
+ ' ,is_published' + CHAR(13)+CHAR(10)
+ ' ,is_schema_published' + CHAR(13)+CHAR(10)
+ ' FROM ' + QUOTENAME(@DatabaseName) + '.sys.objects';
IF (SELECT COUNT(*) FROM #Databases) > 1
SET @CreateView += CHAR(13)+CHAR(10) + CHAR(13)+CHAR(10) + ' UNION' + CHAR(13)+CHAR(10);
ELSE
SET @CreateView += ';';
DELETE #Databases
WHERE name = @DatabaseName;
END;
--PRINT @CreateView --<== Uncomment this to see the DDL for the view.
EXEC master..sp_SQLExec @CreateView;
IF OBJECT_ID('tempdb..Databases') IS NOT NULL
DROP TABLE #Databases;
GO
Function DDL:
USE [master];
GO
CREATE FUNCTION dbo.GetObjCreateDate(@DatabaseName sysname, @objName sysname) RETURNS DATETIME AS
BEGIN
DECLARE @result datetime;
SELECT @result = create_date
FROM master.dbo.AllServerObjects
WHERE [database_name] = @DatabaseName
AND [object_name] = @objname;
RETURN @result;
END
GO
Sample Usage:
SELECT master.dbo.GetObjCreateDate('MyDatabase', 'SomeObject') AS 'Created';
SELECT master.dbo.GetObjCreateDate(DB_NAME(), 'spt_monitor') AS 'Created';
Does it have to be a function? If you just want it accessible everywhere, a trick is to put your code in a varchar and sp_executesql it:
create procedure dbo.GetObjCreateDate(@objName sysname)
as
declare @sql nvarchar(max)
select @sql = 'select create_date from sys.objects where name = ''' + @objname + ''''
EXEC sp_executesql @sql
go
There seems to be an undocumented stored procedure that allows you to create your own system objects: sp_ms_marksystemobject
You can read more on http://www.mssqltips.com/tip.asp?tip=1612
Have a look at How to Write Your Own System Functions. I believe that it may help you
精彩评论