Padrão de Projeto: Usando Listas ao invés de Cursores em Transact-SQL

Já li muitos autores falarem sobre evitar o uso de cursores no código T-SQL por questões de performance. Então resolvi dar minha contribuição para a discussão apresentando um padrão que tenho usado em meu projeto no trabalho. Não acho que esta solução seja uma panacéia para evitar todo uso de cursores. Muito menos acho que é a melhor solução. É apenas uma solução que me sinto mais à vontade usando. Achei legal compartilhá-la e por isso humildemente a apresento para a comunidade debater e melhorar.

Descrição do Problema

Algumas vezes deparamo-nos com a tarefa de fazer um loop em um conjunto de valores retornados através de um select. A solução mais óbvia é usar cursores. Não quero aqui discutir o porquê de evitar cursores, afinal existe grande literatura sobre o assunto.

Solução

Use listas para percorrer um pequeno subconjunto de valores ao invés de declarar cursores, alocá-los, etc. A alternativa que proponho é usar tabelas temporárias para simular o conceito de listas e/ou arrays. A tarefa se torna mais simples porque eu estou mais acostumado à sintaxe e a organização do código em loops com a utilização de contadores como condição para sair do loop. Quem não escreveu um loop para percorrer um RecordSet (ADO) ou um Dataset (Delphi) usando um while not Eof?

Exemplo

Suponha que você queira chamar uma stored procedure para cada registro de um subconjunto de uma tabela. Cada registro é identificado por um inteiro, que na linguagem relacional representa uma chave primária em uma tabela. Podemos criar uma lista de inteiros ou um array de inteiros, como quiser (me desculpem os professores de estruturas de dados, as características conceituais de cada tipo de dado aqui não faz diferença) para armazenar este subconjunto de chaves primárias. E fazemos isto através de uma tabela temporária no Transact-SQL.

declare @rowCount int
declare @idItem int
create #Lista (id int)
insert into #Lista select id from Tabela where Condicao=True
set @rowCount = @@ROWCOUNT

No código acima declarei o contador que será a condição para saída do loop e a variável que armazenará o id do item no loop, depois criei uma tabela temporária (identificada pelo prefixo #) para armazenar a lista e em seguida preenchi a linha com o subconjunto identificado por Condicao=True. Finalmente inicializei a variável @rowCount com o total de linhas do subconjunto.

A partir daí podemos percorrer a lista com o loop while:

while @rowCount>0 begin
select top 1 @idItem = select id from #Lista
exec AlgumaSP( @idItem )
delete from #Lista where id = @idItem
set @rowCount = @rowCount - 1
end


No loop temos sempre este padrão:

  1. Recuperar o id do item corrente utilizando select top 1
  2. Chamar a stored procedure com o id do item corrente
  3. Excluir o item da lista
  4. Decrementar o contador

É isso, galera. É um código muito específico mas para mim tem sido mais intuitivo do que a utilização de cursores em situações como esta. E vocês, o que acharam? Comentem!

Anúncios

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s