DECLARE CURSOR (Transact-SQL)

Aplica-se a:SQL ServerBanco de Dados SQL do AzureInstância Gerenciada de SQL do Azure

Define os atributos de um cursor de servidor Transact-SQL, como seu comportamento de rolagem e a consulta usada para criar o conjunto de resultados no qual o cursor funciona. DECLARE CURSOR aceita uma sintaxe fundada no padrão ISO e uma sintaxe que usa um conjunto de extensões Transact-SQL.

Convenções de sintaxe de Transact-SQL

Sintaxe

Sintaxe ISO:

DECLARE cursor_name [ INSENSITIVE ] [ SCROLL ] CURSOR
    FOR select_statement
    [ FOR { READ ONLY | UPDATE [ OF column_name [ , ...n ] ] } ]
[ ; ]

Sintaxe estendida do Transact-SQL:

DECLARE cursor_name CURSOR [ LOCAL | GLOBAL ]
    [ FORWARD_ONLY | SCROLL ]
    [ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ]
    [ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ]
    [ TYPE_WARNING ]
    FOR select_statement
    [ FOR UPDATE [ OF column_name [ , ...n ] ] ]
[ ; ]

Observação

Para exibir a sintaxe do Transact-SQL para o SQL Server 2014 (12.x) e versões anteriores, confira a Documentação das versões anteriores.

Argumentos

cursor_name

O nome do cursor do servidor Transact-SQL definido. cursor_name deve estar em conformidade com as regras de identificadores.

INSENSITIVE

Define um cursor que faz uma cópia temporária dos dados a serem usados por ele. Todas as solicitações para o cursor são respondidas a partir desta tabela temporária no tempdb. Portanto, as modificações feitas nas tabelas base não são refletidas nos dados retornados pelas buscas feitas nesse cursor, e esse cursor não permite modificações. Quando a sintaxe de ISO é usada, se INSENSITIVE for omitido, exclusões e atualizações confirmadas nestas tabelas subjacentes (por qualquer usuário) serão refletidas em buscas subsequentes.

SCROLL

Especifica que todas as opções de busca (FIRST, LAST, PRIOR, NEXT, RELATIVE, ABSOLUTE) estão disponíveis. Se SCROLL não for especificado em um ISO DECLARE CURSOR, NEXT é a única opção de busca suportada. SCROLL não pode ser especificado se FAST_FORWARD também for especificado. Se SCROLL não for especificado, somente a opção NEXT de busca estará disponível e o cursor se tornará FORWARD_ONLY.

select_statement

Uma instrução padrão SELECT que define o conjunto de resultados do cursor. As palavras-chave FOR BROWSEe INTO não são permitidas dentro de select_statement de uma declaração de cursor.

O SQL Server converte o cursor implicitamente em outro tipo se as cláusulas em select_statement entram em conflito com a funcionalidade do tipo de cursor solicitado.

READ ONLY

Previne atualizações feitas por este cursor. O cursor não pode ser referenciado em uma WHERE CURRENT OF cláusula em uma UPDATE instrução ou DELETE . Essa opção anula a funcionalidade padrão de um cursor para ser atualizado.

UPDATE [ OF column_name [ ,...n ] ]

Define colunas atualizáveis em um cursor. Se OF <column_name> [, <... n> ] for especificado, somente as colunas listadas permitirão modificações. Se UPDATE for especificada sem uma lista de colunas, todas as colunas poderão ser atualizadas.

cursor_name

O nome do cursor do servidor Transact-SQL definido. cursor_name deve estar em conformidade com as regras de identificadores.

LOCAL

