Arquivo de junho, 2014

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.

Native SQL - Cursor

Native SQL – Cursor

O Native SQL possui uma sintaxe simplificada apesar de nos permitir uma conexão direta sem utilizar o dicionário de dados ABAP. No banco de dados, geralmente um cursor é criado dentro de uma Stored Procedure, mas algumas linguagens de programação possuem instruções para cria-los utilizando a sintaxe da própria língua, em ABAP esta sintaxe é bem parecida com a sintaxe utilizada pelo Open SQL.

Sintaxe:

  • OPEN <cursor name> FOR <statement>
  • FETCH NEXT <cursor name> INTO <target(s)>.
  • CLOSE <cursor name>

Exemplo:

Neste exemplo criamos uma cursor SQL direto sem utilizar uma procedure.

Abap

*&---------------------------------------------------------------------*
*& Report  ZCURSOR
*&
*&---------------------------------------------------------------------*
*& Desenvolvimento Aberto
*& Native SQL - Open Cursor
*&---------------------------------------------------------------------*

REPORT  ZCURSOR.

* Cria parametro de pesquisa
DATA : parametro1 TYPE spfli-carrid VALUE 'AZ'.
DATA : parametro2 TYPE spfli-carrid VALUE 'LH'.

* Cria variáveis do cursor
DATA: BEGIN OF cur,
       variavel1 TYPE spfli-CONNID,
       variavel2 TYPE spfli-CITYFROM,
       variavel3 TYPE spfli-CITYTO,
       variavel4 TYPE spfli-DISTANCE,
       variavel5 TYPE spfli-DISTID,
 END OF cur.

* Declara e Abre um cursor
* -------------------------
*
* Atente-se que estamos utilizando o SAP MaxDB para este exemplo.
* O Native SQL possui sua própria sintaxe e não utiliza
* a sintaxe do banco de dados, neste caso a sintaxe para o banco seria:
*
* --SAP MaxDB ANSI 92 SQL
*
* DECLARE db1 CURSOR FOR
* SELECT * FROM TABELA
* WHERE X = 1
*
* Em vez disto, utiliza o comando NATIVE SQL: 
* OPEN nome do cursor FOR clausula sql
* este comando declara e abre um cursor no banco de dados.

EXEC SQL.
  OPEN db1  FOR
    SELECT CONNID, CITYFROM, CITYTO, DISTANCE,  DISTID
    FROM spfli
    WHERE
    MANDT  = '200' AND
    CARRID = :parametro1
    UNION
    SELECT CONNID, CITYFROM, CITYTO, DISTANCE,  DISTID
    FROM spfli
    WHERE
    MANDT  = '200' AND
    CARRID = :parametro2

ENDEXEC.

* Executa Fetch e alimenta as variáveis do cursor
DO.
  EXEC SQL.
    FETCH NEXT db1 INTO :cur-variavel1, :cur-variavel2, :cur-variavel3, :cur-variavel4, :cur-variavel5
  ENDEXEC.

  IF sy-subrc <> 0.
    EXIT.
  ELSE.
    WRITE : / cur-variavel1, cur-variavel2, cur-variavel3, cur-variavel4, cur-variavel5.
  ENDIF.
ENDDO.

* Fecha o cursor
EXEC SQL.
  CLOSE db1
ENDEXEC.

 

Stored Procedures são procedimentos de código SQL armazenados no banco de dados, as stored procedures são mais rápidas do que o código tradicional, o que significa que elas estão se tornando cada vez mais populares. Com código da aplicação se mudando dos programas externos para o motor de banco de dados, Os DBAs precisam entender os requisitos de memória relacionados para procedimentos armazenados e saber como gerenciar estes procedimentos para o ideal desempenho do banco de dados. Isto muda de banco para banco, cada um deles possui suas recomendações de melhores praticas para atingir um melhor desempenho.

Uma palavra sobre o Dicionário de Dados SAP

Como sabemos Native SQL nos permite utilizar código SQL direto, ignorando a camada de banco de dados do SAP R/3, isto significa que o Native SQL é o método mais rápido para manipular grande quantidade de dados em ABAP, apesar do desenvolvedor estar sozinho nesta empreitada e não poder utilizar nenhum recurso do dicionário ABAP, incluindo os tipos de campos compatíveis entre banco e linguagem de programação, manipulação automática do campo MANDT do cliente, escrita SQL única para qualquer banco de dados (Open SQL) entre outras facilidades.

Apesar dos contras este conceito nos permite utilizar Stored Procedures como métodos para extrair ou manipular dados utilizando o ABAP, podendo até exercer a mesma função do RFC em termos de manuseio de dados entre diferentes servidores e aplicações não R/3.

Por exemplo algumas tabelas contendo dados massivos como o caso da tabela de notas fiscais ou lançamentos contábeis entre outras que necessitam de algum tipo de auditoria de algum sistema não R/3 que pretende importar os dados do sistema R/3, podem obter método de extração da própria empresa detentora do sistema R/3 utilizando procedures obtendo a melhor performance possível na extração e importação de dados aplicando técnicas de Bulk dos bancos de dados(importação em massa) ao invés de utilizar as próprias funções de RFC disponíveis pela SAP, cujo criam um set de dados na memoria e necessitam de um looping para extrair linha a linha da tabela alocada por um sistema não R/3.

SAP MaxDB SQL Studio

Utilizaremos neste post o banco de dados MaxDB da própria SAP, mas escreveremos as Stored Procedures para os bancos de dados Oracle, IBM DB2 e Microsoft SQL Server.

Este tipo de técnica necessita que o desenvolvedor tenha um conhecimento avançado do banco de dados a ser utilizado e do próprio banco de dados SAP, suas tabelas e seus conceitos por traz do dicionário de dados.

1- Entre no SAP MaxDB e utilize o script SQL completo encontrado abaixo.

SQL Studio

SQL Studio

2 – Crie um programa no SAP e utilize o código correspondente.

Stored Procedure - Abap

Stored Procedure – Abap

Exemplo:

Neste exemplo criamos uma tabela que não está declarada no dicionário de dados ABAP e criamos uma Stored Procedure com parâmetros de entrada e saída, e a utilizamos como um método para extrair dados diretamente em um programa ABAP.

Obs: Visto que no campo de valor flutuante da imagem acima, o mesmo foi extraído diretamente do banco de dados, ele não pode ser formatado pela linguagem ABAP por seus tipos nativos, mas você pode criar seu próprio tipo de dado para mostra-lo corretamente usando o dicionário de dados após a operação no banco de dados, utilizando o tipo de valor padrão para números flutuantes com casas decimais, que compõe o conceito padrão da linguagem ABAP ou seja, utilizando um Data Object.

SAP MaxDB

-- Cria tabela no schema SAPNSP
CREATE TABLE SAPNSP.ZFUNCIONARIO
(
            ID_FUNCIONARIO INT,
            NOME VARCHAR (30),
            SOBRENOME VARCHAR(70),
            CARGO VARCHAR(30),
            SALARIO DECIMAL(9,2)
)

-- Insere dados na tabela
Insert into SAPNSP.ZFUNCIONARIO values (1,'Steve','Gates','Programador',2550.56)
Insert into SAPNSP.ZFUNCIONARIO values (2,'Bill','Jobs','Diretor',5143.71)

-- Visualiza dados
select * from SAPNSP.ZFUNCIONARIO

-- Cria Stored Procedure
CREATE DBPROC SAPNSP.ZFUNCIONARIOS    (
           IN PID_FUNCIONARIO INT,
           OUT  PNOME VARCHAR (30),
           OUT PSOBRENOME VARCHAR(70),
           OUT PCARGO VARCHAR(30),
           OUT PSALARIO FLOAT      )  

    AS
           SELECT NOME, SOBRENOME, CARGO, SALARIO
           INTO :PNOME, :PSOBRENOME, :PCARGO, :PSALARIO
           FROM SAPNSP.ZFUNCIONARIO
           WHERE ID_FUNCIONARIO = :PID_FUNCIONARIO;

