MCDBA Brasil


  • Home
  • Sobre
  • Contato

Livros





Links Rápidos

SQL Server Builds (All Versions/Editions)


Download SQL Server 2017 (trial)


SQL Server 2017 Feature Pack


SQL Server 2016 Feature Pack


Cumulative Update SQL Server 2017 builds


Cumulative Update SQL Server 2016 builds


Cumulative Update SQL Server 2014 builds


Cumulative Update SQL Server 2012 builds


SQL Server 2005/2008 Samples Databases


Documentando o Servidor SQL Server


Analisando a Performance do Servidor-CheckList


Virtual PASS PT


Faça parte do maior virtual chapter do PASS com conteúdos técnicos em Português sobre SQL Server.

Todos os meses um evento Online para você! Acompanhe aqui os WebCasts já agendados

Sindicalize seu blog ou site ao VirtualPASSPT

SQL Server Blogs

SQL Server Query Processing Team


SQL Programmability & API Development Team


SQL Server Manageability Team


Latin America Support Team


Database + Disk + Performance


Microsoft SQL Server Support


SQL CLR Team


SQL Query Optimization Team


SQL 2005 Code Samples


SQL Server Express Team


SQL SMO Samples


SQL Storage Engine Team


SQL CAT Team


SQL Protocols Team


PSS SQL Server Engineers


Slava Oks on SQLOS


Ken Henderson’s blog


LUTI@Microsoft Blog


kimberly L. Trip’s blog


Fernando Garcia Blog

Artigos

Monitorando Alterações de Dados com a Cláusula OUTPUT

por Nilton Pinheiro maio 5, 2009 Nenhum comentário

Para demonstrar a utilização da cláusula OUTPUT, vou usar como exemplo a tabela Sales.CreditCard do banco de dados AdventureWorks. Esta será a tabela a ser … vamos dizer auditada e terá como finalidade monitorar os usuários que fizeram alterações nos números dos cartões de crétido. O script abaixo é o script original de criação da tabela:

CREATE TABLE [Sales].[CreditCard](
[CreditCardID] [int] IDENTITY(1,1) NOT NULL,
[CardType] [nvarchar](50) NOT NULL,
[CardNumber] [nvarchar](25) NOT NULL,
[ExpMonth] [tinyint] NOT NULL,
[ExpYear] [smallint] NOT NULL,
[ModifiedDate] [datetime] NOT NULL
CONSTRAINT [DF_CreditCard_ModifiedDate]  DEFAULT (getdate()),
CONSTRAINT [PK_CreditCard_CreditCardID] PRIMARY KEY CLUSTERED
([CreditCardID] ASC))


Conhecendo os objetivos e a estrutura da tabela a ser auditada, precisamos então ter uma segunda tabela que será usada para armazenar os dados da auditoria, chamaremos aqui de “tabela espelho”. Uma observação muito importante sobre esta tabela é que para receber as linhas da cláusula OUTPUT ela não pode possuir triggers, check contraints ou qualquer foreign key referenciando suas colunas ou colunas de outras tabelas.


O script apresentado logo abaixo é o script que cria a tabela para auditarmos as operações de INSERT, UPDATE e DELETE sobre a tabela Sales.CreditCard. Notem que esta tabela possui duas entradas para cada coluna da tabela a ser auditada. A coluna com o prefixo INSERT armazenará os dados inseridos e a coluna com o prefixo DELETE os dados excluídos. Outro ponto de observação são as duas últimas colunas do script (INSERT_Usuario e DELETE_Usuario). Estas colunas existem apenas na tabela espelho e serão utilizadas para guardar o nome do usuário que modificou o registro na tabela Sales.CreditCard, para isso usarei a função de sistema SUSER_SNAME() que retorna o nome do usuário que executou a operação.

CREATE TABLE [Sales].[CreditCard_Espelho](
AuditoriaID int IDENTITY(1,1) NOT NULL PRIMARY KEY,
ComandoDML varchar(10),
INSERT_CreditCardID int NULL,
DELETE_CreditCardID int NULL,
INSERT_CardType [nvarchar](50)  NULL,
DELETE_CardType [nvarchar](50)  NULL,
INSERT_CardNumber [nvarchar](25)  NULL,
DELETE_CardNumber [nvarchar](25)  NULL,
INSERT_ExpMonth [tinyint]  NULL,
DELETE_ExpMonth [tinyint]  NULL,
INSERT_ExpYear [smallint]  NULL,
DELETE_ExpYear [smallint]  NULL,
INSERT_ModifiedDate [datetime]  NULL,
DELETE_ModifiedDate [datetime]  NULL,
INSERT_Usuario varchar(50) NULL DEFAULT SUSER_SNAME(),
DELETE_Usuario varchar(50) NULL DEFAULT SUSER_SNAME()
)


