DECLARE CURSOR (Transact-SQL)

Aplica-se a: SQL Server Banco de Dados SQL do Azure Instâ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 ] ] ]
[ ; ]

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 da tabela base não são refletidas nos dados retornados pelas buscas feitas para esse 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 com suporte. SCROLL não pode ser especificado se FAST_FORWARD também for especificado. Se SCROLL não for especificado, somente a opção NEXT fetch 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 or DELETE . Essa opção anula a funcionalidade padrão de um cursor para ser atualizado.

ATUALIZAÇÃO [ DE 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 passar 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 as linhas no conjunto de resultados são visíveis à medida que as linhas são buscadas. No entanto, como o cursor não pode ser rolado para trás, as alterações feitas nas linhas do banco de dados depois que a linha foi buscada não são 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, KEYSET, ou 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, inserções, atualizações e exclusões feitas em tabelas base não são refletidas nos dados retornados por buscas feitas para esse cursor, e esse cursor não detecta alterações feitas na associação, ordem ou 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 fazer isso.

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 é criado em uma tabela tempdb conhecida 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 -2 porque a linha excluída aparece como uma lacuna no conjunto de 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 fetch 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 encontrará 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 for 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 or 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 for especificado.

OPTIMISTIC

Especifica que as atualizações ou exclusões posicionadas feitas por meio do cursor não serão bem-sucedidas, se a linha tiver sido atualizada desde que foi lida no cursor. 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.

Se STATIC for especificado junto com o argumento do OPTIMISTIC cursor, a combinação dos dois será implicitamente convertida no equivalente da combinação de argumentos using STATIC and READ_ONLY ou os STATIC argumentos and FORWARD_ONLY .

TYPE_WARNING

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

Nenhum aviso é enviado ao cliente quando a combinação de argumentos de OPTIMISTIC cursor e STATIC é usada e o cursor é convertido implicitamente no equivalente a um STATIC READ_ONLY cursor or STATIC FORWARD_ONLY . A conversão para READ_ONLY se transforma em um FAST_FORWARD cursor e READ_ONLY da perspectiva de um cliente.

select_statement

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

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.

Você não pode misturar as duas formas. Se você especificar as SCROLL palavras-chave or INSENSITIVE antes da CURSOR palavra-chave, não poderá usar palavras-chave entre as CURSOR palavras-chave e FOR <select_statement> . Se você especificar palavras-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 using Transact-SQL não especificar READ_ONLY, OPTIMISTICou SCROLL_LOCKS, o padrão será o seguinte:

  • Se a SELECT instrução não der suporte a atualizações (permissões insuficientes, acesso a tabelas remotas que não dão 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 de 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 de funções ou métodos OLE DB, ODBC ou ADO. As linhas do cursor não podem ser buscadas usando as funções ou métodos de busca 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 Retorna uma lista de cursores atualmente visíveis na conexão e seus atributos.
sp_describe_cursor Descreve os atributos de um cursor, como se ele é um cursor somente para frente ou de rolagem.
sp_describe_cursor_columns Descreve os atributos das colunas no conjunto de resultados do cursor.
sp_describe_cursor_tables Descreve as tabelas base acessadas pelo cursor.

As variáveis podem ser usadas como parte do select_statement que declara um cursor. Os valores da variável 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. Use 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 está 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;