-- Testa Stored Procedure
  CALL SAPNSP.ZFUNCIONARIOS (1, :PNOME , :PSOBRENOME , :PCARGO , :PSALARIO)

Oracle

create or replace PROCEDURE SAPNSP.ZFUNCIONARIOS
- Cria parametros
(pid_funcionario IN FUNCIONARIOS.ID_FUNCIONARIO%TYPE,
 p_nome OUT FUNCIONARIOS.NOME%TYPE,
 p_sobrenome OUT FUNCIONARIOS.SOBRENOME%TYPE,
 p_cargo OUT FUNCIONARIOS.CARGO%TYPE,
 p_salario OUT FUNCIONARIOS.SALARIO%TYPE
 )
AS
BEGIN
-- Insere dados da query dentro dos parametros de saida
  SELECT NOME, SOBRENOME, CARGO, SALARIO
  INTO p_nome, p_sobrenome, p_cargo, p_salario
  FROM SAPNSP.ZFUNCIONARIO
  WHERE ID_FUNCIONARIO = pid_funcionario;

END;

DB2

-- Cria procedure
CREATE PROCEDURE SAPNSP.ZFUNCIONARIOS
( IN pid_funcionario INTEGER,
  OUT p_nome VARCHAR(30),
  OUT p_sobrenome VARCHAR(70),
  OUT p_cargo VARCHAR(30),
  OUT p_salario DECIMAL(9,2)
 )

P1: BEGIN

  SELECT NOME, SOBRENOME, CARGO, SALARIO
  INTO p_nome, p_sobrenome, p_cargo, p_salario
  FROM SAPNSP.ZFUNCIONARIO
  WHERE ID_FUNCIONARIO = pid_funcionario;

END P1

MSSQL

CREATE PROCEDURE SAPNSP.ZFUNCIONARIOS
   @pfuncionario INT,
   @pnome		 NVarchar(30) OUTPUT,
   @psobrenome	 NVarchar(70) OUTPUT,
   @pcargo	     NVarchar(30) OUTPUT,
   @psalario	 Decimal(9,2) OUTPUT
AS
BEGIN
   SELECT @pnome = Nome,
		  @psobrenome = Sobrenome,
		  @pcargo = Cargo,
		  @psalario = Salario
   FROM SAPNSP.ZFUNCIONARIO
   WHERE ID_Funcionario = @pfuncionario
END

Abap

*&---------------------------------------------------------------------*
*& Report  ZSTOREDPROCEDURE
*&
*&---------------------------------------------------------------------*
*& Desenvolvimento Aberto
*& Native SQL - Stored Procedures - Abap
*&---------------------------------------------------------------------*

REPORT  ZSTOREDPROCEDURE.

* Declara parametros de saida para a procedure
DATA :  pnome      TYPE c LENGTH 30,
        psobrenome TYPE c LENGTH 70,
        pcargo     TYPE c LENGTH 30,
        psalario   TYPE f.

* Declara parametro de entrada para a procedure
PARAMETERS id_func TYPE i.

* Executa Native SQL utilizando os parametros
EXEC SQL.

 EXECUTE PROCEDURE SAPNSP.ZFUNCIONARIOS (IN :id_func, OUT :PNOME , OUT :PSOBRENOME , OUT :PCARGO , OUT :PSALARIO)

ENDEXEC.

* Exibe resultado dos parâmetros
WRITE: / 'Dados Retornados direto do banco SAP MaxDB' Color 5.

skip 2.

WRITE: / 'Código:'    Color 1, id_func,
       / 'Nome:'      Color 1, pnome,
       / 'Sobrenome:' Color 1, psobrenome,
       / 'Cargo:'     Color 1, pcargo,
       / 'Salário:'   Color 1, psalario .

SAP – Database – Native SQL – Abap

Publicado: 24 de junho de 2014 em Abap

Instruções Native SQL permitem utilizar comandos SQL específicos de um banco de dados em um programa ABAP. Isso significa que você pode usar instruções de banco de dados que não são administradas pelo dicionário ABAP, e, portanto, programas criados com instruções SQL nativas não podem ser transportados para qualquer plataforma pois utilizam por exemplo PL/SQL para o banco de dados Oracle ou Transact-SQL para o Microsoft SQL Server e assim por diante.

Instruções SQL nativas permitem uma maior flexibilidade de dados em um programa ABAP por não ter restrições e permitem que você utilize quase todos os recursos da linguagem de cada banco de dados, pois instruções SQL nativas ignoram a interface de banco de dados do R/3. Não há registro de tabelas de log, e não há sincronização com o buffer do banco de dados no servidor de aplicativos. Por esta razão, você deve, sempre que possível, usar o Open SQL para alterar as tabelas de banco de dados declaradas no dicionário ABAP. Em particular, as tabelas declaradas no dicionário ABAP que contêm longas colunas com os tipos LCHR ou LAW e só devem ser abordadas usando o Open SQL, já que as colunas contêm, informação extra e de comprimento específico do banco de dados. O SQL nativo não tem essa informação, e pode,  produzir resultados incorretos. Além disso, o SQL nativo não suporta manuseio automático de cliente. Em vez disso, você deve tratar campos do cliente como qualquer outro.

O Native SQL permite que você execute Stored Procedures, cursores e outros tipos de procedimentos comuns do banco de dados, mas existe algumas ressalvas, o SQL nativo funciona sem os dados administrativos sobre as tabelas armazenadas no dicionário ABAP. Consequentemente, não pode realizar todas as verificações de consistência como o Open SQL. Isto coloca um maior grau de responsabilidade sobre os desenvolvedores de aplicativos em como trabalhar com campos ABAP corretamente. Você deve sempre garantir que o tipo de dado ABAP e o tipo da coluna de banco de dados são idênticos.

Native SQL

Native SQL

Em sua sintaxe, o Native SQL deve começar com uma instrução EXEC SQL e terminar com ENDEXEC, a instrução também permite que você utilize uma instrução FORMPERFORM que é executada automaticamente.

Exemplo:

Neste exemplo escrevemos uma simples instrução SQL nativa que utiliza parâmetros para executar uma instrução SQL para o banco de dados SAP MaxDB.

Abap

*&---------------------------------------------------------------------*
*& Report  ZNATIVESQL
*&
*&---------------------------------------------------------------------*
*& Desenvolvimento Aberto
*& Abap - Native SQL
*&---------------------------------------------------------------------*

REPORT  ZNATIVESQL.

* Cria tabela interna
DATA: BEGIN OF itabela,
        connid   TYPE spfli-connid,
        cityfrom TYPE spfli-cityfrom,
        airpfrom TYPE spfli-airpfrom,
        cityto   TYPE spfli-cityto,
        airpto   TYPE spfli-airpto,
        deptime  TYPE spfli-deptime,
        arrtime  TYPE spfli-arrtime,
      END OF itabela.

* Cria parametro de pesquisa
DATA parametro TYPE spfli-carrid VALUE 'AZ'.

* Executa Native SQL utilizando um procedimento FORM
EXEC SQL PERFORMING dados.
  SELECT connid, cityfrom, airpfrom, cityto, airpto, deptime, arrtime
  INTO   :itabela
  FROM   spfli
  WHERE  carrid = :parametro
ENDEXEC.

* Pula duas linhas
SKIP 2.

* Retorna a quantidade de linhas afetadas
WRITE: / 'A instrução SQL retornou', SY-DBCNT, ' linhas de dados.'.

* Cria procedimento
FORM dados.
  WRITE: / itabela-connid, itabela-cityfrom, itabela-airpfrom,
           itabela-cityto, itabela-airpto, itabela-deptime, itabela-arrtime.
