No SQL, os cursores servem como um ponteiro que permite que a linguagem de programação de aplicativos lide com os resultados da consulta uma linha por vez. Este artigo explora rapidamente o conceito por trás e mostra como declarar cursores, abrir, recuperar dados deles e fechá-los.
Cursores SQL
Os dados no banco de dados relacional são gerenciados na forma de conjuntos. Como resultado, os resultados da consulta retornados por instruções SQL SELECT são chamados de conjuntos de resultados. Os conjuntos de resultados nada mais são do que combinações de uma ou mais linhas e colunas extraídas de uma ou mais tabelas. Você pode rolar pelos conjuntos de resultados para extrair as informações necessárias. Os elementos de dados retornados são usados por linguagens de programação como Java ou qualquer outra para fins de aplicação específicos. Mas aqui reside o problema da incompatibilidade de impedância devido à diferença de construção entre o modelo de banco de dados e o modelo de linguagem de programação.
Um modelo de banco de dados SQL tem três construções principais:
- colunas (ou atributos) e seus tipos de dados
- linhas (registros ou tuplas)
- tabelas (coleção de registros)
Portanto, a incompatibilidade primária entre dois modelos são:
- Os tipos de dados de atributo disponíveis no modelo de banco de dados não são os mesmos que os tipos de variáveis usados em linguagens de programação. Existem muitos idiomas de host e cada um tem um tipo de dados diferente. Por exemplo, os tipos de dados de C/C++ e Java são diferentes, assim como os tipos de dados SQL. Portanto, é necessário um mecanismo de vinculação para mitigar o problema de incompatibilidade.
- O resultado retornado pelas instruções SQL SELECT são multiconjuntos de registros em que cada registro é uma coleção de atributos. As linguagens de programação de host geralmente funcionam em valores de dados individuais de tupla retornados pela consulta. Portanto, é essencial que o resultado da consulta SQL mapeie com a estrutura de dados suportada pela linguagem de programação. O mecanismo de loop sobre tuplas é necessário para iterar sobre tuplas e seus valores de atributo.
O cursor age como uma variável iteradora para fazer um loop sobre as tuplas retornadas pela consulta SQL e extrair valores individuais dentro de cada tupla que podem ser mapeados para o tipo apropriado de variáveis de programa.
O cursor, portanto, serve como um ponteiro que permite que a linguagem de programação processe o resultado da consulta um registro por vez. Um cursor pode percorrer todas as linhas de um resultado de consulta com foco em uma linha por vez. Considere a seguinte consulta SQL:
SELECT emp_no, first_name, last_name, birth_date FROM employees WHERE MONTH(birth_date) = MONTH(CURRENT_DATE) AND DAY(birth_date) = DAY(CURRENT_DATE);
O resultado da consulta da instrução acima retorna detalhes de todos os funcionários cuja data de nascimento cai no dia atual de um determinado mês. O resultado pode conter muitas linhas, mas a linguagem do aplicativo host pode lidar com uma linha por vez. Como resultado, o cursor é declarado como uma instrução SQL incorporada na linguagem de programação do aplicativo. O cursor é aberto como um arquivo e extrai uma única linha do resultado da consulta. Outras linhas são extraídas posteriormente, em sequência, até que o cursor seja fechado.
Declarando um cursor
Os cursores são declarados como uma variável. Um nome é dado, há instruções para abrir o cursor, recuperar o resultado da consulta e, finalmente, fechar o cursor. Observe que diferentes implementações de SQL suportam o uso de cursores de maneira diferente. Mas há um acordo geral sobre como o cursor deve ser escrito.
Devemos usar instruções SQL para implementar totalmente a funcionalidade do cursor porque simplesmente declarar um cursor não é suficiente para extrair dados de um banco de dados SQL. Há quatro etapas básicas para declarar um cursor:
DECLARAR CURSOR: A declaração começa dando um nome ao cursor e atribuindo a expressão de consulta a ser invocada quando o cursor for aberto.
ABRIR: A instrução open executa a expressão de consulta atribuída e prepara o resultado da consulta para FETCH subsequente.
BUSCAR: Recupera valores de dados em variáveis que podem ser passadas para a linguagem de programação do host ou para outras instruções SQL incorporadas.
FECHAR: O cursor está fechado para buscar mais resultados de consulta.
A sintaxe é a seguinte:
DECLARE <cursor_name> [SENSITIVE | INSENSITIVE | ASENSITIVE] [SCROLL | NO SCROLL] CURSOR [ WITH HOLD | WITHOUT HOLD] [ WITH RETURN | WITHOUT RETURN] FOR <sql_query_expression> [ ORDER BY <sort_expression>] [ FOR {READ ONLY | UPDATE [ OF <list_of_column>]}]
A parte essencial de uma declaração de cursor é a seguinte:
DECLARE <cursor_name> FOR <sql_query_expression>
A parte opcional como [SENSITIVE | INSENSITIVO | ASENSITIVE] significa se o cursor é sensível a alterações e se deve refleti-las no resultado da consulta. SENSÍVEL significa que o cursor é afetado por alterações, INSENSITIVO significa que o cursor não é afetado e ASENSITIVO significa que as alterações podem ou não ser visíveis para o cursor. Se não especificado assume a opção ASENSITIVE.
O opcional [ROLAR | NOSCROLL] define a capacidade de rolagem do cursor. Se não for especificado, assume a opção NO SCROLL.
O opcional [ COM HOLD | WITHOUT HOLD] define se deve manter ou fechar automaticamente quando a transação devido ao cursor for confirmada. Se não for especificado mantém a opção SEM HOLD.
O opcional [ COM RETORNO | WITHOUT RETURN] determina se o conjunto de resultados do cursor deve ser retornado ao invocador, como outra rotina SQL ou idioma do host. Se não for especificado significa SEM RETORNO.
A cláusula ORDER BY é usada para classificar o resultado da consulta retornado de acordo com a técnica de classificação especificada.
A opção UPDATE refere-se ao uso da instrução UPDATE ou DELETE é associação com as linhas retornadas pela instrução SELECT do cursor. Qualquer modificação não é possível se especificarmos a opção READ ONLY. Se não for especificado, por padrão, a opção UPDATE é assumida.
Portanto, um cursor simples pode ser declarado da seguinte forma:
DECLARE mycursor CURSOR FOR SELECT emp_no, first_name, last_name, birth_date FROM employees WHERE MONTH(birth_date) = MONTH(CURRENT_DATE) AND DAY(birth_date) = DAY(CURRENT_DATE);
Cursores no MySQL
Normalmente, existem dois tipos de cursores encontrados no MySQL:cursores somente leitura e somente encaminhamento. Esses cursores podem ser usados para o procedimento armazenado do MySQL. Esses cursores nos ajudam a iterar os resultados da consulta uma linha por vez e buscar variáveis para processamento adicional. É possível declarar mais de um cursor e aninhá-los em loops. Observe que os cursores são somente leitura porque são usados para iterar sobre tabelas temporárias. O cursor normalmente executa a consulta à medida que a abrimos.
Um dos problemas com o cursor no MySQL é que eles podem diminuir o desempenho da consulta devido a operações extras de E/S que realizam. Isso é particularmente para tipos de dados grandes verdadeiros, como BLOB e TEXT. Como os cursores funcionam com tabelas temporárias, esses tipos não são suportados em tabelas na memória. Portanto, ao trabalhar com esses tipos, o MySQL precisa criar tabelas temporárias no disco e isso requer muita operação de E/S e também em dispositivos lentos como discos. Esta é a principal razão do desempenho lento do cursor.
O MySQL também não suporta cursores do lado do cliente, no entanto, a API do cliente pode emulá-los, se necessário. Mas isso não é muito diferente de buscar o resultado em uma matriz em linguagem de programação como Java e manipulá-los lá.
Aqui está um exemplo de como escrever cursores no MySQL.
CREATE PROCEDURE 'cursor_demo'() BEGIN DECLARE done INT DEFAULT FALSE; DECLARE id INT(11); DECLARE fn varchar(14); DECLARE ln varchar(16); DECLARE bdate date; DECLARE mycursor CURSOR FOR SELECT emp_no, first_name, last_name, birth_date FROM employees WHERE MONTH(birth_date)=MONTH(CURRENT_DATE) AND DAY(birth_date)=DAY(CURRENT_DATE); DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; OPEN mycursor; fetch_loop: LOOP FETCH mycursor INTO id, fn, ln, bdate; IF done THEN LEAVE fetch_loop; END IF; SELECT id, fn, ln, bdate; END LOOP; CLOSE mycursor; END
Chame o procedimento armazenado da seguinte forma:
mysql> CALL cursor_demo
O procedimento busca as linhas de uma tabela chamada employee cuja data de nascimento corresponde ao dia e mês atuais em um cursor chamado meucursor e simplesmente os imprime usando a instrução SELECT.
Consulte a documentação do MySQL no cursor para obter mais informações.
Conclusão
Os cursores nada mais são do que ponteiros para os conjuntos de registros retornados pela consulta SQL. O ponteiro normalmente aponta para uma linha de cada vez e pode ser percorrido em um loop para recuperar registros individuais. SQL é normalmente usado para invocação direta para acessar e criar objetos de dados. Os cursores fornecem a técnica de SQL interativo onde permite a execução ad hoc de instruções SQL facilitada por meio de aplicativo cliente. O mecanismo do cursor aproveita o modelo de acesso a dados onde as instruções SQL são incorporadas na linguagem do host, como C, C++ ou Java etc. Este é apenas um vislumbre do que o cursor está prestes a começar. Consulte a documentação apropriada do banco de dados SQL para obter detalhes sobre normas específicas de várias implementações.
# # #