Agora que você conhece a estrutura da tabela espelho, use o script abaixo para executar um INSERT sobre a tabela Sales.CreditCard.


— INSERT
INSERT Sales.CreditCard (CardType,CardNumber,ExpMonth,ExpYear,ModifiedDate)
OUTPUT ‘INSERT’,
Inserted.CreditCardID,
Inserted.CardType,
Inserted.CardNumber,
Inserted.ExpMonth,
Inserted.ExpYear,
Inserted.ModifiedDate
INTO Sales.CreditCard_Espelho
(ComandoDML,INSERT_CreditCardID,INSERT_CardType,INSERT_CardNumber,INSERT_ExpMonth,INSERT_ExpYear,
INSERT_ModifiedDate)

VALUES (‘Visa’,’11111111111111′,12,2014,’20090305′)


Note que a cláusula OUTPUT esta posicionada entre as palavras chaves INSERT e VALUES (negrito). Em verdade, observando atentamente é possível notar que a instrução de INSERT é muito semelhante a uma instrução de INSERT qualquer, a grande diferença no uso da cláusula OUTPUT está no fato de ter que acrescentar o bloco destacado em vermelho. Tirando este bloco, a instrução de INSERT ficaria como abaixo:


INSERT Sales.CreditCard (CardType,CardNumber,ExpMonth,ExpYear,ModifiedDate)
VALUES (‘Visa’,’11111111111111′,12,2014,’20090305′)


Outro ponto importante, notem que após o INTO Sales.CreditCard_Espelho tem-se então a lista das colunas da CreditCard_Espelho onde os dados devem ser inseridos. Como a operação de INSERT utiliza apenas a tabela virtual Inserted, a lista de colunas possui apenas as colunas correspondentes.


Assim como uma trigger de INSERT, a cláusula OUTPUT também faz uso da tabela virtual Inserted para obter os dados afetados pela operação DML de INSERT. Quando usamos uma trigger, esta faz uso de duas tabelas chamadas INSERTED e DELETED. Estas tabelas são tabelas virtuais que existem apenas durante o tempo de execução da trigger e podem ser usadas para capturar o antes e depois de uma operação DML. As tabelas são afetadas de forma diferente dependendo da operação DML executada. Abaixo a Tabela mostra o que contém em cada tabela de acordo com a operação DML.





















Operação


Tabela INSERTED contém


Tabela DELETED contém


DELETE


Não possui registros


Registros excluídos


INSERT


Novos registros


Não possui registros


UPDATE


Novos registros


Registros antigos


A cláusula OUTPUT faz uso destas mesmas tabelas virtuais, então quando você executa um INSERT a tabela virtual Inserted possui o dados inseridos na tabela auditada, e a cláusula OUTPUT utiliza a tabela virtual para capturar os dados e inserí-los na tabela CreditCard_Espelho.


O resultado da operação de INSERT sobre a tabela Sales.CreditCard pode ser visto na figura abaixo. Este é obtido executando este script…


SELECT TOP 5 * FROM Sales.CreditCard ORDER BY ModifiedDate DESC


SELECT ComandoDML,INSERT_CreditCardID,INSERT_CardType,INSERT_CardNumber,INSERT_ExpMonth,INSERT_ExpYear,
INSERT_ModifiedDate, INSERT_Usuario
FROM Sales.CreditCard_Espelho


Observe que o novo registro foi inserido sobre a tabela Sales.CreditCard e ao mesmo tempo um registro também foi inserido sobre a tabela
Sales.CreditCard_Espelho indicando ainda o usuário que executou a operação.


Para uma operação de UPDATE, o que muda é que devemos pegar os dados não apenas da tabela Inserted, mas também da tabela deleted. Isso porque quando ocorre uma operação de UPDATE o que ocorre na prática é a exclusão do dados antigos e a inclusão dos novos dados, com isso durante uma operação de UPDATE a tabela Inserted armazena os novos dados e a tabela deleted armazena os dados antigos ou excluídos.
Observando o script abaixo você notará que na lista de colunas passada à cláusula OUTPUT estou usando não apenas a tabela Inserted, mas também a Deleted (bloco laranja). No mais, observe que após o INTO Sales.CreditCard_Espelho informo não apenas as colunas de prefixo INSERT, mas também as de prefixo DELETE.


