A frase..

"A bondade tornou feliz minha vida."



domingo, 2 de outubro de 2011

Criando Cursor em SQLServer

Faz nem muito tempo estava eu procurando feito uma doida como fazer um cursor em SQL. Encontrei muita coisa, mas como não tive muita facilidade com os exemplos e a sintaxe cruamente exposta, achei interessante postar aqui o que fiz para poder entregar no TP de Banco de Dados que tive de fazer para a faculdade. Já entreguei o TP, mas se alguém tiver uma sugestão para melhorá-lo é sempre bom.

Fazendo Cursor

Primeiro o que é uma cursor? É algo bem simples mesmo no banco de dados existe uma área de memória, que tem o poder de armazenar linhas feitas em um Select. Que linhas são essas? Não tem quando você faz um Select ele apresenta uma sequência de registros, então cada registro desse é uma linha. Voltando um cursor sempre será criado com uma função Select, exatamente pelo motivo explicado acima.. Mesmo que você não saiba, quando você está fazendo um Select a diferença é que você não consegue manipulá-lo. Vamos domá-lo então haha.

Como eu usei uma trigger para criar o cursor vou explicar passo-a-passo:
Primeiro vamos criar a trigger:

create trigger tr_mudancavalor_cursor
on produto
for update <-- Com isso você informa que a Trigger só será executada quando houver um Update
as


Onde tr_mudancavalor_cursor é o nome da trigger e produto e o nome da tabela da qual você pretende que ao fazer um update, a Trigger seja executada.
Agora declaro os ponteiros:

declare p_p Cursor for Select cd_produto,vl_produto from inserted
declare p_p2 Cursor for select vl_produto from deleted


Explicarei agora:
O primeiro e importantíssimo passo é declarar o cursor, se não lógica mente ele não existirá (hiihi). Você vê também p_p que é o nome do cursor. Cursor para o select (essa seria a tradução a grosso modo de Cursor (que é palavra do sistema) for select) dos campos cd_produto, vl_produto da tabelainserted. Viu que legal você pode tirar dados de campos específicos. Inserted é a tabela temporária criada pelo próprio banco quando você faz um insert, um delete ou mesmo o update. A mesma coisa acontece com deleted, que aparece na linha abaixo, também uma declaração de cursor, apenas tendo como diferença que só e criada quando existe um delete ou update.
Prosseguiremos com Trigger normalmente:

--declarando variáveis
declare @CD_PRODUTO INT
declare @qt_estoque int
declare @qt_estoquemin int
declare @vl_novo money
declare @ds_produto varchar(50)
declare @vl_antigo money


Para saber:
declare @vl_antigo(nome da variável) money(tipo da variável, no caso é valor para dinheiro)


Continuando..
Os ponteiros para funcionarem precisam ser abertos:

--abrindo ponteiros
open p_p
open p_p2


Então faço as condições de inserção:

--condições para iserção
begin
--preciso dos valores já para compará-lo, isso quer dizer que está ocorrendo uma alteração
      fetch p_p into @CD_PRODUTO,@vl_novo
      fetch p_p2 into @vl_antigo
      while @@FETCH_STATUS=0
      begin
            fetch p_p into @CD_PRODUTO,@vl_novo
            fetch p_p2 into @vl_antigo
--para saber se o valor não é o mesmo
            if @vl_antigo <> @vl_novo
            begin
                  insert into logpreco (dt_alteracao,cd_produto,vl_produtoant,vl_produtonovo)
                  values (getdate(),@CD_PRODUTO,@vl_antigo, @vl_novo)
            end
      end


O que vem a ser fetch.. Bom vai ser uma informação rápida e indolor: Você vai pegar o valor do ponteiro (p_p ou mesmo p_p2) nos determinados campos desejados que está apontado para o primeiro registro do select e enfiar, é isso mesmo, enfiar nas variáveis(@CD_PRODUTO,@vl_novo ou para p_p2 @vl_antigo) que você criou.
Tá o que eu faço com essa informação?? Agora com esses valores você pode trabalhar cada um deles. No meu caso Eu fui fazer um reajuste de preços na minha tabela de preços, e optei por reajustar todos os preços pelo mesmo novo preço. E quando eu fizer isso a minha Trigger vai colocar os registros dessas alterações em uma tabela de log. Sabe, já testei sem cursor e ao invés de surger o mesmo número de registros alterados, apenas um aparecia, o último a ser analisado pelo select. Então para resolver o problema fiz o seguinte: Criei os dois ponteiros, para permitir que o select seja varrido registro por registro. Tá por que estou frisando isso?? Porque estou querendo dizer que você também poderio usa um loop, mas é bem mais pratico um cursor. Repare no comentários em verde em cima dos fetch. Eles explicam tudo. Repare no comentário embaixo deles eu não queira adicionar registros os quais não tenham sofrido alteração. Opa, mas como isso?? Você não disse que fez alteração no preço de todo mundo?? Sim, sim fiz, mas o que acontece, quem me garante que já não existem preços iguais. Ei, você não explicou uma coisa o que é @@FETCH_STATUS?? Não sei se você percebeu, mas esse tal aí vem acompanhado com o while. Então eu fiz um loop, por quê? Porque enquanto o cursor tiver correndo eu quero saber quando ele vai chegar a 0. Porque zero vai mostrar que não existe mais registros no select. Quando isso acontecer vai sair do while.O insert intologpreco que você vê é para colocar na minha tabela de registros os tais valores que capturei com os meus ponteiros (eles são tão fofuchinhos =** ).

--fechando ponteiros
close p_p
close p_p2
--desalocando os ponteiros
deallocate p_p
deallocate p_p2
end

Assim como você abre o ponteiro é preciso fechá-lo.
O dellocate desaloca o ponteiro. 
Quero comentar que begin e end, trabalham como se fosse {} e getdate() recupera a data do dia, no caso do dia em que o registro foi inserido na tabela de registros. 

Ei, gente espero que tenham gostado. Qualquer mandem sugestões para nathalia_electron@hotmail, com o título da mensagem "cursor - SQLServer".

Xau
Bjins !*

Até a próxima ^^