Database – Cursor – Oracle – IBM DB2 – Microsoft SQL Server – C#

Publicado: 3 de julho de 2014 em C#

A linguagem de banco de dados SQL permite que você retorne um resultado de dados completo de uma única vez, mas as vezes precisamos manipular este resultado em tempo de execução, uma linha de cada vez, deste modo podemos utilizar um recurso chamado Cursor para realizar este procedimento.

Basicamente todos os bancos de dados possuem este recurso, entretanto cada um deles possui também suas peculiaridades e funcionalidades diferenciadas, mas no geral funcionam da seguinte maneira: a instrução DECLARE CURSOR define os atributos de um cursor do servidor SQL, como o seu comportamento de rolagem e a consulta usada para construir 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 declaração DEALLOCATE libera os recursos usados ​​pelo cursor.

Cursor - C#

Cursor – C#

Preparando o Banco de dados

Utilizaremos uma modelagem básica contendo três tabelas básicas sem chave primaria, sem chave estrangeira, permitido assim que nosso exemplo possua dados duplicados,  basicamente utilizaremos apenas a logica relacional para brincar com os dados utilizando uma Stored procedure contendo um cursor.

Relacionamentos

A tabela de FUNCIONARIOS contem dados de cadastro e o salario de cada funcionário, a tabela DESCONTO possui os valores de porcentagens de desconto para cada funcionário, e a tabela SALARIO contem os lançamentos de salários e deve ser alimentada mês a mês para cada funcionário.  Utilize os Scripts abaixo para criar as tabelas e os dados iniciais.

Visual Studio

Para efetuar as conexões com os diferentes bancos de dados você precisa primeiro configurar seu projeto com os assemblers ADO.NET  necessários e depois você pode criar um design com 3 componentes RadioButton, um componente Button e um componente DataGridView use a figura abaixo para referencia:

Visual Studio - Design Time

Visual Studio – Design Time

 

Algo Extremamente Útil  Sobre Cursores

Cursores são mais rápidos do que os looping efetuados dentro da linguagem de programação de sua preferencia, funcionam basicamente da mesma maneira, porem residem no motor do banco de dados dentro de uma Stored Procedure.

Os Cursores utilizam memoria e também necessitam de um laço para rolar registro a registro do resultado de dados e manipula-lo, é de extrema importância que você utilize cursores somente quando necessário. Caso queira que seu programa tenha uma ótima performance, antes de optar por um cursor é necessário saber que os motores dos bancos de dados são projetados para manipular dados em massa, manipulação de dados registro a registro deve ser utilizada somente quando não houver possibilidade de usar instruções SQL, para ilustrar esta explicação vamos escrever um script SQL que executa o mesmo procedimento do cursor utilizando apenas um acesso ao banco de dados, você encontra este script logo após o código C#.

Exemplo:

Neste exemplo criamos um cursor que reside dentro de uma Stored Procedure, calcula o desconto do salario dos funcionários e insere os valores líquidos em uma tabela de lançamento, após efetuar o procedimento que seria mensal, uma query exibe o relatório em uma grade de dados.

Cursor

O cursor seleciona dados da tabela de FUNCIONARIOS e da tabela de DESCONTO, através de um looping, alimenta os dados relevantes dentro de variáveis e insere os lançamentos na tabela de SALARIO efetuando o calculo do desconto.

SQL

Oracle

create table Funcionarios
(     

    ID_Funcionario  NUMBER(5),
    Nome            VARCHAR2(30),
    Sobrenome       VARCHAR2(70),
    Cargo           VARCHAR2(30),
    Salario         NUMBER(9,2)

);

Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56);
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71);

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO NUMBER,
  PORCENTAGEM NUMBER(9,2));

-- Insere porcentagem por  funcionario
Insert Into DESCONTO Values (1, 5 );
Insert Into DESCONTO Values (2, 8 );

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO NUMBER,
  DATA_LANC  DATE,
  VDESCONTO NUMBER(9,2));

-- Lista lançamentos por funcionario
select * from salario;