— UPDATE
UPDATE Sales.CreditCard
SET CardNumber= ‘11111111111122’
OUTPUT ‘UPDATE’,
Inserted.CreditCardID,
Deleted.CreditCardID,
Inserted.CardType,
Deleted.CardType,
Inserted.CardNumber,
Deleted.CardNumber,
Inserted.ExpMonth,
Deleted.ExpMonth,
Inserted.ExpYear,
Deleted.ExpYear,
Inserted.ModifiedDate,
Deleted.ModifiedDate

INTO Sales.CreditCard_Espelho
(ComandoDML,INSERT_CreditCardID,DELETE_CreditCardID,INSERT_CardType,DELETE_CardType,
INSERT_CardNumber,DELETE_CardNumber,INSERT_ExpMonth,DELETE_ExpMonth,INSERT_ExpYear,DELETE_ExpYear,
INSERT_ModifiedDate,DELETE_ModifiedDate)
WHERE CreditCardID=19249


O resultado da operação de UPDATE pode ser visto na figura abaixo. Note que na tabela Sales.CreditCard o número do cartão de crédito para o CreditCardID 19249 foi alterado de 11111111111111 para 11111111111122. Na tabela de auditoria CreditCard_Espelho podemos notar que tanto as colunas de prefixo INSERT quanto de prefixo DELETE foram preenchidas. Na coluna DELETE_CreditCrad temos o número antes da alteração e na coluna INSERT_CredtCard o novo número do cartão de crédito. 


O resultado e obtido executando este script…


SELECT TOP 5 * FROM Sales.CreditCard ORDER BY ModifiedDate DESC


SELECT ComandoDML,INSERT_CreditCardID,INSERT_CardType, INSERT_CardNumber,INSERT_ExpMonth,INSERT_ExpYear,
INSERT_ModifiedDate, INSERT_Usuario
FROM Sales.CreditCard_Espelho


SELECT ComandoDML,DELETE_CreditCardID,DELETE_CardType, DELETE_CardNumber,DELETE_ExpMonth,DELETE_ExpYear,
DELETE_ModifiedDate, DELETE_Usuario
FROM Sales.CreditCard_Espelho



Para finalizar, um exemplo demonstrando o uso da cláusula OUTPUT em uma operação de DELETE. Como vocês já devem ter notado, para uma operação de DELETE apenas as colunas com prefixo DELETE para a tabela CreditCard_Espelho serão preenchida. O script para a operação de DELETE pode ser visto abaixo e o exemplo exclui registro de CreditCardID 19249 da tabela Sales.CreditCard


— DELETE
DELETE FROM Sales.CreditCard
OUTPUT ‘DELETE’,
Deleted.CreditCardID,
Deleted.CardType,
Deleted.CardNumber,
Deleted.ExpMonth,
Deleted.ExpYear,
Deleted.ModifiedDate
INTO Sales.CreditCard_Espelho
(ComandoDML,DELETE_CreditCardID,DELETE_CardType, DELETE_CardNumber,DELETE_ExpMonth,DELETE_ExpYear,
DELETE_ModifiedDate)
WHERE CreditCardID=19249


Podemos ver o resultado da operação na figura abaixo. Note que o registro de CreditCardID 19249 foi excluído da tabela principal Sales.CreditCard. Para a tabela Sales.CreditCard_Espelho podemos notar também que as colunas de prefixo INSERT estão como NULL, isso ocorre porque para operações de DELETE não há inserção de novos dados. Já para as colunas de prefixo DELETE, temos o registro dos dados excluídos e quem o excluiu.



Dicas para a utilização do OUTPUT


Como vocês devem ter notado, a cláusula OUTPUT pode ser utilizada nas instruções Transact-SQL de INSERT, UPDATE ou DELETE. Isso proporciona uma excelente flexibilidade, pois podemos utilizá-la apenas nas instruções que desejamos monitorar. Desta forma, qualquer processo que tenha permissão para modificar uma tabela pode usar a cláusula OUTPUT para popular a tabela de auditoria. Algumas boas práticas para a utilização da cláusula OUTPUT são as seguintes:


1) Remover qualquer permissão de acesso direto à tabela de auditada;
2) Escrever todas as operações de INSERT, UPDATE e DELETE dentro de stored procedures;
3) Atribuir as permissões apenas nas stored procedures;


Seguir estas boas práticas garantirá que o usuário só conseguirá executar as operações através das stored procedures e consequentemente não executará nenhuma operação sem passar pela auditoria. O ponto de atenção ao trabalhar com a cláusula OUTPUT está em ficar sempre atento para não esquecer e fazer as devidas modificações nas procedures quando houver mudanças na estrutura da tabela auditada ou até mesmo não esquecer da cláusula quando estiver escrevendo novas procedures.

Para evitar este problema, minha sugestão é que sejam criadas regras que definam os passos envolvidos para a modificação ou criação de operações que envolvam tabelas que precisem ser auditadas.


É verdade que ao invéz de trabalhar com a cláusula OUTPUT você também poderia executar esta auditoria usando triggers sobre a tabela a ser auditada, no entando, quando trabalhamos com triggers, além de termos os problemas de overhead sobre as tabelas afetas ainda temos que nos preocupar em lembrar das trigger sempre que modificamos as tabelas ou geramos scripts de criação das tabelas. Este problema não existe com a utilização da cláusula OUTPUT pois tudo está dentro das próprias procedures que executam as operações de INSERT, UPDATE e DELETE. Se você alterar a tabela auditada, certamente terá que alterar também as procedures que executam estas operações e neste momento verá a cláusula OUTPUT. Se você gerar script de criação das tabelas, certamente irá gerar também os scripts de criação das procedures e mais uma vez estará lá a cláusula OUTPUT.


É isso aí pessoal, abraço e até…


Nilton Pinheiro

Avaliação:
Compartilhe:
  • Anterior Liberado o Cumulative Update 1 para o SQL Server 2008 SP117 anos atrás
  • Próximo Microsoft Adiciona Suporte a Lock Pages In Memory no CU2 do SQL Server 2008 SP117 anos atrás

Deixe uma resposta Cancelar resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

MVP Reconnect Award

Categorias

  • Artigos (359)
  • Dica da Semana (95)
  • Documentação (54)
  • Downloads (113)
  • MSDE 2000 (3)
  • Sem categoria (1)
  • Tutoriais (9)

Posts recentes

  • #FechouBrasil #PartiuPortugal
  • Brigando com o erro “The cached MSI file is missing”
  • MCDBABRASIL está de volta
  • Documentando o Servidor SQL Server
  • Brigando com os Erros 17182, 17826 e 17120

SQL Server AlwaysOn Video Series

Video1: Introdução ao SQLServer2012 AlwaysOn


Video2: Introdução ao SQLServer2012 AlwaysOn Availability Group


Video3: Introdução ao SQLServer2012 AlwaysOn AVG-Demo


Video4: Introdução ao SQLServer2012 AlwaysOn Listener


Video5: Introdução ao SQLServer2012 AlwaysOn Readable Secondaries


Video6: Introdução ao SQLServer2012 AlwaysOn Readable Secondaries-Demo


Video7: Introdução ao SQLServer2012 AlwaysOn Failover Clustering


Serie SQL Server Failover Clustering End-to-End

Parte 1: Configuração da Rede e Ambiente


Parte 2: Configurando o Windows 2008 R2 Domain Controler e DNS


Parte 3: Preparando os nós para o Failover Cluster


Parte 4: Configurando um Failover Cluster de 2 nós


Parte 5: Configurando as LUNs no iSCSI Software Target (Parte 1)


Parte 6: Configurando as LUNs no iSCSI Software Target (Parte 2)


Parte 7: Apresentando as LUNs para os nós do Failover Cluster


Parte 8: Configurando os discos no Failover Cluster


Parte 9: Instalando a primeira instância virtual do SQL Server 2008


Parte 10: Instalando a segunda instância virtual do SQL Server 2008


Parte 11: Instalando e Configurando o MSDTC no Failover Cluster


Parte 12: Configurando Mount Points no Cluster e SQL Server 2008


Vídeo Extra: Removendo uma Instância do SQL Server 2008 R2 em Cluster


Alta Disponibilidade no SQL Server 2008 R2: Failover Clustering Overview


Alta Disponibilidade no SQL Server 2008 R2: Failover Clustering na Prática

Menu

  • Home
  • Sobre
  • Contato

Mais

  • RSS Feeds
2026 MCDBA Brasil.