Especifica que o escopo do cursor é local para o lote, procedimento armazenado ou gatilho no qual o cursor foi criado. O nome de cursor só é válido dentro desse escopo. O cursor pode ser referenciado por meio de variáveis de cursor local no lote, no procedimento armazenado ou no gatilho ou em um parâmetro OUTPUT do procedimento armazenado. Um parâmetro OUTPUT é usado para repassar o cursor local para o lote de chamada, o procedimento armazenado ou o gatilho, que pode atribuir o parâmetro a uma variável do cursor para fazer referência ao cursor após o procedimento armazenado terminar. O cursor é implicitamente desalocado quando o lote, o procedimento armazenado ou o gatilho é encerrado, a menos que o cursor tenha sido repassado como um parâmetro OUTPUT. Se ele for passado de volta em um OUTPUT parâmetro, o cursor será desalocado quando a última variável que faz referência a ele for desalocada ou sair do escopo.

GLOBAL

Especifica que o escopo do cursor é global para a conexão. O nome do cursor pode ser referenciado em qualquer procedimento armazenado ou lote executado pela conexão. O cursor só é desalocado implicitamente na desconexão.

Observação

Se nem GLOBAL nem LOCAL forem especificados, o padrão será controlado pela definição da opção padronizar para cursor local do banco de dados.

FORWARD_ONLY

Especifica se o cursor só pode se mover para frente e ser rolado da primeira à última linha. FETCH NEXT é a única opção de busca compatível. Todas as instruções de inserção, atualização e exclusão feitas pelo usuário atual (ou confirmadas por outros usuários) que afetam linhas no conjunto de resultados ficam visíveis à medida que as linhas são buscadas. Como o cursor não pode ser rolado para trás, no entanto, as alterações feitas nas linhas no banco de dados depois que a linha foi buscada não ficam visíveis por meio do cursor. Cursores somente de avanço são dinâmicos por padrão, o que significa que todas as alterações são detectadas conforme a linha atual é processada. Isso permite uma abertura do cursor mais rápida e que o conjunto de resultados exiba as atualizações feitas nas tabelas subjacentes. Embora os cursores somente para frente não ofereçam suporte à rolagem para trás, os aplicativos podem retornar ao início do conjunto de resultados fechando e reabrindo o cursor.

Se FORWARD_ONLY for especificado sem as palavras-chave STATIC, KEYSET ou DYNAMIC, o cursor operará como um cursor dinâmico. Quando FORWARD_ONLY ou SCROLL não são especificados, FORWARD_ONLY é o padrão, a menos que as palavras-chave STATIC, KEYSETou DYNAMIC sejam especificadas. Os cursores STATIC, KEYSET e DYNAMIC utilizam SCROLL como padrão. Ao contrário de APIs de banco de dados, como ODBC e ADO, FORWARD_ONLY é compatível com os cursores Transact-SQL STATIC, KEYSET e DYNAMIC.

STATIC

Especifica que o cursor sempre exibe o conjunto de resultados como ele era quando o cursor foi aberto pela primeira vez e faz uma cópia temporária dos dados a serem usados pelo cursor. Todas as solicitações para o cursor são respondidas a partir desta tabela temporária no tempdb. Portanto, as inserções, atualizações e exclusões feitas nas tabelas base não são refletidas nos dados retornados pelas buscas feitas nesse cursor, e esse cursor não detecta as alterações feitas na associação, na ordem ou nos valores do conjunto de resultados depois que o cursor é aberto. Os cursores estáticos podem detectar suas próprias atualizações, exclusões e inserções, embora não sejam obrigados a fazê-lo.

Por exemplo, suponha que um cursor estático busque uma linha e outro aplicativo então atualize a linha. Se o aplicativo buscar novamente a linha do cursor estático, os valores que ele verá estarão inalterados, apesar das alterações feitas por outro aplicativo. Há suporte para todos os tipos de rolagem.

KEYSET

Especifica que a associação e a ordem de linhas no cursor são fixas, quando o cursor é aberto. O conjunto de chaves que identifica exclusivamente as linhas é incorporado em uma tabela conhecida tempdb como conjunto de chaves. Esse cursor fornece funcionalidades entre um cursor dinâmico e um cursor estático em sua capacidade de detectar alterações. Como um cursor estático, ele nem sempre detecta alterações na associação e na ordem do conjunto de resultados. Como um cursor dinâmico, ele detecta alterações aos valores de linhas no conjunto de resultados.