-- Desenvolvimento Aberto - Cursor explicito
create or replace Procedure CalculoDesconto  is
-- Declara cursor
Cursor calculo is
  Select A.ID_FUNCIONARIO, A.SALARIO, B.PORCENTAGEM
  from FUNCIONARIOS A, DESCONTO B
  Where
  A.ID_FUNCIONARIO = B.ID_FUNCIONARIO;

  -- Declara variáveis
  pID NUMBER;
  pSalario NUMBER(9,2);
  pPorcentagem NUMBER(9,2);

  -- Abre cursor
  begin
    open calculo;
      -- Cria laço
      loop
        -- Alimenta variáveis
        fetch calculo into pID, pSalario, pPorcentagem;
        EXIT WHEN calculo%NOTFOUND;

        -- Insere valores da tabela
        Insert into SALARIO
        values  (
                 pID,
                 SYSDATE,
                 (pSalario * pPorcentagem)/100);

      end loop;
    -- Fecha cursor
    close calculo;  

  end;

DB2

create table Funcionarios
(     

    ID_Funcionario  INTEGER,
    Nome            VARCHAR(30),
    Sobrenome       VARCHAR(70),
    Cargo           VARCHAR(30),
    Salario         NUMERIC(9,2)

);

Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56);
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71);

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO INTEGER,
  PORCENTAGEM DECIMAL(9,2));

-- Insere porcentagem por  funcionario
Insert Into DESCONTO Values (1, 5 );
Insert Into DESCONTO Values (2, 8 );

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO INTEGER,
  DATA_LANC  DATE,
  VDESCONTO DECIMAL(9,2));

-- Lista lançamentos por funcionario
select * from desconto;

-- Desencolcimento Aberto - Cursor explicito
CREATE PROCEDURE calculodesconto ()
	DYNAMIC RESULT SETS 1	

P1: BEGIN

	-- Declara variáveis
	 DECLARE pID INTEGER;
	 DECLARE pSalario DECIMAL(9,2);
	 DECLARE pPorcentagem DECIMAL(9,2);
	 DECLARE eof SMALLINT DEFAULT 0;

	-- Declara cursor
	DECLARE calculo CURSOR WITH RETURN for
	Select A.ID_FUNCIONARIO, A.SALARIO, B.PORCENTAGEM
    from FUNCIONARIOS A, DESCONTO B
    Where
    A.ID_FUNCIONARIO = B.ID_FUNCIONARIO;

   -- Declara handler para final de arquivo
   DECLARE CONTINUE HANDLER FOR NOT FOUND SET eof = 1;

	-- Abre cursor
	OPEN calculo;

	-- Cria label e executa looping
	fim:
	LOOP
	  -- Alimenta valores nas variáveis
	  FETCH calculo into pID, pSalario, pPorcentagem;
	  	  IF eof <> 0 THEN LEAVE fim;
	      END IF;	  

	      -- Insere dados na tabela
	      Insert into SALARIO values (
	        pID,
	        Current date,
	        (pSalario * pPorcentagem)/100);

	END LOOP fim;
	CLOSE calculo;
END P1

Mssql

create table Funcionarios
(     

    ID_Funcionario  Int,
    Nome            VARCHAR(30),
    Sobrenome       VARCHAR(70),
    Cargo           VARCHAR(30),
    Salario         Decimal(9,2)

);

Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56);
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71);

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO INT,
  PORCENTAGEM DECIMAL(9,2));

-- Insere porcentagem por  funcionario
Insert Into DESCONTO Values (1, 5 );
Insert Into DESCONTO Values (2, 8 );

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO INT,
  DATA_LANC  DATE,
  VDESCONTO DECIMAL(9,2));

-- Lista lançamentos por funcionario
select * from salario;

-- Desenvolvimento Aberto - cursor explicito
Create Procedure CALCULODESCONTO
AS
BEGIN
-- Declara Variáveis
DECLARE @pID INT,
        @pSalario DECIMAL(9,2),
		@pPorcentagem DECIMAL(9,2);