ENDFORM.

O objeto Window nos permite utilizar o evento OnError para interceptar uma exceção no código javascript, geralmente um erro contido dentro de uma tag de script é ignorado pelo browser.

Este evento do objeto Window é uma herança do tempo em que a linguagem ainda não continha a instrução Try… Catch, com a modernização da linguagem, este tipo de recurso hoje em dia é raramente usado, mas ainda é útil para explicitar quando um erro ocorre em um script.

Cria um erro de sintaxe

Cria um erro de sintaxe

Exemplo:

Neste exemplo criamos uma função que exibe uma mensagem contendo informações de erros encontrados em um script. Criamos um erro proposital de sintaxe para que o evento seja disparado.

Html/Javascript

<!DOCTYPE html>
<html>

<head>
   <title>Desenvolvimento Aberto</title>
</head>

<body>
<h2>Desenvolvimento Aberto</h2>
<h3>Javascript - Manipulando Erros</h3>
<pre>

<script>
// Mostra a menssagem de erro em uma caixa de dialogo

window.onerror = function(msg, url, line)
{
	if (onerror.num++ < onerror.max)
	{
   	alert("ERROR: " + msg + "\n" + url + ":" + line);
   	return true;
	}
}
// Define propriedades do evento de erro
onerror.max = 2;
onerror.num = 0;

write("Linux Ubuntu o comando write é case-sensitive");

// Cria Erro - Comando write com inicio maiusculo;
Write("Este comando contem um erro");

</script>
</pre>
</body>
</html>

Para excluir um registro do banco de dados através de uma pagina da web, utilizando o conceito de persistência do ActiveRecord do framework Rails, basta simplesmente utilizar a instrução destroy dentro do método do mesmo nome no controlador referenciando sua rota pelo nome do verbo delete que nos fornece a ação do controlador sobre o nome empresas#destroy, que pode ser visto usando a instrução rake route no console do Aptana.

Destroy - rake route

Destroy – rake route

Deletando um Registro

Para deletar um registro do banco de dados MySQL precisamos modificar a visão da pagina Index, criar um link de seleção e incluir o método para deletar o registro escolhido alterando o arquivo do controlador.

1 – Altere o arquivo de visão chamado index.html.erb e o arquivo do controlador chamado empresas_controller.rb utilizando os respectivos códigos abaixo:

Deletar - MVC

Deletar – MVC

Exemplo:

Neste exemplo deletamos um arquivo selecionado na pagina índice e o deletamos através da ação de seu controlador.

Arquivo – index.html.erb

<h2>Desenvolvimento Aberto</h2>
<p>Lista de Blogs e Projetos Open Source</p>
<pre>
<table width="500">
<tr>
	<th>Cod:</th>
	<th>&nbsp;&nbsp;</th>
	<th>Empresa:</th>
	<th>&nbsp;&nbsp;</th>
	<th>Site:</th>
	<th>&nbsp;&nbsp;</th>
	<th>Evento:</th>
	<th>&nbsp;&nbsp;</th>
	<th>Excluir:</th>
</tr>
<% @empresas.each do |empresa| %>

<tr>
<td><%= empresa.codigo%> </td>
<td>&nbsp;&nbsp;</td>
<td><%= link_to empresa.nome, empresa %> </td>
<td>&nbsp;&nbsp;</td>
<td><%= empresa.site%> </td>
<td>&nbsp;&nbsp;</td>
<td><%= link_to "Editar", edit_empresa_path(empresa) %> </td>
<td>&nbsp;&nbsp;</td>
<td><%= link_to "Deletar", empresa, :confirm => "Deseja apagar o registro?", :method => :delete  %> </td>

</tr>

<%end%>
</table>

<p> <%= link_to "Adicionar um novo registro", new_empresa_path %> </p>
</pre>

Arquivo – empresas_controller.rb

class EmpresasController < ApplicationController

  def index
    @empresas = Empresa.all
  end

  def show
    @empresa = Empresa.find(params[:id])
  end

  def new
    @empresa = Empresa.new
  end

  def create
    @empresa = Empresa.new(empresa_params)
    if @empresa.save
      redirect_to empresas_path :notice => "Seu registro foi criado com sucesso"
    else
      render "new"
    end
  end

  def edit
    @empresa = Empresa.find(params[:id])
  end

  def update
    @empresa = Empresa.find(params[:id])

    if @empresa.update_attributes(empresa_params)
      redirect_to empresas_path :notice => "Seu registro foi criado com sucesso"
    else
      render "edit"
    end
  end

  def destroy
    @empresa = Empresa.find(params[:id])
    @empresa.destroy
    redirect_to empresas_path :notice => "Seu registro foi deletado com sucesso"
  end

  private

  def empresa_params
    params.require(:empresa).permit(:codigo, :nome, :site, :projeto, :tipo, :linguagem, :descricao)
  end

end

 

Stored Procedures são procedimentos de código SQL armazenados no banco de dados, as stored procedures são mais rápidas do que o código tradicional, o que significa que elas estão se tornando cada vez mais populares. Com código da aplicação se mudando dos programas externos para o motor de banco de dados, Os DBAs precisam entender os requisitos de memória relacionados para procedimentos armazenados e saber como gerenciar estes procedimentos para o ideal desempenho do banco de dados. Isto muda de banco para banco, cada um deles possui suas recomendações de melhores praticas para atingir um melhor desempenho.

Neste site existe uma versão deste mesmo programa utilizando código SQL direto dentro da aplicação e podemos comparar a diferença com o código SQL sendo executado dentro do motor do banco de dados e o resultado é visivelmente notado, sem duvida o código executado utilizando procedures é mais rápido.

Ainda existe um outro modo de utilizar o banco de dados que é utilizando um set de dados persistente, onde uma camada  de classes ou componentes geram o código SQL para o banco de dados através de instruções definidas pelas classes, mas este método por possuir uma camada que cria o código para o banco pode se tornar menos atrativo em termos de desempenho, apesar de ser muito mais fácil e rápido para se desenvolver, sendo assim vale avaliar a quantidade de dados que sua aplicação pretende manipular.

Para adquirir o script SQL para criar a tabela deste exemplo ou visualizar o método utilizando SQL direto da aplicação: clique aqui.

DB2 - Stored Procedure

DB2 – Stored Procedure

Exemplo:

Neste exemplo utilizamos Stored Procedures que retornam parâmetros para criar um método dentro do banco de dados ao invés de criar o método dentro da aplicação utilizando a linguagem de programação nativa.

IBM DB2

-- Cria procedure
CREATE PROCEDURE buscaFuncionario
( IN pid_funcionario INTEGER,
  OUT p_nome VARCHAR(30),
  OUT p_sobrenome VARCHAR(70),
  OUT p_cargo VARCHAR(30),
  OUT p_salario DECIMAL(9,2)
 )

P1: BEGIN

  SELECT NOME, SOBRENOME, CARGO, SALARIO
  INTO p_nome, p_sobrenome, p_cargo, p_salario
  FROM FUNCIONARIOS
  WHERE ID_FUNCIONARIO = pid_funcionario;

END P1

Python

#!/usr/bin/env python
# -*- coding: latin-1 -*-
# Desenvolvimento Aberto
# StoredDB2.py

# importa modulos
from Tkinter import *
import tkMessageBox
import ibm_db

# Cria formulario
formulario = Tk(className='Desenvolvimento Aberto')
formulario.geometry("350x280+300+300")

# Cria janela para menssagem
janela = Tk()
janela.wm_withdraw()

# Define banco de dados
# oracle = Oracle Database
DBconexao = "db2"

