Как создать UDF или View в другой базе данных, которая ссылается на правильную таблицу sys.objects в вызывающей программе? - PullRequest
2 голосов
/ 27 октября 2010

Используя SQL Server 2008, я хотел бы создать UDF, который дает мне дату создания объекта. Это код:

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

Я бы хотел поместить этот UDF в основную базу данных или в другую общую базу данных, чтобы он был доступен из любого места, за исключением того, что если я это сделаю, то ссылка sys.objects извлекается из базы данных master вместо база данных, из которой я инициирую свой запрос. Я знаю, что вы можете сделать это, так как information_schema представления находятся в master и просто обертывают вызовы локальных экземпляров sys.objects, поэтому я надеюсь, что есть простой способ сделать это и с моим UDF.

Ответы [ 5 ]

5 голосов
/ 05 ноября 2012

Попробуйте это:

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
;
4 голосов
/ 09 ноября 2012

Почему бы не сделать это вместо этого?

  1. Создать хранимую процедуру, которая создает представление в базе данных master, содержащее всю информацию в sys.objects из каждой базы данных на сервере.
  2. Создайте DDL Trigger , который запускается всякий раз, когда для базы данных выполняется оператор CREATE, ALTER или DROP.Затем триггер выполнит хранимую процедуру на шаге № 1.Это позволяет автоматически обновлять представление.
  3. (необязательно) Создать пользовательскую функцию, которая запрашивает представление о дате создания данного объекта.

Хранимая процедура 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

Функция 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

Использование образца:

SELECT master.dbo.GetObjCreateDate('MyDatabase', 'SomeObject') AS 'Created';
SELECT master.dbo.GetObjCreateDate(DB_NAME(), 'spt_monitor') AS 'Created';
2 голосов
/ 19 ноября 2010

Должно ли это быть функцией?Если вы просто хотите, чтобы он был доступен везде, хитрость заключается в том, чтобы поместить ваш код в varchar и sp_executesql:

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
1 голос
/ 07 ноября 2012

Посмотрите на Как написать свои собственные системные функции . Я верю, что это может помочь вам

1 голос
/ 27 октября 2010

Кажется, есть недокументированная хранимая процедура, которая позволяет вам создавать свои собственные системные объекты: sp_ms_marksystemobject

Вы можете прочитать больше на http://www.mssqltips.com/tip.asp?tip=1612

...