Pergunta sobre sql, sql-server-2008 – Posso criar uma função global no SQL Server?

5

É possível criar uma função no SQL Server que eu poderia usar em qualquer banco de dados no servidor, sem adicionar o prefixo do banco de dados?

Por exemplo, com esta função:

CREATE FUNCTION getDays (@date date)
RETURNS INT
AS
BEGIN

RETURN CASE WHEN MONTH(@date) IN (1, 3, 5, 7, 8, 10, 12) THEN 31
            WHEN MONTH(@date) IN (4, 6, 9, 11) THEN 30
            ELSE CASE WHEN (YEAR(@date) % 4    = 0 AND
                            YEAR(@date) % 100 != 0) OR
                           (YEAR(@date) % 400  = 0)
                      THEN 29
                      ELSE 28
                 END
       END

END

Sua resposta

2   a resposta
3

Embora a criação de procedimentos armazenados no mestre os torne disponíveis globalmente, isso não funciona para funções. Você precisa usar a convenção de nomenclatura de três partes:

select <dbname>.<schema>.getDays(...)

Por que a Microsoft tornaria as funções diferentes dos procedimentos armazenados?

A funcionalidade que torna os procedimentos armazenados globalmente disponíveis nunca foi realmente destinada aos clientes, era para procedimentos armazenados no sistema, como o sp_help, que existe em um lugar, mas para ser executado no contexto de qualquer banco de dados. Esse recurso nunca foi necessário internamente para tabelas, visualizações, funções, etc. por isso simplesmente nunca existiu. Eu não acho que o uso deste "recurso" é oficialmente suportado, e pode não funcionar em alguma versão futura. Aaron Bertrand
Criar a função no mestre não a torna disponível para outros bancos de dados. Esse comportamento é verdadeiro para procedimentos armazenados e somente quandosp_configure opçãoallow updates está definido como 1 ou o procedimento é nomeadosp_<something>. Aaron Bertrand
Aaron, essa é uma boa resposta, mas por que eles não fariam o mesmo com funções? Certamente, existem funções do sistema que também se beneficiam de estar globalmente disponíveis. Gordon Linoff
Eu criei no mestre, mas o meu roteiro não o vê Артём Царионов
16

Você pode criar a função em master (ou algum outro banco de dados permanente) e, em seguida, criar um sinônimo no banco de dados de modelo:

USE model;
GO
CREATE SYNONYM dbo.getDays FOR master.dbo.getDays;

Isso criará um sinônimo para a função em qualquerNovo bancos de dados, mas para bancos de dados existentes (ou bancos de dados anexados ou restaurados no futuro) você precisará copiar o sinônimo lá. Isso permitirá que você faça referência ao objeto com um nome de duas partes em qualquer banco de dados, tendo apenas que armazenar uma cópia do código.

Como um aparte, seu código pode ser muito mais conciso:

  RETURN (SELECT DATEPART(DAY, DATEADD(DAY, -1, 
     DATEADD(MONTH, 1, DATEADD(DAY, 1-DAY(@date), @date)))));

Então, de cima:

USE [master];
GO
DROP FUNCTION dbo.getDays;
GO
CREATE FUNCTION dbo.getDays
(
    @date DATE
)
RETURNS INT
AS
BEGIN
    RETURN (SELECT DATEPART(DAY, DATEADD(DAY, -1, 
         DATEADD(MONTH, 1, DATEADD(DAY, 1-DAY(@date), @date)))));
END
GO

Agora, para criar um sinônimo para isso em cada banco de dados:

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += CHAR(13) + CHAR(10) 
+ 'USE ' + QUOTENAME(name) + ';

IF OBJECT_ID(''dbo.getDays'', ''FN'') IS NOT NULL
  DROP FUNCTION dbo.getDays;

IF OBJECT_ID(''dbo.getDays'', ''SN'') IS NOT NULL
  DROP SYNONYM dbo.getDays

CREATE SYNONYM dbo.getDays FOR master.dbo.getDays;'
 FROM sys.databases WHERE name <> 'master';

PRINT @sql;

EXEC sp_executesql @sql;
Eu não entendo como aquelesreturn trabalho Артём Царионов
Ah eu vejo. Артём Царионов
Obtém os mesmos resultados ... trabalhando de dentro para fora, subtrai (1-@date's date) a partir de@date para obter o primeiro dia desse mês. Adicione um mês, esse é o primeiro do próximo mês. Então subtraia um dia. Esse é o último dia do mês do @ date. DATEPART (DAY) extrai o dia (por exemplo, 31 para @date = '2005-05-anything') ... Aaron Bertrand
'getDays' não é um nome de função interno reconhecido. Артём Царионов
Você precisa criar a função em master e, em seguida, criar o sinônimo em bancos de dados existentes (não apenas no modelo). Cria-lo no modelo só cria a função emNovo bancos de dados criados depois que o sinônimo foi criado no modelo. E você deve sempre, sempre, referenciar SEMPRE funções ou sinônimos com o prefixo do esquema, então deve serdbo.getDays, nãogetDays. Aaron Bertrand

Perguntas relacionadas