# Cria conexão com o banco de dados
def conectar(banco):
    # Cria string de conexão Oracle
    if (banco == "db2"):
        # Cria string de conexão IBM
        sconexao = "DATABASE=DEVA" +  \
                   ";HOSTNAME=localhost;PORT=50000;PROTOCOL=TCPIP;" + \
                   "UID=user;" + \
                   "PWD=p@55w0rd"
        try:
            con = ibm_db.connect(sconexao, "", "")
        except ValueError:
            tkMessageBox.showinfo(title="Menssagem", message="Erro de Conexão", parent=janela)

    return con

# Limpa campo
def limpar():
    tcodigo.delete(0, END)
    tpnome.delete(0, END)
    tsnome.delete(0, END)
    tcargo.delete(0, END)
    tsalario.delete(0, END)

# Evento do botão
def on_Pesquisar():
    # Exibe banco de dados
    titulo['text'] = "Stored Procedure: " + DBconexao

    # Cria conexão
    con = conectar(DBconexao)

    # Define e executa Stored Procedure
    if (DBconexao == "db2"):

        #Declara parametros
        pid = tpesquisa.get()
        pnome = ""
        psobrenome = ""
        pcargo = ""
        psalario = 0.0

        # Executa Stored Procedure
        stmt, pid, pnome, psobrenome, pcargo, psalario = ibm_db.callproc(con, "buscaFuncionario" , (pid, pnome, psobrenome, pcargo, psalario))

    # Prepara campos
    limpar()

    # Exibe dados
    tcodigo.insert(0, pid)
    tpnome.insert(0, pnome)
    tsnome.insert(0, psobrenome)
    tcargo.insert(0, pcargo)
    tsalario.insert(0, str(psalario))

# Cria componentes widgets
titulo = Label(formulario, text="Database: Nenhum")
# labels
lcodigo = Label(formulario, text="Codigo:")
lpnome = Label(formulario, text="Nome:")
lsnome = Label(formulario, text="Sobrenome:")
lcargo = Label(formulario, text="Cargo:")
lsalario = Label(formulario, text="Salario:")
# Entry
tcodigo = Entry(formulario)
tpnome = Entry(formulario)
tsnome = Entry(formulario)
tcargo = Entry(formulario)
tsalario = Entry(formulario)
# Pesquisa
lpesquisa = Label(formulario, text="Pesquisa:")
tpesquisa = Entry(formulario)
botao = Button(formulario, text = "Pesquisar", command=on_Pesquisar)

# Define Layout
titulo.grid(row=0, sticky=W+E+N+S, pady=20)
lcodigo.grid(row=1, sticky=W, padx=20)
tcodigo.grid(row=1, column=1, pady=5)
lpnome.grid(row=2,sticky=W, padx=20)
tpnome.grid(row=2, column=1, pady=5)
lsnome.grid(row=3,sticky=W, padx=20)
tsnome.grid(row=3, column=1, pady=5)
lcargo.grid(row=4, sticky=W, padx=20)
tcargo.grid(row=4, column=1, pady=5)
lsalario.grid(row=5, sticky=W, padx=20)
tsalario.grid(row=5, column=1, pady=5)
# Layout pesquisa
lpesquisa.grid(row=6, column=0, pady=20)
tpesquisa.grid(row=6, column=1, pady=20)
botao.grid(row=6, column=2,pady=20)

# loop do tcl
mainloop()

Stored Procedures são procedimentos de código SQL armazenados no banco de dados, as stored procedures são mais rápidas do que o código tradicional, o que significa que elas estão se tornando cada vez mais populares. Com código da aplicação se mudando dos programas externos para o motor de banco de dados, Os DBAs precisam entender os requisitos de memória relacionados para procedimentos armazenados e saber como gerenciar estes procedimentos para o ideal desempenho do banco de dados. Isto muda de banco para banco, cada um deles possui suas recomendações de melhores praticas para atingir um melhor desempenho.

Neste site existe uma versão deste mesmo programa utilizando código SQL direto dentro da aplicação e podemos comparar a diferença com o código SQL sendo executado dentro do motor do banco de dados e o resultado é visivelmente notado, sem duvida o código executado utilizando procedures é mais rápido.

Ainda existe um outro modo de utilizar o banco de dados que é utilizando um set de dados persistente, onde uma camada  de classes ou componentes geram o código SQL para o banco de dados através de instruções definidas pelas classes, mas este método por possuir uma camada que cria o código para o banco pode se tornar menos atrativo em termos de desempenho, apesar de ser muito mais fácil e rápido para se desenvolver, sendo assim vale avaliar a quantidade de dados que sua aplicação pretende manipular.

Para adquirir o script SQL para criar a tabela deste exemplo ou visualizar o método utilizando SQL direto da aplicação: clique aqui.

Python - Stored Procedure

Python – Stored Procedure

Exemplo:

Neste exemplo utilizamos Stored Procedures que retornam parâmetros para criar um método dentro do banco de dados ao invés de criar o método dentro da aplicação utilizando a linguagem de programação nativa.

Oracle

create or replace PROCEDURE buscaFuncionario
- Cria parametros
(pid_funcionario IN FUNCIONARIOS.ID_FUNCIONARIO%TYPE,
 p_nome OUT FUNCIONARIOS.NOME%TYPE,
 p_sobrenome OUT FUNCIONARIOS.SOBRENOME%TYPE,
 p_cargo OUT FUNCIONARIOS.CARGO%TYPE,
 p_salario OUT FUNCIONARIOS.SALARIO%TYPE
 )
AS
BEGIN
-- Insere dados da query dentro dos parametros de saida
  SELECT NOME, SOBRENOME, CARGO, SALARIO
  INTO p_nome, p_sobrenome, p_cargo, p_salario
  FROM FUNCIONARIOS
  WHERE ID_FUNCIONARIO = pid_funcionario;

END;

Python

#!/usr/bin/env python
# -*- coding: latin-1 -*-
# Desenvolvimento Aberto
# StoredOra.py

# importa modulos
from Tkinter import *
import tkMessageBox
import cx_Oracle

# Cria formulario
formulario = Tk(className='Desenvolvimento Aberto')
formulario.geometry("350x280+300+300")

# Cria janela para menssagem
janela = Tk()
janela.wm_withdraw()

# Define banco de dados
# oracle = Oracle Database
DBconexao = "oracle"

# Cria conexão com o banco de dados
def conectar(banco):
    # Cria string de conexão Oracle
    if (banco == "oracle"):
        sconexao = "user/p@55w0rd@localhost/XE"
        try:
            con = cx_Oracle.connect(sconexao)
        except ValueError:
            tkMessageBox.showinfo(title="Menssagem", message="Erro de Conexão", parent=janela) 

    return con

# Limpa campo
def limpar():
    tcodigo.delete(0, END)
    tpnome.delete(0, END)
    tsnome.delete(0, END)
    tcargo.delete(0, END)
    tsalario.delete(0, END)

# Evento do botão
def on_Pesquisar():
    # Exibe banco de dados
    titulo['text'] = "Database: " + DBconexao

    # Cria conexão
    con = conectar(DBconexao)

    # Define e executa Stored Procedure
    if (DBconexao == "oracle"):
        cursor = con.cursor()

        #Declara parametros
        pnome = cursor.var(cx_Oracle.STRING)
        psobrenome = cursor.var(cx_Oracle.STRING)
        pcargo = cursor.var(cx_Oracle.STRING)
        psalario = cursor.var(cx_Oracle.NUMBER)

        # Chama stored procedure utilizando um tupple
        cursor.callproc('buscaFuncionario', (tpesquisa.get(), pnome, psobrenome, pcargo, psalario))

    # Prepara campos
    limpar()

    # Exibe dados
    tcodigo.insert(0, tpesquisa.get())
    tpnome.insert(0, pnome.getvalue())
    tsnome.insert(0, psobrenome.getvalue())
    tcargo.insert(0, pcargo.getvalue())
    tsalario.insert(0, str(psalario.getvalue()))