Os cursores controlados por conjuntos de chaves são controlados por um conjunto exclusivo de identificadores (chaves) conhecido como conjunto de chaves. As chaves são criadas a partir de um conjunto de colunas, que identificam exclusivamente as linhas no conjunto de resultados. O conjunto de chaves é o conjunto de valores de chave de todas as linhas retornadas pela instrução de consulta. Com cursores controlados por conjunto de chaves, uma chave é criada e salva para cada linha do cursor e armazenada na estação de trabalho cliente ou no servidor. Quando você acessa cada linha, a chave armazenada é usada para buscar os valores de dados atual da fonte de dados. Em um cursor controlado por conjunto de chaves, a associação do conjunto de resultados é congelada quando o conjunto de chaves está completamente preenchido. Depois disso, as adições ou atualizações que afetam a associação não fazem parte do conjunto de resultados até que ele seja reaberto.

Alterações nos valores de dados (feitas por outros processos ou pelo proprietário do conjunto de chaves) são visíveis conforme o usuário rola pelo conjunto de resultados:

  • Se uma linha for excluída, uma tentativa de buscar a linha retornará um @@FETCH_STATUS de porque a linha excluída aparece como uma lacuna no conjunto de -2 resultados. A chave para a linha existe no conjunto de chaves, mas a linha não existe mais no conjunto de resultados.

  • Inserções feitas fora do cursor (por outros processos) serão visíveis apenas se o cursor for fechado e reaberto. Inserções feitas de dentro do cursor são visíveis no final do conjunto de resultados.

  • Atualização de valores de chave externos ao cursor lembram a exclusão de uma linha antiga, seguida de uma inserção de uma nova linha. A linha com os novos valores não está visível e as tentativas de buscar a linha com os valores antigos retornam um @@FETCH_STATUS de -2. Os novos valores ficarão visíveis se a atualização for feita por meio do cursor especificando a cláusula WHERE CURRENT OF.

Observação

Se a consulta referencia ao menos uma tabela sem um índice exclusivo, o cursor controlado por conjunto de chaves é convertido a um cursor estático.

DYNAMIC

Define um cursor que reflete todas as alterações de dados feitas às linhas em seu conjunto de resultados conforme você rola o cursor e busque um novo registro, não importa se as alterações ocorrem de dentro do cursor ou são feitas por outros usuários fora do cursor. Portanto, todas as instruções insert, update e delete feitas por todos os usuários são visíveis por meio do cursor. Os valores de dados, a ordem e a associação das linhas podem ser alterados em cada busca. A ABSOLUTE opção de busca não é compatível com cursores dinâmicos. As atualizações feitas fora do cursor não ficam visíveis até que sejam confirmadas (a menos que o nível de isolamento da transação do cursor esteja definido como UNCOMMITTED).

Por exemplo, suponha que um cursor dinâmico busque duas linhas e outro aplicativo atualize uma dessas linhas e exclua a outra. Se o cursor dinâmico buscar essas linhas, ele não localizará a linha excluída, mas exibirá os novos valores para a linha atualizada.

FAST_FORWARD

Especifica um cursor FORWARD_ONLY, READ_ONLY com otimizações de desempenho habilitadas. FAST_FORWARD não pode ser especificado se SCROLL ou FOR_UPDATE também é especificado. Esse tipo de cursor não permite modificações de dados de dentro do cursor.

Observação

FAST_FORWARD e FORWARD_ONLY podem ser usados na mesma instrução DECLARE CURSOR.

READ_ONLY

Previne atualizações feitas por este cursor. O cursor não pode ser referenciado em uma WHERE CURRENT OF cláusula em uma UPDATE instrução ou DELETE . Essa opção anula a funcionalidade padrão de um cursor para ser atualizado.

SCROLL_LOCKS

