{"id":286,"date":"2010-04-11T15:18:01","date_gmt":"2010-04-11T18:18:01","guid":{"rendered":"http:\/\/fabriciodba.wordpress.com\/2010\/04\/11\/como-criar-um-controle-de-versao-de-procedures-views-e-functions-no-sql-server"},"modified":"2016-12-16T13:32:14","modified_gmt":"2016-12-16T15:32:14","slug":"como-criar-um-controle-de-versao-de-procedures-views-e-functions-no-sql-server","status":"publish","type":"post","link":"https:\/\/fabriciolima.net\/blog\/2010\/04\/11\/como-criar-um-controle-de-versao-de-procedures-views-e-functions-no-sql-server\/","title":{"rendered":"Como criar um Controle de Vers\u00e3o de Procedures, Views e Functions no SQL Server"},"content":{"rendered":"<div id=\"msgcns!874FDFFD5EC76B2E!342\" class=\"bvMsg\">\n<p>Quantas vezes j\u00e1 te perguntaram qual era o c\u00f3digo de uma fun\u00e7\u00e3o, procedure ou view em uma determinada data?<\/p>\n<p>At\u00e9 o SQL Server 2000, s\u00f3 era poss\u00edvel obter essa informa\u00e7\u00e3o atrav\u00e9s da gera\u00e7\u00e3o peri\u00f3dica de arquivos com scripts dos objetos do banco de dados. Entretanto, a partir do SQL Server 2005, esse procedimento melhorou com a nova funcionalidade das Triggers DDL(Data Definition Language). Nesse artigo, mostrarei como montar um Controle de Vers\u00e3o de objetos do banco de dados, tais como, fun\u00e7\u00f5es, procedures, views, tabelas, \u00edndices e etc. O procedimento \u00e9 muito simples de se implementar e \u00e9 de muita import\u00e2ncia para um ambiente de banco de dados. Portanto, se voc\u00ea ainda n\u00e3o guarda essas informa\u00e7\u00f5es, aconselho que implemente esse Controle de Vers\u00e3o de objetos assim que poss\u00edvel em seu ambiente.<\/p>\n<p>Inicialmente, devemos gerar um script de nossa database para armazenar as informa\u00e7\u00f5es dos objetos da forma como eles est\u00e3o nesse momento. Para fazer isso, basta ir no Object Explore do Management Studio, clicar com o bot\u00e3o direito sobre uma database -&gt; Tasks &#8211; &gt; Generate Scripts , depois \u00e9 s\u00f3 seguir o Wizard marcando a op\u00e7\u00e3o de gerar o script para todos os objetos dessa database e salvar o script em um arquivo.<\/p>\n<p>Esse procedimento deve ser realizado para todas as databases que voc\u00ea queira guardar as informa\u00e7\u00f5es.<\/p>\n<p>Nesse momento, temos a vers\u00e3o de todos os objetos das databases de nosso banco de dados. Para guardar as altera\u00e7\u00f5es futuras criaremos uma tabela e uma trigger DDL que ir\u00e1 inserir registros em nossa tabela com as novas vers\u00f5es dos objetos.<\/p>\n<p>Mas Fabr\u00edcio, e as altera\u00e7\u00f5es que j\u00e1 foram realizadas, eu n\u00e3o consigo descobrir?<br \/>\nInfelizmente n\u00e3o. O controle de vers\u00e3o passar\u00e1 a valer somente a partir de sua implementa\u00e7\u00e3o, s\u00f3 a partir desse momento que saberemos como um objeto estava em qualquer dia e hora que precisarmos.<\/p>\n<p>Para criar a tabela, deve ser escolhida uma database para rodar o script abaixo. No meu caso, a tabela ficar\u00e1 armazenada em uma database chamada FabricioLima e esse nome deve ser alterado para o nome de uma database do seu ambiente.<\/p>\n<pre class=\"lang:tsql decode:true \">\r\nCREATE TABLE [FabricioLima].[dbo].[Trace_Alteracao_Objeto] (\r\n\t[Id_Trace_Alteracao_Objeto] [INT] IDENTITY(1,1) NOT NULL,\r\n\t[Tp_Evento] [VARCHAR](30) NULL,\r\n\t[Dt_Alteracao] [DATETIME] NULL,\r\n\t[Nm_Servidor] [VARCHAR](100) NULL,\r\n\t[Nm_Login] [VARCHAR](50) NULL,\r\n\t[Nm_Database] [VARCHAR](20) NULL,\r\n\t[Nm_Objeto] [VARCHAR](50) NULL,\r\n\t[Ds_Evento] [XML] NULL\r\n) ON [PRIMARY]\r\n<\/pre>\n<p>Logo em seguida, criaremos a trigger a n\u00edvel de database que enviar\u00e1 os dados para a nossa tabela. Essa trigger deve ser criada em todas as databases que voc\u00ea queira fazer o controle de vers\u00e3o dos objetos.<\/p>\n<pre class=\"lang:tsql decode:true \">\r\nCREATE TRIGGER [trgTrace_Alteracao_Objeto]\r\nON DATABASE\r\nFOR DDL_DATABASE_LEVEL_EVENTS\r\nAS\r\nBEGIN\r\n    SET NOCOUNT ON\r\n    SET ARITHABORT ON\r\n\r\n    DECLARE @Evento XML\r\n    SET @Evento = EVENTDATA()\r\n    \r\n    INSERT INTO [FabricioLima].[dbo].[Trace_Alteracao_Objeto] ( [Tp_Evento], [Dt_Alteracao], [Nm_Servidor], [Nm_Login], [Nm_Database], [Nm_Objeto], [Ds_Evento] )\r\n    SELECT  @Evento.value('(\/EVENT_INSTANCE\/EventType\/text())[1]','VARCHAR(50)') [Tipo_Evento],\r\n            @Evento.value('(\/EVENT_INSTANCE\/PostTime\/text())[1]','DATETIME') [PostTime],\r\n            @Evento.value('(\/EVENT_INSTANCE\/ServerName\/text())[1]','VARCHAR(50)') [ServerName],\r\n            @Evento.value('(\/EVENT_INSTANCE\/LoginName\/text())[1]','VARCHAR(50)') [LoginName],\r\n            @Evento.value('(\/EVENT_INSTANCE\/DatabaseName\/text())[1]','VARCHAR(50)') [DatabaseName],\r\n            @Evento.value('(\/EVENT_INSTANCE\/ObjectName\/text())[1]','VARCHAR(50)') [ObjectName], \r\n            @Evento\r\nEND\r\n<\/pre>\n<p>Vamos aos testes. Execute os procedimentos abaixo para verificar se os mesmos ser\u00e3o registrados.<\/p>\n<pre class=\"lang:tsql decode:true \">\r\nCREATE PROCEDURE [dbo].[stpControle_versao] AS SELECT 'Vers\u00e3o 1.0'\r\n\r\nGO\r\nALTER PROCEDURE [dbo].[stpControle_versao] AS SELECT 'Vers\u00e3o 2.0'\r\n\r\nGO\r\nDROP PROCEDURE [dbo].[stpControle_versao]\r\n\r\nGO\r\nCREATE FUNCTION [dbo].[fncControle_versao]() RETURNS VARCHAR(10) AS  BEGIN RETURN 'Vers\u00e3o 1.0' END\r\n\r\nGO\r\nALTER FUNCTION [dbo].[fncControle_versao]() RETURNS VARCHAR(10) AS  BEGIN RETURN 'Vers\u00e3o 2.0' END\r\n\r\nGO\r\nDROP FUNCTION [dbo].[fncControle_versao]\r\n<\/pre>\n<p>Para conferir as informa\u00e7\u00f5es do controle de vers\u00e3o, basta executar a query abaixo.<\/p>\n<pre class=\"lang:tsql decode:true \">\r\nSELECT [Tp_Evento], [Dt_Alteracao], [Nm_Servidor], [Nm_Login], [Nm_Database], [Nm_Objeto], [Ds_Evento]\r\nFROM [FabricioLima].[dbo].[Trace_Alteracao_Objeto] WITH(NOLOCK)\r\nORDER BY [Dt_Alteracao]\r\n<\/pre>\n<p>Essa query retorna o seguinte resultado.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/fg7djq.bay.livefilestore.com\/y1pZnviks_oXTAbvTepEXLmnGOQrvNjLmPIYsnTtHeOc35EqnNRyKgWy5UP9pLfVfu7xdnua1G4ZCJ-dmwm3lqJfpEEYCjfqwI3\/Figura 1 - Resultado query.JPG\" alt=\"\" width=\"953\" height=\"120\" \/><\/p>\n<\/div>\n<p>Podemos verificar que a cria\u00e7\u00e3o, altera\u00e7\u00e3o e a exclus\u00e3o dos dois objetos foram registradas com a data da altera\u00e7\u00e3o e o Login de quem alterou.<\/p>\n<p>Segue um exemplo da utiliza\u00e7\u00e3o do controle de vers\u00e3o:<\/p>\n<p>Imagine que foi gerado um script de uma database chamada FabricioLima no dia 01\/01\/2010.<br \/>\nEssa database possui uma SP chamada stpControle_Versao, onde a mesma foi alterada nos dias 01\/02\/2010, 01\/03\/2010 e 01\/04\/2010.<br \/>\nNos dias em que o objeto foi alterado, a trigger inseriu uma linha na tabela de trace com as altera\u00e7\u00f5es.<\/p>\n<p>Abaixo mostro onde encontrar a vers\u00e3o procurada de acordo com uma determinada necessidade:<\/p>\n<p>Preciso de saber como a SP estava no dia 10\/01\/2010: Est\u00e1 no Script gerado dia 01\/01\/2010<br \/>\nPreciso de saber como a SP estava no dia 30\/01\/2010: Est\u00e1 no Script gerado dia 01\/01\/2010<br \/>\nPreciso de saber como a SP estava no dia 20\/02\/2010: Est\u00e1 na tabela Trace_Alteracao_Objeto com Dt_Alteracao = 01\/02\/2010<br \/>\nPreciso de saber como a SP estava no dia 20\/03\/2010: Est\u00e1 na tabela Trace_Alteracao_Objeto com Dt_Alteracao = 01\/03\/2010<br \/>\nPreciso de saber como a SP estava no dia 05\/04\/2010: Como a \u00faltima altera\u00e7\u00e3o foi no dia 01\/04\/2010, o c\u00f3digo da SP no dia 05\/04\/2010 \u00e9 o c\u00f3digo atual da SP.<\/p>\n<p>Assim, quando algu\u00e9m te solicitar o script de um objeto, basta executar a query abaixo para recuperar todas as altera\u00e7\u00f5es nesse objeto.<\/p>\n<pre class=\"lang:tsql decode:true \">\r\nSELECT *\r\nFROM [dbo].[Trace_Alteracao_Objeto] WITH(NOLOCK)\r\nWHERE [Nm_Objeto] = 'Nome_Objeto'\r\nORDER BY [Dt_Alteracao]\r\n<\/pre>\n<p>Caso nenhum resultado seja retornado, esse objeto nunca foi alterado desde a implementa\u00e7\u00e3o do Controle de Vers\u00e3o.<\/p>\n<p>Depois de encontrada a vers\u00e3o desejada na tabela, para visualizar seu c\u00f3digo basta clicar sobre a coluna Ds_Evento dessa linha. Uma nova janela \u00e9 aberta com o c\u00f3digo XML do evento que foi executado, conforme podemos ver abaixo.<\/p>\n<pre class=\"lang:tsql decode:true \">\r\n&lt;EVENT_INSTANCE&gt;\r\n  &lt;EventType&gt;ALTER_PROCEDURE&lt;\/EventType&gt;\r\n  &lt;PostTime&gt;2010-04-11T10:51:44.483&lt;\/PostTime&gt;\r\n  &lt;SPID&gt;51&lt;\/SPID&gt;\r\n  &lt;ServerName&gt;FABRICIO&lt;\/ServerName&gt;\r\n  &lt;LoginName&gt;FABRICIO\\Fabriciol1&lt;\/LoginName&gt;\r\n  &lt;UserName&gt;dbo&lt;\/UserName&gt;\r\n  &lt;DatabaseName&gt;FabricioLima&lt;\/DatabaseName&gt;\r\n  &lt;SchemaName&gt;dbo&lt;\/SchemaName&gt;\r\n  &lt;ObjectName&gt;stpControle_versao&lt;\/ObjectName&gt;\r\n  &lt;ObjectType&gt;PROCEDURE&lt;\/ObjectType&gt;\r\n  &lt;TSQLCommand&gt;\r\n    &lt;SetOptions ANSI_NULLS=\"ON\" ANSI_NULL_DEFAULT=\"ON\" ANSI_PADDING=\"ON\" QUOTED_IDENTIFIER=\"ON\" ENCRYPTED=\"FALSE\" \/&gt;\r\n    &lt;CommandText&gt;ALTER PROCEDURE stpControle_versao AS SELECT 'Vers\u00e3o 2.0'\r\n    &lt;\/CommandText&gt;\r\n  &lt;\/TSQLCommand&gt;\r\n&lt;\/EVENT_INSTANCE&gt;\r\n<\/pre>\n<p>O c\u00f3digo do objeto fica entre as tags &lt;CommandText&gt; e &lt;\/CommandText&gt; na mesma formata\u00e7\u00e3o utilizada na cria\u00e7\u00e3o ou altera\u00e7\u00e3o do objeto.<\/p>\n<p>Caso os objetos possuam os caracteres <span style=\"color: #ff0000;\">&#8216;&gt;&#8217;<\/span> e <span style=\"color: #ff0000;\">&#8216;&lt;&#8216;<\/span> em seu script, eles ser\u00e3o substitu\u00eddos no campo XML pelas strings <span style=\"color: #ff0000;\">&#8216;&amp;gt;&#8217;<\/span> e <span style=\"color: #ff0000;\">&#8216;&amp;lt;&#8217;<\/span> respectivamente. Logo, caso voc\u00ea precise subir uma vers\u00e3o antiga de um objeto que possua esses caracteres, deve ser realizado um replace no script do objeto como abaixo:<\/p>\n<ol>\n<li> Copie o texto entre as tags &lt;CommandText&gt; &lt;\/CommandText&gt;\n<li> Abra uma nova query e cole o texto.\n<li> Tecle Ctrl+H e realize o replace de <span style=\"color: #ff0000;\">&#8216;&amp;gt;&#8217;<\/span> por <span style=\"color: #ff0000;\">&#8216;&gt;&#8217;<\/span> de todo o texto.\n<li> Tecle Ctrl+H e realize o replace de <span style=\"color: #ff0000;\">&#8216;&amp;lt;&#8217;<\/span> por <span style=\"color: #ff0000;\">&#8216;&lt;&#8216;<\/span> de todo o texto.\n<li> Tecle F5 para subir o objeto.\n<\/ol>\n<p>Agora que as informa\u00e7\u00f5es de cria\u00e7\u00e3o, altera\u00e7\u00e3o e exclus\u00e3o de objetos est\u00e3o armazenadas em seu banco de dados, \u00e9 poss\u00edvel adicionar mais uma informa\u00e7\u00e3o a planilha do meu primeiro artigo <a title=\"criando-um-checklist-automatico-do-banco-de-dados\/\" href=\"https:\/\/www.fabriciolima.net\/blog\/2010\/03\/24\/criando-um-checklist-automatico-do-banco-de-dados\/\" target=\"_blank\">Criando um CheckList Autom\u00e1tico do Banco de Dados<\/a>. No meu ambiente existe uma aba dessa planilha com as altera\u00e7\u00f5es de objetos realizadas no dia anterior, assim, acompanho diariamente todos os objetos que s\u00e3o alterados no meu Banco de Dados.<\/p>\n<p>Desde quando me mostraram essa nova funcionalidade do SQL Server 2005 eu implementei esse Controle de Vers\u00e3o dos objetos no meu banco de dados. At\u00e9 hoje, j\u00e1 perdi as contas do n\u00famero de vezes que me solicitaram essa informa\u00e7\u00e3o, al\u00e9m de identificar os culpados de alterar um objeto de forma err\u00f4nea.<\/p>\n<p>Espero ter ajudado.<\/p>\n<p>&nbsp;<br \/>\n<b>Gostou desse Post?<\/b><\/p>\n<p>Cadastre seu e-mail para receber novos Posts e curta minha <a href=\"https:\/\/www.facebook.com\/FabricioLimaSolucoesemBancodeDados\/\" target=\"_blank\">P\u00e1gina no Facebook<\/a> para receber Dicas de Leituras e Eventos sobre SQL Server.<\/p>\n<p>Abra\u00e7os,<\/p>\n<p>Fabr\u00edcio Lima<\/p>\n<p>MCITP \u2013 Database Administrator<\/p>\n<p>Consultor e Instrutor SQL Server<\/p>\n<p>Trabalha com SQL Server desde 2006<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Quantas vezes j\u00e1 te perguntaram qual era o c\u00f3digo de uma fun\u00e7\u00e3o, procedure ou view em uma determinada data? At\u00e9 o SQL Server 2000, s\u00f3 era poss\u00edvel obter essa informa\u00e7\u00e3o atrav\u00e9s da gera\u00e7\u00e3o peri\u00f3dica de arquivos com scripts dos objetos do banco de dados. Entretanto, a partir do SQL Server 2005, esse procedimento melhorou com [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"footnotes":""},"categories":[3,280],"tags":[14,52,18,19,23,26,48,33,50,34,35],"class_list":["post-286","post","type-post","status-publish","format-standard","hentry","category-administracao-de-bd","category-virtual-pass-br","tag-auditoria","tag-auditoria-de-sistemas","tag-checklist","tag-controle-de-versao","tag-dba","tag-excel","tag-planilha","tag-sql-server","tag-sql-server-2005","tag-sql-server-2008","tag-sql-server-2008-r2"],"post_mailing_queue_ids":[],"_links":{"self":[{"href":"https:\/\/fabriciolima.net\/blog\/wp-json\/wp\/v2\/posts\/286","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fabriciolima.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fabriciolima.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fabriciolima.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fabriciolima.net\/blog\/wp-json\/wp\/v2\/comments?post=286"}],"version-history":[{"count":0,"href":"https:\/\/fabriciolima.net\/blog\/wp-json\/wp\/v2\/posts\/286\/revisions"}],"wp:attachment":[{"href":"https:\/\/fabriciolima.net\/blog\/wp-json\/wp\/v2\/media?parent=286"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fabriciolima.net\/blog\/wp-json\/wp\/v2\/categories?post=286"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fabriciolima.net\/blog\/wp-json\/wp\/v2\/tags?post=286"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}