# Cria componentes widgets
titulo = Label(formulario, text="Database: Nenhum")
# labels
lcodigo = Label(formulario, text="Codigo:")
lpnome = Label(formulario, text="Nome:")
lsnome = Label(formulario, text="Sobrenome:")
lcargo = Label(formulario, text="Cargo:")
lsalario = Label(formulario, text="Salario:")
# Entry
tcodigo = Entry(formulario)
tpnome = Entry(formulario)
tsnome = Entry(formulario)
tcargo = Entry(formulario)
tsalario = Entry(formulario)
# Pesquisa
lpesquisa = Label(formulario, text="Pesquisa:")
tpesquisa = Entry(formulario)
botao = Button(formulario, text = "Pesquisar", command=on_Pesquisar)

# Define Layout
titulo.grid(row=0, sticky=W+E+N+S, pady=20)
lcodigo.grid(row=1, sticky=W, padx=20)
tcodigo.grid(row=1, column=1, pady=5)
lpnome.grid(row=2,sticky=W, padx=20)
tpnome.grid(row=2, column=1, pady=5)
lsnome.grid(row=3,sticky=W, padx=20)
tsnome.grid(row=3, column=1, pady=5)
lcargo.grid(row=4, sticky=W, padx=20)
tcargo.grid(row=4, column=1, pady=5)
lsalario.grid(row=5, sticky=W, padx=20)
tsalario.grid(row=5, column=1, pady=5)
# Layout pesquisa
lpesquisa.grid(row=6, column=0, pady=20)
tpesquisa.grid(row=6, column=1, pady=20)
botao.grid(row=6, column=2,pady=20)

# loop do tcl
mainloop()

Stored Procedures são procedimentos de código SQL armazenados no banco de dados, as stored procedures são mais rápidas do que o código tradicional, o que significa que elas estão se tornando cada vez mais populares. Com código da aplicação se mudando dos programas externos para o motor de banco de dados, Os DBAs precisam entender os requisitos de memória relacionados para procedimentos armazenados e saber como gerenciar estes procedimentos para o ideal desempenho do banco de dados. Isto muda de banco para banco, cada um deles possui suas recomendações de melhores praticas para atingir um melhor desempenho.

Neste site existe uma versão deste mesmo programa utilizando código SQL direto dentro da aplicação e podemos comparar a diferença com o código SQL sendo executado dentro do motor do banco de dados e o resultado é visivelmente notado, sem duvida o código executado utilizando procedures é mais rápido.

Ainda existe um outro modo de utilizar o banco de dados que é utilizando um set de dados persistente, onde uma camada  de classes ou componentes geram o código SQL para o banco de dados através de instruções definidas pelas classes, mas este método por possuir uma camada que cria o código para o banco pode se tornar menos atrativo em termos de desempenho, apesar de ser muito mais fácil e rápido para se desenvolver, sendo assim vale avaliar a quantidade de dados que sua aplicação pretende manipular.

Para adquirir o script SQL para criar a tabela deste exemplo ou visualizar o método utilizando SQL direto da aplicação: clique aqui.

Restrições

Um problema com o ADO.NET é que a Microsoft não pode acessar todos os recursos dos bancos de dados Oracle e IBM DB2, então se o desenvolvedor optar assim como nós por utilizar os drivers de cada fornecedor, diferentemente da linguagem de programação JAVA que também é uma linguagem nativa para os bancos de dados Oracle e DB2, não é possível utilizar instruções C# únicas para os diferentes bancos de dados, pois os drivers acabam sendo incompatíveis, uma opção seria criar um dicionário de dados.

Stored Procedure

Stored Procedure

Visual Studio

Crie um novo projeto C# e utilize a imagem abaixo para criar o design da aplicação utilizando 2 componentes Panels, 7 componentes Labels, 6 TextBoxes e um componente Button.

Design

Design

 

Exemplo:

Neste exemplo utilizamos Stored Procedures que retornam parâmetros para criar um método dentro do banco de dados ao invés de criar o método dentro da aplicação utilizando a linguagem de programação nativa.

Ao contrario da linguagem de programação Java não podemos utilizar o mesmo objeto para manipular todos os bancos de dados e utilizar todos os seus recursos ao mesmo tempo, a não ser se pretendermos restringir a aplicação apenas aos recursos comuns entre os três bancos de dados e utilizar apenas os drivers fornecidos pela Microsoft.

Obs: Para criar uma Stored Procedure utilizando o IBM Data Studio, você deve utilizar o editor de procedures e não o editor comum de SQL, pois encontrará um erro do caractere ponto e virgula no momento de escrever sua sintaxe.

Oracle

create or replace PROCEDURE buscaFuncionario
- Cria parametros
(pid_funcionario IN FUNCIONARIOS.ID_FUNCIONARIO%TYPE,
 p_nome OUT FUNCIONARIOS.NOME%TYPE,
 p_sobrenome OUT FUNCIONARIOS.SOBRENOME%TYPE,
 p_cargo OUT FUNCIONARIOS.CARGO%TYPE,
 p_salario OUT FUNCIONARIOS.SALARIO%TYPE
 )
AS
BEGIN
-- Insere dados da query dentro dos parametros de saida
  SELECT NOME, SOBRENOME, CARGO, SALARIO
  INTO p_nome, p_sobrenome, p_cargo, p_salario
  FROM FUNCIONARIOS
  WHERE ID_FUNCIONARIO = pid_funcionario;

END;

DB2

-- Cria procedure
CREATE PROCEDURE buscaFuncionario
( IN pid_funcionario INTEGER,
  OUT p_nome VARCHAR(30),
  OUT p_sobrenome VARCHAR(70),
  OUT p_cargo VARCHAR(30),
  OUT p_salario DECIMAL(9,2)
 )

P1: BEGIN

  SELECT NOME, SOBRENOME, CARGO, SALARIO
  INTO p_nome, p_sobrenome, p_cargo, p_salario
  FROM FUNCIONARIOS
  WHERE ID_FUNCIONARIO = pid_funcionario;

END P1

MSSQL

CREATE PROCEDURE buscaFuncionario
   @pfuncionario INT,
   @pnome		 NVarchar(30) OUTPUT,
   @psobrenome	 NVarchar(70) OUTPUT,
   @pcargo	     NVarchar(30) OUTPUT,
   @psalario	 Decimal(9,2) OUTPUT