Especifica se atualizações posicionadas ou exclusões feitas pelo cursor têm garantia de êxito. O SQL Server bloqueia as linhas à medida que são lidas no cursor para assegurar a disponibilidade para modificações posteriores. SCROLL_LOCKS não pode ser especificado se FAST_FORWARD ou STATIC também é especificado.

OPTIMISTIC

Especifica que as atualizações posicionadas ou exclusões feitas por meio do cursor não serão bem-sucedidas se a linha tiver sido atualizada desde que foi lida no cursor. O SQL Server não bloqueia linhas à medida que são lidas no cursor. Em vez disso, ele usa comparações de valores de coluna timestamp ou um valor de soma de verificação se a tabela não tem nenhuma coluna timestamp, para determinar se a linha foi modificada depois de ser lida no cursor. Se a linha tiver sido modificada, a tentativa de atualização ou exclusão posicionada falhará. OPTIMISTIC não pode ser especificado se FAST_FORWARD também for especificado.

TYPE_WARNING

Especifica que uma mensagem de aviso é enviada ao cliente quando o cursor é convertido implicitamente em outro a partir do tipo solicitado.

select_statement

Uma instrução padrão SELECT que define o conjunto de resultados do cursor. As palavras-chave , , e não são permitidas dentro de select_statement de uma declaração de cursor.INTOFOR BROWSECOMPUTE BYCOMPUTE

Observação

Você pode usar uma dica de consulta em uma declaração de cursor. No entanto, se você também usar a FOR UPDATE OF cláusula, especifique OPTION (<query_hint>) após FOR UPDATE OF.

O SQL Server converte o cursor implicitamente em outro tipo se as cláusulas em select_statement entram em conflito com a funcionalidade do tipo de cursor solicitado.

PARA ATUALIZAÇÃO [ DE column_name [ ,...n ] ]

Define colunas atualizáveis em um cursor. Se OF <column_name> [, <... n>] for fornecido, somente as colunas listadas permitirão modificações. Se UPDATE for especificado sem uma lista de colunas, todas as colunas poderão ser atualizadas, a não ser que a opção de simultaneidade READ_ONLY seja especificada.

Comentários

DECLARE CURSOR define os atributos de um cursor de servidor Transact-SQL, como seu comportamento de rolagem e a consulta usada para criar o conjunto de resultados no qual o cursor funciona. A instrução OPEN popula o conjunto de resultados e FETCH retorna uma linha do conjunto de resultados. A instrução CLOSE libera o conjunto de resultados atual associado ao cursor. A instrução DEALLOCATE libera os recursos usados pelo cursor.

O primeiro formulário da instrução DECLARE CURSOR usa a sintaxe ISO para declarar comportamentos do cursor. A segunda forma de DECLARE CURSOR usa extensões Transact-SQL que lhe permitem definir cursores com os mesmos tipos de cursores usados nas funções de cursor de API do banco de dados ODBC ou ADO.

Não é possível misturar as duas formas. Se você especificar as SCROLL palavras-chave ou INSENSITIVE antes da CURSOR palavra-chave, não poderá usar nenhuma palavra-chave entre as CURSOR palavras-chave e FOR <select_statement> . Se você especificar qualquer palavra-chave entre as CURSOR palavras-chave e FOR <select_statement> , não poderá especificar SCROLL ou INSENSITIVE antes da CURSOR palavra-chave.

Se uma DECLARE CURSOR sintaxe de uso do Transact-SQL não especificar READ_ONLY, OPTIMISTICou SCROLL_LOCKS, o padrão será o seguinte:

  • Se a SELECT instrução não oferecer suporte a atualizações (permissões insuficientes, acesso a tabelas remotas que não oferecem suporte a atualizações e assim por diante), o cursor será READ_ONLY.

  • Os cursores STATIC e FAST_FORWARD utilizam READ_ONLY como padrão.

  • Os cursores DYNAMIC e KEYSET utilizam OPTIMISTIC como padrão.