-- Declara cursor
DECLARE calculo CURSOR FOR
   Select A.ID_FUNCIONARIO, A.SALARIO, B.PORCENTAGEM
   from FUNCIONARIOS A,   DESCONTO B
   Where
   A.ID_FUNCIONARIO = B.ID_FUNCIONARIO;

   -- Abre cursor
   Open calculo;

   -- Alimenta -
   FETCH NEXT FROM calculo INTO @pID, @pSalario, @pPorcentagem;

   While @@FETCH_STATUS = 0
   BEGIN
      Insert into SALARIO values (
	        @pID,
	        GETDATE(),
	        (@pSalario * @pPorcentagem)/100);

      FETCH NEXT FROM calculo INTO @pID, @pSalario, @pPorcentagem;
   END

   -- Fecha conteudo do cursor
   Close calculo;
   -- Desaloca cursor da memória
   Deallocate calculo;
END

C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Data.SqlClient;
using Oracle.DataAccess.Client;
using IBM.Data.DB2; 

namespace Acesso
{
    public partial class Dados : Form
    {
        private static OracleConnection connORA; // ODAC 12c
        private static DB2Connection connDB2;   // IBM Data Server Provider
        private static SqlConnection connMSSQL; // ADO .NET

        DataTable dataTable;

        string sql;
        static string bancodedados;

        public Dados()
        {
            InitializeComponent();
        }

        // Cria métodos de conexão
        // Você pode optar por um unico método se usar apenas ADO.NET
        // Neste caso usamos os drivers nativos de conexão de cada banco de dados.
        // Todos os drivers são baseados em ADO .NET
        public void conexaoODAC(string Username, string Password, string Datasource)
        {
            try
            {
                // String de Conexao
                string connectionString =

                    // Usuario
                    "User Id=" + Username +

                    // Senha
                    ";Password=" + Password +

                    // TNSnames
                    ";Data Source=" + Datasource;

                //Conecta ao datasource usando a conexão Oracle
                 connORA = new OracleConnection(connectionString);

                //Abre a conexão com o banco de dados
                connORA.Open();

            }
            // Retorna erro
            catch (Exception ex)
            {
                // Mostra menssagem de erro
                MessageBox.Show(ex.ToString());

            }
        }

        void conexaoDB2(string Server, string Database,
                                    string Username, string Password, string Timeout)
        {
            try
            {
                // String de Conexao
                string connectionString =

                    // Servidor
                    "Server=" + Server +

                    // Banco de dados
                    ";Database=" + Database +

                    // Usuario
                    ";UID=" + Username +

                    // Senha
                    ";PWD=" + Password +

                    // TNSnames
                    ";Connect Timeout=" + Timeout;

                //Conecta ao datasource usando a conexão DB2
                connDB2 = new DB2Connection(connectionString);

                //Abre a conexão com o banco de dados
                connDB2.Open();                

            }
            // Retorna erro
            catch (Exception ex)
            {
                // Mostra menssagem de erro
                MessageBox.Show(ex.ToString());

            }
        }

         public void conexaoMSSQL(string Server, string Database,
                                     string Username, string Password, string Timeout)
         {
             try
             {
                 // String de Conexao
                 string connectionString =

                     // Servidor
                     "Data Source=" + Server +

                     // Banco de dados
                     ";Initial Catalog=" + Database +

                     // Usuario
                     ";User ID =" + Username +

                     // Senha
                     ";Password=" + Password +

                     // TNSnames
                     ";Connect Timeout=" + Timeout;

                 //Conecta ao datasource usando a conexão Padrão
                 connMSSQL = new SqlConnection(connectionString);

                 //Abre a conexão com o banco de dados
                 connMSSQL.Open();

             }
             // Retorna erro
             catch (Exception ex)
             {
                 // Mostra menssagem de erro
                 MessageBox.Show(ex.ToString());

             }
         }