AS
BEGIN
   SELECT @pnome = Nome,
		  @psobrenome = Sobrenome,
		  @pcargo = Cargo,
		  @psalario = Salario
   FROM Funcionarios
   WHERE ID_Funcionario = @pfuncionario
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 StoredCs
{
    public partial class Procedures : Form
    {
        // Declara componentes de conexão
        private static OracleConnection connORA; // ODAC 12c
        private static DB2Connection connDB2;   // IBM Data Server Provider
        private static SqlConnection connMSSQL; // ADO .NET

       // ************** Sobre Conexões - ADO.NET **************
       //
       // A Microsoft disponibiliza por exemplo, o System.Data.OracleClient
       // porem se tornou obsoleto e ainda é suportado somente
       // a nível de compatibilidade com versões anteriores do Framework.
       // A Microsoft recomenda utilizar o driver de cada fornecedor:
       //
       // veja: http://msdn.microsoft.com/en-us/library/77d8yct7.aspx
       //
       // Você pode utilizar a classe DbProviderFactory
       // para criar um único datasource para todos os bancos de dados:
       //
       // http://msdn.microsoft.com/pt-br/library/system.data.common.dbproviderfactory(v=vs.110).aspx
       //
       // No entanto diferentemente da linguagem JAVA (JDBC) o ADO.NET não suporta
       // alguns recursos do Oracle e IBM DB2.
       //
       // *** Factory ***
       //
       // Utilizando conexões únicas de cada provedor de banco de dados
       // através de um Factory, permite que você utilize um único set de instruções
       // para todos os bancos de dados.
       //
       // Atente-se que se utilizar instruções únicas, em alguns casos poderá encontrar
       // alguns erros de compatibilidade ou criar certas limitações a outros bancos.
       // O ADO.NET é desenvolvido para o MSSQL Server e está sujeito
       // a algumas limitações quando utilizar alguns tipos de campos,
       // conceitos de conexão e acesso a dados de outros bancos de dados.
       //
       // Sistemas de grande porte possuem um Dicionário de dados
       // para se prevenir destas situações.
       //
       // Veja este mesmo programa utilizando o DriverManager equivalente ao factory para java
       // e veja comentários extras no código apontando diferenças de conceitos.

        // Declara variável do banco de dados
        private static string DBconexao;

        public Procedures()
        {
            InitializeComponent();
        }

        public void conectarDB(string banco)
        {
            DBconexao = banco;

            if (banco == "oracle")
            {

                try
                {
                    // String de Conexao
                    string connectionString =

                    // Usuario
                    "User Id=daberto" +

                    // Senha
                    ";Password=p@55w0rd" +

                    // TNSnames
                    ";Data Source=XE";

                    //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());
                }
            }

            if (banco == "db2")
            {
                try
                {
                    // String de Conexao
                    string connectionString =

                        // Servidor
                        "Server=localhost" +

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

                        // Usuario
                        ";UID=db2admin" +

                        // Senha
                        ";PWD=p@55w0rd" +

                        // Timeout
                        ";Connect Timeout=40";

                    //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());

                }

            }

            if (banco == "mssql")
            {
                try
                {
                    // String de Conexao
                    string connectionString =

                        // Servidor
                        "Data Source=localhost" +

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

                        // Usuario
                        ";User ID =devaberto" +

                        // Senha
                        ";Password=p@55w0rd" +

                        // Timeout
                        ";Connect Timeout=40";

                    //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());

                }

            }

        }

        private void button1_Click(object sender, EventArgs e)
        {
            // Cria instancia do objeto
            Procedures proc = new Procedures();

            // A variável abaixo:
            // Define banco de dados
            // oracle = Oracle Database
            // db2    = IBM DB2 Database
            // mssql  = Microsoft SQL Server
            proc.conectarDB("db2");

            // Define conexão
            label7.Text = "Database - Stored Procedure - " + DBconexao;

            // Define comandos
            // Um problema com as classes do ADO.NET entre o Oracle e o IBM DB2
            // são a incompatibilidade de drivers e alguns dos tipos de campos.
            // Se você pretende utilizar todos os recursos destes bancos você não pode
            // utilizar um driver ADO.NET Nativo e sim um driver do proprio fabricante.
            // Apesar da sintaxe ser igual, em certos casos não é possível utilizar um unico comando
            // para manipular dados entre todos os bancos.

            OracleCommand cmdORA;
            DB2Command cmdDB2;
            SqlCommand cmdSQL;            

            if (DBconexao== "oracle")
            {
                // Define a instrução SQL e a conexão
                cmdORA = new OracleCommand("buscaFuncionario", connORA);

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

                // Define parametros, tipos de campos e direção
                cmdORA.Parameters.Add("pid_funcionario", OracleDbType.Double).Value = Convert.ToDouble(textBox1.Text);
                cmdORA.Parameters.Add("p_nome", OracleDbType.Varchar2, 30).Direction = ParameterDirection.Output;
                cmdORA.Parameters.Add("p_sobrenome", OracleDbType.Varchar2, 70).Direction = ParameterDirection.Output;
                cmdORA.Parameters.Add("p_cargo", OracleDbType.Varchar2, 30).Direction = ParameterDirection.Output;
                cmdORA.Parameters.Add("P_salario", OracleDbType.Decimal).Direction = ParameterDirection.Output;

                // Executa query
                cmdORA.ExecuteNonQuery();

                // Neste caso você pode alimentar variaveis e
                // criar uma unica exibição para todos os bancos
                // optamos neste exemplo pelo classico CTRL+C  e CTRL + V

                textBox2.Text = textBox1.Text;
                textBox3.Text = cmdORA.Parameters[1].Value.ToString();
                textBox4.Text = cmdORA.Parameters[2].Value.ToString();
                textBox5.Text = cmdORA.Parameters[3].Value.ToString();
                textBox6.Text = cmdORA.Parameters[4].Value.ToString();
            }

            // Aqui foi efetuado um CTRL + C e um CTRL + V
            // Mudando apenas os drivers, uma opção é criar um dicionario de dados

            if (DBconexao == "db2")
            {
                cmdDB2 = new DB2Command("buscaFuncionario", connDB2);

                cmdDB2.CommandType = CommandType.StoredProcedure;

                cmdDB2.Parameters.Add("pid_funcionario", DB2Type.Integer).Value = Convert.ToInt32(textBox1.Text);
                cmdDB2.Parameters.Add("p_nome", DB2Type.VarChar, 30).Direction = ParameterDirection.Output;
                cmdDB2.Parameters.Add("p_sobrenome", DB2Type.VarChar, 70).Direction = ParameterDirection.Output;
                cmdDB2.Parameters.Add("p_cargo", DB2Type.VarChar, 30).Direction = ParameterDirection.Output;
                cmdDB2.Parameters.Add("p_salario", DB2Type.Decimal).Direction = ParameterDirection.Output;

                cmdDB2.ExecuteNonQuery();

                textBox2.Text = textBox1.Text;
                textBox3.Text = cmdDB2.Parameters[1].Value.ToString();
                textBox4.Text = cmdDB2.Parameters[2].Value.ToString();
                textBox5.Text = cmdDB2.Parameters[3].Value.ToString();
                textBox6.Text = cmdDB2.Parameters[4].Value.ToString();

            }

            if (DBconexao == "mssql")
            {
                cmdSQL = new SqlCommand("buscaFuncionario", connMSSQL);

                cmdSQL.CommandType = CommandType.StoredProcedure;

                cmdSQL.Parameters.Add("@pfuncionario", SqlDbType.Int).Value = Convert.ToInt32(textBox1.Text);
                cmdSQL.Parameters.Add("@pnome", SqlDbType.NVarChar, 30).Direction = ParameterDirection.Output;
                cmdSQL.Parameters.Add("@psobrenome", SqlDbType.NVarChar, 70).Direction = ParameterDirection.Output;
                cmdSQL.Parameters.Add("@pcargo", SqlDbType.NVarChar, 30).Direction = ParameterDirection.Output;
                cmdSQL.Parameters.Add("@Psalario", SqlDbType.Decimal).Direction = ParameterDirection.Output;

                cmdSQL.ExecuteNonQuery();

                textBox2.Text = textBox1.Text;
                textBox3.Text = cmdSQL.Parameters[1].Value.ToString();
                textBox4.Text = cmdSQL.Parameters[2].Value.ToString();
                textBox5.Text = cmdSQL.Parameters[3].Value.ToString();
                textBox6.Text = cmdSQL.Parameters[4].Value.ToString();

            }
        }
    }
}

Stored Procedures são procedimentos de código SQL armazenados no banco de dados, as stored procedures são mais rápidas do que o código tradicional, o que significa que elas estão se tornando cada vez mais populares. Com código da aplicação se mudando dos programas externos para o motor de banco de dados, Os DBAs precisam entender os requisitos de memória relacionados para procedimentos armazenados e saber como gerenciar estes procedimentos para o ideal desempenho do banco de dados. Isto muda de banco para banco, cada um deles possui suas recomendações de melhores praticas para atingir um melhor desempenho.