Os nomes dos cursor só podem ser referenciados por outras instruções Transact-SQL. Eles não podem ser referenciados por funções de API de banco de dados. Por exemplo, depois de declarar um cursor, o nome do cursor não pode ser referenciado a partir de funções ou métodos OLE DB, ODBC ou ADO. As linhas do cursor não podem ser buscadas usando as funções de busca ou métodos das APIs; as linhas só podem ser buscadas por instruções Transact-SQL FETCH .

Depois que um cursor é declarado, esses procedimentos armazenados do sistema podem ser usados para determinar as características do cursor.

Procedimentos armazenados do sistema Descrição
sp_cursor_list (Transact-SQL) Retorna uma lista de cursores atualmente visíveis na conexão e seus atributos.
sp_describe_cursor (Transact-SQL) Descreve os atributos de um cursor, como se ele é um cursor somente para frente ou rolagem.
sp_describe_cursor_columns (Transact-SQL) Descreve os atributos das colunas no conjunto de resultados do cursor.
sp_describe_cursor_tables (Transact-SQL) Descreve as tabelas base acessadas pelo cursor.

As variáveis podem ser usadas como parte do select_statement que declara um cursor. Os valores das variáveis do cursor não são alterados depois que um cursor é declarado.

Permissões

Permissões de DECLARE CURSOR seguem o padrão para todo usuário que tem permissões SELECT para exibições, tabelas e colunas usadas no cursor.

Limitações

Não é possível usar cursores nem gatilhos em uma tabela com um índice columnstore clusterizado. Essa restrição não se aplica a índices columnstore não clusterizados. Você pode usar cursores e gatilhos em uma tabela com um índice columnstore clusterizado.

Exemplos

R. Usar cursor e sintaxe básicos

O conjunto de resultados gerado na abertura deste cursor inclui todas as linhas e todas as colunas na tabela. Este cursor pode ser atualizado e todas as atualizações e exclusões são representadas em buscas feitas no cursor. FETCH NEXT é a única busca disponível porque a SCROLL opção não é especificada.

DECLARE vend_cursor CURSOR
    FOR SELECT * FROM Purchasing.Vendor
OPEN vend_cursor
FETCH NEXT FROM vend_cursor;

B. Usar cursores aninhados para produzir saída de relatório

O exemplo a seguir mostra como cursores podem ser aninhados para produzir relatórios complexos. O cursor interno é declarado para cada vendedor.

SET NOCOUNT ON;

DECLARE @vendor_id INT, @vendor_name NVARCHAR(50),
    @message VARCHAR(80), @product NVARCHAR(50);

PRINT '-------- Vendor Products Report --------';

DECLARE vendor_cursor CURSOR FOR
SELECT VendorID, Name
FROM Purchasing.Vendor
WHERE PreferredVendorStatus = 1
ORDER BY VendorID;

OPEN vendor_cursor

FETCH NEXT FROM vendor_cursor
INTO @vendor_id, @vendor_name

WHILE @@FETCH_STATUS = 0
BEGIN
    PRINT ' '
    SELECT @message = '----- Products From Vendor: ' +
        @vendor_name

    PRINT @message

    -- Declare an inner cursor based
    -- on vendor_id from the outer cursor.

    DECLARE product_cursor CURSOR FOR
    SELECT v.Name
    FROM Purchasing.ProductVendor pv, Production.Product v
    WHERE pv.ProductID = v.ProductID AND
    pv.VendorID = @vendor_id  -- Variable value from the outer cursor

    OPEN product_cursor
    FETCH NEXT FROM product_cursor INTO @product

    IF @@FETCH_STATUS <> 0
        PRINT '         <<None>>'

    WHILE @@FETCH_STATUS = 0
    BEGIN

        SELECT @message = '         ' + @product
        PRINT @message
        FETCH NEXT FROM product_cursor INTO @product
        END

    CLOSE product_cursor
    DEALLOCATE product_cursor
        -- Get the next vendor.
    FETCH NEXT FROM vendor_cursor
    INTO @vendor_id, @vendor_name
END
CLOSE vendor_cursor;
DEALLOCATE vendor_cursor;