        // Retorna um set de dados
         public  DataTable retornaTabela(string sql)
         {
             // Declara comandos para Stored Procedure
             OracleCommand cmdORA;
             DB2Command cmdDB2;
             SqlCommand cmdSQL;

             // Cria instância da classe
             Dados acesso = new Dados();

             // Define banco de dados

             if (bancodedados == "oracle")
             {
                 // Efetua Login no banco de dados
                 acesso.conexaoODAC("user", "p@55w0rd", "XE");

                 // Define a instrução SQL e a conexão
                 cmdORA = new OracleCommand("CalculoDesconto", connORA);

                 // Define tipo como Stored procedure
                 cmdORA.CommandType = CommandType.StoredProcedure;

                 // Executa query
                 cmdORA.ExecuteNonQuery();

                 // Cria comandos para retornar dados para exibir a grade de dados
                 OracleCommand oracmd = new OracleCommand(sql, connORA);
                 OracleDataReader orareader = oracmd.ExecuteReader();
                 dataTable = new DataTable();
                 dataTable.Load(orareader);
             }

             if (bancodedados == "db2")
             {
                 acesso.conexaoDB2("localhost", "DEVA", "user", "p@55w0rd", "40");

                 cmdDB2 = new DB2Command("CalculoDesconto", connDB2);

                 cmdDB2.CommandType = CommandType.StoredProcedure;

                 cmdDB2.ExecuteNonQuery();

                 DB2Command db2cmd = new DB2Command(sql);
                 db2cmd.Connection = connDB2;
                 DB2DataReader db2reader = db2cmd.ExecuteReader();
                 dataTable = new DataTable();
                 dataTable.Load(db2reader);                

             }

             if (bancodedados == "mssql")
             {
                 acesso.conexaoMSSQL("localhost", "DevAberto", "user", "p@55w0rd", "");

                 cmdSQL = new SqlCommand("CalculoDesconto", connMSSQL);

                 cmdSQL.CommandType = CommandType.StoredProcedure;

                 cmdSQL.ExecuteNonQuery();

                 SqlCommand mssqlcmd = new SqlCommand(sql);
                 mssqlcmd.Connection = connMSSQL;
                 SqlDataReader mssqlreader = mssqlcmd.ExecuteReader();
                 dataTable = new DataTable();
                 dataTable.Load(mssqlreader);

             }

             return  dataTable;
         }

        // configura programa
        private void Form1_Shown(object sender, EventArgs e)
        {
            radioButton1.Checked = true;
            bancodedados = "oracle";
        }

        // Conecta dados
        private void button1_Click(object sender, EventArgs e)
        {
            // Cria instância da classe
            Dados dados = new Dados();

            // Exibe relatorio de lançamentos
            string sql = "Select A.ID_FUNCIONARIO, " + "A.NOME, " + " A.CARGO, "
                       + " A.SALARIO, " + "B.PORCENTAGEM, " + "C.VDESCONTO, "
                       + "C.DATA_LANC,  " + "A.SALARIO - C.VDESCONTO AS SLIQUIDO "
                       + "from FUNCIONARIOS A, DESCONTO B, SALARIO C " + "Where "
                       + "A.ID_FUNCIONARIO = B.ID_FUNCIONARIO  AND "
                       + "A.ID_FUNCIONARIO = C.ID_FUNCIONARIO";

            // Alimenta grid de dados
            dataGridView1.DataSource = dados.retornaTabela(sql);

        }

        // Seleciona banco de dados Oracle
        private void radioButton1_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButton1.Checked)
            {
                bancodedados = "oracle";
            }

        }

        // Seleciona banco de dados IBM DB2
        private void radioButton2_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButton2.Checked)
            {
                bancodedados = "db2";
            }
        }

        // Seleciona banco de dados MSSQL Server
        private void radioButton3_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButton3.Checked)
            {
                bancodedados = "mssql";
            }
        }
    }
}

SQL – A instrução a seguir, substitui o cursor em um único acesso. (Oracle)

-- Este script SQL efetua o mesmo procedimento do cursor
-- utilizando apenas um acesso ao banco de dados.
-- é importante projetar seu acesso a dados para obter alta performance
-- você deve utilizar cursores apenas quando realmente for necessário.
--
-- Para os outros bancos substitua o campo SYSDATE
-- Para DB2 use Current date
-- Para MSSQL use GETDATE() 

Insert into SALARIO
Select A.ID_FUNCIONARIO,SYSDATE, ((A.SALARIO * B.PORCENTAGEM)/100)
  from FUNCIONARIOS A, DESCONTO B
  Where
  A.ID_FUNCIONARIO = B.ID_FUNCIONARIO;

 

 

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 )

Foto do Google+

Você está comentando utilizando sua conta Google+. 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 )

Conectando a %s