Neste site existe uma versão deste mesmo programa utilizando código SQL direto dentro da aplicação e podemos comparar a diferença com o código SQL sendo executado dentro do motor do banco de dados e o resultado é visivelmente notado, sem duvida o código executado utilizando procedures é mais rápido.

Ainda existe um outro modo de utilizar o banco de dados que é utilizando um set de dados persistente, onde uma camada  de classes ou componentes geram o código SQL para o banco de dados através de instruções definidas pelas classes, mas este método por possuir uma camada que cria o código para o banco pode se tornar menos atrativo em termos de desempenho, apesar de ser muito mais fácil e rápido para se desenvolver, sendo assim vale avaliar a quantidade de dados que sua aplicação pretende manipular.

Para adquirir o script SQL para criar a tabela deste exemplo ou visualizar o método utilizando SQL direto da aplicação: Clique Aqui.

Stored Procedure

Stored Procedure

Vantagens de utilizar Stored Procedures

Esta explicação é dirigida ao banco de dados Oracle, porem também se aplica aos bancos de dados DB2 e MSSQL, levando-se em conta a arquitetura do motor (engine) de cada um dos bancos de dados, para uma definição mais precisa consulte as especificações de cada um dos bancos de dados.

Melhor desempenho

Procedimentos armazenado Oracle carregam uma vez no pool comum e permanecem lá a menos que eles se tornem paginados. Execuções subsequentes do procedimento armazenado Oracle são muito mais rápidos do que as execuções de código externo.

Acoplamento de dados com comportamentos.

Os DBAs podem usar convenções de nomenclatura para tabelas relacionais pares com os comportamentos associados a uma tabela usando os procedimentos armazenados do Oracle como “métodos”.

Isolamento de código.

Uma vez que todos os códigos SQL forem movidos para fora dos programas externos e para dentro dos procedimentos armazenados do Oracle, os programas de aplicação tornam-se nada mais do que chamadas para procedimentos armazenados. Como tal, torna-se muito simples de trocar de um banco de dados para outro.

Exemplo:

Neste exemplo utilizamos Stored Procedures que retornam parâmetros para criar um método dentro do banco de dados ao invés de criar o método dentro da aplicação utilizando a linguagem de programação nativa. Deste modo podemos utilizar o mesmo programa sem alterar uma única linha e utiliza-lo em vários bancos de dados diferentes e ainda obter a melhor performance na execução de instruções SQL.

Obs: Para criar uma Stored Procedure utilizando o IBM Data Studio, você deve utilizar o editor de procedures e não o editor comum de SQL, pois encontrará um erro do caractere ponto e virgula no momento de escrever sua sintaxe.

Oracle

create or replace PROCEDURE buscaFuncionario
- Cria parametros
(pid_funcionario IN FUNCIONARIOS.ID_FUNCIONARIO%TYPE,
 p_nome OUT FUNCIONARIOS.NOME%TYPE,
 p_sobrenome OUT FUNCIONARIOS.SOBRENOME%TYPE,
 p_cargo OUT FUNCIONARIOS.CARGO%TYPE,
 p_salario OUT FUNCIONARIOS.SALARIO%TYPE
 )
AS
BEGIN
-- Insere dados da query dentro dos parametros de saida
  SELECT NOME, SOBRENOME, CARGO, SALARIO
  INTO p_nome, p_sobrenome, p_cargo, p_salario
  FROM FUNCIONARIOS
  WHERE ID_FUNCIONARIO = pid_funcionario;

END;

DB2

-- Cria procedure
CREATE PROCEDURE buscaFuncionario
( IN pid_funcionario INTEGER,
  OUT p_nome VARCHAR(30),
  OUT p_sobrenome VARCHAR(70),
  OUT p_cargo VARCHAR(30),
  OUT p_salario DECIMAL(9,2)
 )

P1: BEGIN

  SELECT NOME, SOBRENOME, CARGO, SALARIO
  INTO p_nome, p_sobrenome, p_cargo, p_salario
  FROM FUNCIONARIOS
  WHERE ID_FUNCIONARIO = pid_funcionario;

END P1

MSSQL

CREATE PROCEDURE buscaFuncionario
   @pfuncionario INT,
   @pnome		 NVarchar(30) OUTPUT,
   @psobrenome	 NVarchar(70) OUTPUT,
   @pcargo	     NVarchar(30) OUTPUT,
   @psalario	 Decimal(9,2) OUTPUT
AS
BEGIN
   SELECT @pnome = Nome,
		  @psobrenome = Sobrenome,
		  @pcargo = Cargo,
		  @psalario = Salario
   FROM Funcionarios
   WHERE ID_Funcionario = @pfuncionario
END

Java

import java.awt.ComponentOrientation;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.Border;
import javax.swing.border.EtchedBorder;

public class Campos implements ActionListener {
	// Declara componentes
	private JLabel ltitulo;
	private JLabel lid;
	private JLabel lpnome;
	private JLabel lsnome;
	private JLabel lcargo;
	private JLabel lsalario;
	private JLabel lpesquisa;

	private JTextField tid;
	private JTextField tpnome;
	private JTextField tsnome;
	private JTextField tcargo;
	private JTextField tsalario;
	private JTextField tpesquisa;

	private JButton botao;

	private Border borda;

	private JFrame menssagem;

	// Declara objetos de conexão
	private static Connection conn;
	private static Statement query;

	// Declara variaveis
	private static String bconexao;

	// Cria conexão
	public void conectar(String banco) {

		// Verifica strings de conexão

		// ORACLE
		if (banco == "oracle") {
			try {
				// Define Driver de conexão JDBC thin
				Class.forName("oracle.jdbc.driver.OracleDriver");
				conn = DriverManager.getConnection(
						"jdbc:oracle:thin:@localhost:1521:xe", "daberto",
						"p@55w0rd");

				// Executa pedido SQL
				query = conn.createStatement();

			}

			catch (ClassNotFoundException ex) {
				ex.printStackTrace();
			}

			catch (SQLException ex) {
				ex.printStackTrace();
			}
		}

		// DB2
		if (banco == "db2") {
			try {
				// Define Driver de conexão JDBC
				Class.forName("com.ibm.db2.jcc.DB2Driver");
				conn = DriverManager.getConnection(
						"jdbc:derby:net://localhost:50000/deva", "db2admin",
						"p@55w0rd");

				// Executa pedido SQL
				query = conn.createStatement();
				// JOptionPane.showMessageDialog(menssagem,
				// "Conexão Efetuada com sucesso!");
			}

			catch (ClassNotFoundException ex) {
				ex.printStackTrace();
			}

			catch (SQLException ex) {
				// JOptionPane.showMessageDialog(menssagem, "Erro na conexão!");
				ex.printStackTrace();
			}

		}

		// MICROSOFT SQL SERVER
		if (banco == "mssql") {
			try {
				// Define Driver de conexão JDBC
				String URL = "jdbc:sqlserver://localhost\\SQLEXPRESS:1433;databaseName=devaberto"
						+ ";user=devaberto;password=p@55w0rd";

				Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
				conn = DriverManager.getConnection(URL);

				// Executa pedido SQL
				query = conn.createStatement();

			}

			catch (ClassNotFoundException ex) {
				ex.printStackTrace();
			}

			catch (SQLException ex) {
				ex.printStackTrace();
			}

		}

	}

	public Container criaPainel() {
		// cria painel
		JPanel painel = new JPanel();
		painel.setLayout(new FlowLayout());
		painel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
		painel.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
		// Cria titulo
		ltitulo = new JLabel("Database - Stored Procedures - Sem conexão");

		painel.add(ltitulo);
		painel.add(Box.createVerticalStrut(60));

		// Cria painel de usuario
		JPanel painelDados = new JPanel(new GridLayout(0, 2, 10, 10));

		// Cria componentes
		lid = new JLabel("Código:");
		lpnome = new JLabel("Primeiro Nome:");
		lsnome = new JLabel("Sobrenome:");
		lcargo = new JLabel("Cargo:");
		lsalario = new JLabel("Salário:");

		tid = new JTextField();
		tpnome = new JTextField();
		tsnome = new JTextField();
		tcargo = new JTextField();
		tsalario = new JTextField();

		tid.setPreferredSize(new Dimension(150, 20));
		// Adiciona componentes no painel
		painelDados.add(Box.createVerticalStrut(10));
		painelDados.add(Box.createVerticalStrut(10));
		painelDados.add(lid);
		painelDados.add(tid);
		painelDados.add(lpnome);
		painelDados.add(tpnome);
		painelDados.add(lsnome);
		painelDados.add(tsnome);
		painelDados.add(lcargo);
		painelDados.add(tcargo);
		painelDados.add(lsalario);
		painelDados.add(tsalario);
		painelDados.add(Box.createVerticalStrut(10));
		painelDados.add(Box.createVerticalStrut(10));

		// Cria painel de pesquisa
		JPanel painelPesquisa = new JPanel(new GridLayout(0, 3, 10, 10));
		borda = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);
		painelPesquisa.setBorder(borda);

		// Cria pesquisas
		lpesquisa = new JLabel("Pesquisa código:");
		tpesquisa = new JTextField();
		botao = new JButton("Pesquisar");
		botao.addActionListener(this);

		// Define foco do cursor no campo de pesquisa
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				tpesquisa.requestFocus();
			}
		});

		// Adiciona compoentes ao painel de pesquisa
		painelPesquisa.add(lpesquisa);
		painelPesquisa.add(tpesquisa);
		painelPesquisa.add(botao);

		// Cria painel de pesquisa

		// Adiciona paineis
		painel.add(painelPesquisa);
		painel.add(painelDados);

		return painel;
	}

	// Clique do botão de pesquisa
	public void actionPerformed(ActionEvent arg0) {

		// Verifica pesquisa
		if (arg0.getSource() == botao) {

			// retorna result de dados
			CallableStatement proc = null;

			try {
				// Exibe a conexão utilizadda
				ltitulo.setText("Database - Stored Procedures - " + bconexao);

				// Prepara stored procedure
				proc = conn.prepareCall("{call buscaFuncionario(?,?,?,?,?)}");

				// Define parametro de entrada
				proc.setInt(1, Integer.parseInt(tpesquisa.getText()));

				// Registra parametros de saida
				proc.registerOutParameter(2, java.sql.Types.VARCHAR);
				proc.registerOutParameter(3, java.sql.Types.VARCHAR);
				proc.registerOutParameter(4, java.sql.Types.VARCHAR);
				proc.registerOutParameter(5, java.sql.Types.DECIMAL);

				// Executa stored procedure
				proc.execute();			

				// Preenche campos da tela

				tid.setText(tpesquisa.getText());
				tpnome.setText(proc.getString(2));
				tsnome.setText(proc.getString(3));
				tcargo.setText(proc.getString(4));
				tsalario.setText(proc.getString(5));				

			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}

	public static void criaGUI() {
		// Cria formulario
		JFrame formulario = new JFrame("Desenvolvimento Aberto");
		formulario.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		// cria painel de conteudo
		Campos acesso = new Campos();
		// conecta ao banco de dados defindo
		// mude a variavel bconexao para escolher o banco de dados
		// importe os drivers para o projeto
		// oracle = ORACLE
		// db2 = IBM DB2
		// mssql = MSSQL Server

		bconexao = "db2";
		acesso.conectar(bconexao);
		formulario.setContentPane(acesso.criaPainel());

		// Exibe o formulario
		formulario.setSize(400, 380);
		formulario.setVisible(true);

	}

	public static void main(String[] args) {

		javax.swing.SwingUtilities.invokeLater(new Runnable() {

			@Override
			public void run() {

				// Mostra GUI
				criaGUI();

			}
		});

	}

}

A linguagem de programação Ruby e o framework Rails torna muito simples alterar dados em uma pagina web através dos controles EDIT e UPDATE do controlador MVC.

Nosso objetivo será criar uma nova visão (VIEW) para o modelo de dados “empresa” (MODEL) e utilizar as ações de edição e alteração do controlador (CONTROLLER) para manipular os dados contidos em nosso banco de dados MySQL.

Formulário de Edição

1 – Primeiro precisamos modificar a visão da pagina principal para que seja exibido um link para nossa pagina de edição que utiliza a rota do controlador criada anteriormente:

Indice

Índice

2 – Agora precisamos criar um novo arquivo de visão para exibir o formulário de alteração de dados chamado new.html.erb e precisamos modificar também o controlador para que seja executada ações requeridas.

Formulário de Alteração

Formulário de Alteração

Exemplo:

Neste exemplo criamos uma nova visão sobre a ação de edição do controlador para editar nossos dados.

Visão – index.html.erb

<h2>Desenvolvimento Aberto</h2>
<p>Lista de Blogs e Projetos Open Source</p>
<pre>
<table width="500">
<tr>
	<th>Cod:</th>
	<th>&nbsp;&nbsp;</th>
	<th>Empresa:</th>
	<th>&nbsp;&nbsp;</th>
	<th>Site:</th>
	<th>&nbsp;&nbsp;</th>
	<th>Evento:</th>
</tr>
<% @empresas.each do |empresa| %>

<tr>
<td><%= empresa.codigo%> </td>
<td>&nbsp;&nbsp;</td>
<td><%= link_to empresa.nome, empresa %> </td>
<td>&nbsp;&nbsp;</td>
<td><%= empresa.site%> </td>
<td>&nbsp;&nbsp;</td>
<td><%= link_to "Editar", edit_empresa_path(empresa) %> </td>

</tr>

<%end%>
</table>

<p> <%= link_to "Adicionar um novo registro", new_empresa_path %> </p>
</pre>

Visão – edit.html.erb

<h2>Editar Empresa</h2>

<%= form_for @empresa do |cad| %>

    <p>
		<%= cad.label :codigo%> <br />
		<%= cad.text_field :codigo%>
	</p>

	<p>
		<%= cad.label :nome%> <br />
		<%= cad.text_field :nome%>
	</p>

	<p>
		<%= cad.label :site%> <br />
		<%= cad.text_field :site%>
	</p>

	<p>
		<%= cad.label :projeto%> <br />
		<%= cad.text_field :projeto%>
	</p>

	<p>
		<%= cad.label :tipo%> <br />
		<%= cad.text_field :tipo%>
	</p>

	<p>
		<%= cad.label :linguagem%> <br />
		<%= cad.text_field :linguagem%>
	</p>

	<p>
		<%= cad.label :descricao%> <br />
		<%= cad.text_field :descricao%>
	</p>

	<p> <%= cad.submit "Alterar dados" %></p>

<%end%>

Contolador – empresa_controller.rb

class EmpresasController < ApplicationController

  def index
    @empresas = Empresa.all
  end

  def show
    @empresa = Empresa.find(params[:id])
  end

  def new
    @empresa = Empresa.new
  end

  def create
    @empresa = Empresa.new(empresa_params)
    if @empresa.save
      redirect_to empresas_path :notice => "Seu registro foi criado com sucesso"
    else
      render "new"
    end
  end

  def edit
    @empresa = Empresa.find(params[:id])
  end

  def update
    @empresa = Empresa.find(params[:id])

    if @empresa.update_attributes(empresa_params)
      redirect_to empresas_path :notice => "Seu registro foi alterado com sucesso"
    else
      render "edit"
    end
  end

  private

  def empresa_params
    params.require(:empresa).permit(:codigo, :nome, :site, :projeto, :tipo, :linguagem, :descricao)
  end

end