domingo, 4 de maio de 2008

SQL dinâmico no Oracle

Existe alguma forma de criar dinamicamente um comando SQL, tanto DML quanto DDL, no Oracle?

Sim, é possível. A partir da versão 8i podemos usar o "EXECUTE IMMEDIATE" statement para executar um comando SQL montado em tempo de execução. Essa funcionalidade foi introduzida para substituir o “DBMS_SQL package”. Veja alguns exemplos abaixo:

-- Executando comando DDL “Create”
EXECUTE IMMEDIATE 'CREATE TABLE MyZNTable (ZN_ID NUMBER, ZNDescricao Varchar2(30))';

--- executando comando DML “INSERT”
EXECUTE IMMEDIATE 'insert into MyZNTable values (1, ''ZNteste'') ’;



Esse comando é um recurso nativo do Oracle para abordagem de SQL dinâmico, apropriado para tuning pois reduz overhead, otimiza a performance do comando SQL. Considerando que, Comandos SQL criados e executados dinamicamente apresentam overhead em performance. Utilização do comando "EXECUTE IMMEDIATE" reduz este overhead e proporciona maior performance.
Através dessa técnica podemos também usar placeholders para bind.
O que é placeholder? R - Um placeholder é um identificador não declarado que vai servir como parâmetro, cujo o valor será atribuído dinamicamente. O compilador SQL vai entender o identificador porque ele estará marcado com o prefixo, o sinal de “:” (dois pontos).

DECLARE
V_NUM_CONTRATO varchar2(20) := 'ZN1000';
V_NUM_GUIA varchar2(10) := '3000ZN';
ZnSQL_TMP VARCHAR2 (100);
BEGIN
-- Busca ASSOCIADO, DATA DE CADASTRO, e ORIGEM
ZnSQL_TMP := ' SELECT
DATA_CADASTRO, COD_ASSOCIADO, ASSOCIADO_ORIGEM
FROM
ASSOCIADOS
WHERE
NUM_CONTRATO = :NUM_CONTRATO AND
NUM_GUIA = :NUM_GUIA AND
ROWNUM = 1';

EXECUTE IMMEDIATE ZnSQL_TMP
USING V_NUM_CONTRATO
, V_NUM_GUIA;

END;



Acredito que isso pode facilitar muito o trabalho de desenvolvedor. Portanto, vejamos maiores detalhes sobre a sintaxe desse comando:

EXECUTE IMMEDIATE ZNSQL_string
[INTO {variável[, variável]...
| record}]
[USING [IN | OUT | IN OUT] bind_argument
[, [IN | OUT | IN OUT] bind_argument]...];

Analisando a sintaxe:

ZNSQL_string : Trata-se de uma string com comando SQL construído dinamicamente, conforme exemplificamos anteriormente. Essa string pode conter qualquer comando SQL sem o terminador. Comandos DML “SELECT” não devem retornar mais de uma linha. A string também pode conter placeholders (exemplo: :ZN_ASSOCIADO) e bind_arguments. Um detalhe importante, caso o camando SQL na string for uma chamada a uma procedure ou function (ou seja, uma PL/SQL) é necessário o emprego de “begin” e “end”.

INTO (palavra reservada): Indica quais variáveis (uma ou mais) cujos valores selecionados, em uma consulta, serão atribuídos. O record é um TYPE ou %ROWTYPE definido pelo usuário. Ele pode receber uma linha inteira retornada por uma consulta. Atenção, esta cláusula é opcional. É utilizada somente quando a String for uma consulta que retorne somente uma linha. Além disso, tanto a quantidade de variáveis empregadas, quanto a ordem em que elas estarão dispostas no comando, deve respeitar a quantidade e a ordem das colunas retornadas na consulta. Do mesmo modo, o tipo da variável ou registro (record) deve ser compatível com o valor que lhe será atribuído.

USING (palavra reservada): seção onde declaramos os valores atribuídos a cada argumento na bind variables da string. Não é permitido fazer bind para repassar nomes de objetos de um esquema, como nomes de tabelas ou de colunas. Também não é permitido valor booleano ou NULL. Suponha que o código exemplificado abaixo seja o trecho de uma procedure ou function:


SQL_TMP VARCHAR2 (1000);
BEGIN

SQL_TMP := ' SELECT
DATA_REALIZACAO, COD_ASSOCIADO, ORIGEM
FROM
ASSOCIADOS
WHERE
MES_REF = :MES_REF AND
COD_CONTADOR = :COD_CONTADOR AND
NUM_CONTRATO = :NUM_CONTRATO AND
NUM_GUIA = :NUM_GUIA AND
ROWNUM = 1';
BEGIN
EXECUTE IMMEDIATE SQL_TMP
INTO V_DATA_REALIZACAO, V_COD_ASSOCIADO, V_ORIGEM
USING V_MES_REF
, V_COD_CONTADOR
, V_NUM_CONTRATO
, V_NUM_GUIA;
EXCEPTION
WHEN no_data_found THEN
V_DATa_ZN := NULL;
V_NUM_ASSOCIADO_ZN := NULL;
END;

Preciso retornar várias linhas de uma consulta usando SQL dinâmico. Isso é possível?

Como mencionei anteriormente, consultas que retornem mais de uma linha não são suportadas como valor de retorno. Entretanto, existem alternativas: Ou utilizar uma tabela temporária para armazenar os registros, ou ref cursores.

Adiante, pretendo falar mais sobre o emprego do “EXECUTE IMMEDIATE”.

Artigo completo (View Full Post)

sábado, 3 de maio de 2008

SQL - Operador "LIKE" & ESCAPE

Para a utilização do operador “LIKE”, ANSI SQL, usa-se os caracteres coringas ‘_’, ou ‘%’. Veja o exemplo abaixo:

select
*
from (
select
column_value col
from
table(ts.split_varchar2('Jan,Fev,Mar,Abr,Mai,Jun,Jul,Ago,Set,Out,Nov,Dez', ','))
) q
WHERE col like 'J_n'

Acima, vimos o exemplo do coringa posicional. Ou seja, para posição que o underscore ocupar na substring de busca, no filtro, o compilador irá interpretar que qualquer caractere serve. O nosso filtro busca qualquer string de três caracteres cujo a primeira posição é ocupada pelo “J” e a última pelo “n”, a posição do meio é o coringa, portanto, qualquer caractere serve. Por isso obtivemos como resultado: “Jan” e “Jun”. Vejamos outro exemplo usando o “%”:


select
*
from (
select column_value col
from
table(ts.split_varchar2('Jan,Fev,Mar,Abr,Mai,Jun,Jul,Ago,Set,Out,Nov,Dez', ','))
) q
WHERE col like 'J%'



Recapitulando, o underscore é um coringa posicional. Veja que, se por exemplo, na cláusula “where” o valor para o filtro for modificado para “like '_a_'” o resultado do select vai ser: Jan, Mar, Mai. Retornará todos os meses que possuírem a letra “a” como segundo caractere. Conforme exemplificado abaixo:


select
*
from (
select column_value col
from table(ts.split_varchar2('Jan,Fev,Mar,Abr,Mai,Jun,Jul,Ago,Set,Out,Nov,Dez', ','))
) q
WHERE col like '_a_'


O Problema que muitos desenvolvedores eventualmente enfrentam é quando o caractere coringa é justamente o que ele quer usar como filtro. Por exemplo:

select
*
from (
select column_value col
from table(ts.split_varchar2('Jan,Jan_2008,Fev,Mar,Abr,Mai,Jun,Jul,Ago,Set,Out,Nov,Dez', ','))
) q
WHERE col like '%_%'


Se você tentar encontrar o registro pela presença do caractere “underscore” o resultado do select não será o esperado. Conforme ilustrado abaixo:



Uma solução, é usar a palavra reservada “ESCAPE”. Desta forma você indica ao compilador SQL qual caractere coringa você deseja que ele considere para busca. Exemplo:

select
*
from (
select column_value col
from
table(ts.split_varchar2('Jan,Jan_2008,Fev,Mar,Abr,Mai,Jun,Jul,Ago,Set,Out,Nov,Dez', ','))
) q
WHERE col like '%@_%' ESCAPE '@'

Para usar corretamente o ESCAPE, você precisa primeiro marcar o coringa com outro caractere o operando do “like”, exemplo: “like '%@_%'”. Em seguida, o operador do ESCAPE identifica o caractere que marcou o coringa. Exemplo: “ESCAPE '@'”.
Agora o resultado do filtro aplicado retornará o que desejamos:


Outro exemplo:


select
*
from (
select column_value col
from table(ts.split_varchar2('Jan,Jan_2008,Fev_%,Mar,Abr,Mai,Jun,Jul,Ago,Set,Out,Nov,Dez', ','))
) q
WHERE col like '%@_2008' ESCAPE '@'




Se trocarmos o marcador, de “@” para “/” visando tornar nosso exemplo mais claro. Além disso, vamos testar usar como filtro a presença do caractere “%”. Para isso inclui o elemento “Fev%Wanddjah” no conjunto a ser selecionado.


select
*
from (
select column_value col
from table(ts.split_varchar2('Jan,Jan_2008, Fev,Fev%Wanddjah,Mar,Abr,Mai,Jun,Jul,Ago,Set,Out,Nov,Dez', ','))
) q
WHERE col like '%/%Wanddjah' ESCAPE '/'


Veja o resultado:




Outra opção para solução seria usar expressões regulares:

select
*
from (
select column_value col
from table(ts.split_varchar2('Jan,Jan_2008, Jan\Fev ,Fev,Fev%Wanddjah,Mar,Abr,Mai,Jun,Jul,Ago,Set,Out,Nov,Dez', ','))
) q
WHERE REGEXP_LIKE(col,'\')

O ESCAPE do expressões regulares é o “\” .O exemplo acima retorna todos os registros. Para escapar o especial do caractere “\” caso você precise do seu valor literal use o próprio, conforme exemplificado abaixo:
select
*
from (
select column_value col
from table(ts.split_varchar2('Jan,Jan_2008, Jan\Fev ,Fev,Fev%Wanddjah,Mar,Abr,Mai,Jun,Jul,Ago,Set,Out,Nov,Dez', ','))
) q
WHERE REGEXP_LIKE(col,'\\').


Agora obteremos como retorno apenas: “Jan\Fev”.

O mesmo vale para os demais metacaracteres. Exemplo: “\.”, “\[”, “\]”, “\?”, “\+”, “\{” , “\}”, “\^”, e “\$”.

Artigo completo (View Full Post)

sábado, 26 de abril de 2008

"ADO Recordset" desconectado

A seguir, vamos demonstrar uma sacada genial do Felipe Gerço: Trabalhando com um "ADO Command" desconectado no VB6 (Semelhentemente ao que fazemos no Delphi com um "dataset").


Dim rsZN As New ADODB.Recordset

Private Sub SetupCommandDesconectado()
On Error Resume Next
rsZN.Close 'Se ele não estiver aberto vair ocorer uma exceção

rsZN.LockType = adLockBatchOptimistic
rsZN.CursorLocation = adUseClient
rsZN.CursorType = adOpenStatic

rsZN.Fields.Append "DescricaoZn", adVarChar, 200
rsZN.Fields.Append "ValorZn", adDouble

rsZN.Open

End Sub

Private Sub Command4_Click()
rsZN.AddNew Array("DescricaoZn", "ValorZn"), Array(Text1.Text, Text2.Text)

End Sub


Artigo completo (View Full Post)

quinta-feira, 24 de abril de 2008

Configuração de um DataSet de para Select, Insert, Update e Delete- CRUD - For Dummies

Num cadastro padrão (CRUD), como configurar os DataSets de Manipulação de dados:

1 - Adicione o DataSet ao DataModule.

2 - Nomeie o DataSet. Exemplo: AdsClientes.

3 - Associe o DataSet ao conector do banco de dados: Através da propriedade “Connection” (Caso esteja trabalhado com ADO), ou “SQLConnection” (caso trabalhe com DBExpress), ou “DataBase” (caso a tecnologia de acesso a dados seja DBE ou IBExpress).

4 - Defina o comando SQL genérico na propriedade específica para isso:
  • TADODataSet, TSQLDataSet – propriedade “CommandText”.
  • TQuery, TADOQuery, TIBQuery – propriedade “SQL”.

Obs: TQuery deve trabalhar associado ao TUpdateSQL (o TIBQuery, igualmente com o seu correlato). Isso porque, eles não possuem a capacidade de gerar sozinhos os comandos de “insert”, “Update”, “Delete”.

O Comando SQL padrão para um dataset que fará inclusão, alteração e deleção deve ser:

  • Selecionar todas as colunas da tabela (a qual se deseja construir o cadastro). Filtrando sempre pela chave primária usando para isso o operador relaciona de igualdade “=”. Exemplo genérico:

SELECT
*
FROM
[Nome da Tabela]
WHERE
[“ColunaPK”] = :parametro



Exemplo específico:


SELECT
*
FROM
Clientes
WHERE
ClienteID = :pID


OBS: O símbolo : determina um parâmetro, o qual, no programa Delphi, receberá dinamicamente valor (muitas vezes da interface) , para então executar comando SQL retornando para a aplicação os dados desejados.

5 - Configurar o tipo do parâmetro na propriedade “Params”, ou “Parameters” caso trabalhe com ADO.

6 - Adicionar os campos persistentes: Botão direito sobre o dataset, no Fields Editor, Add all fields

7 - Configurar as propriedades “DisplayLabel”, “DisplayFormat” ou “EditMasck” caso deseje formatar o dado para exibí-lo. Exemplo:
AdsClientesConsDataCadastro.DiplayLabel = ‘Data de Cadastro’;
AdsClientesConsDataCadastro.DiplayFormat = ‘DD/MM/YYYY’;
AdsClientesConsValorComprado.DiplayLabel = ‘Valor Total em Compras:’;
AdsClientesConsValorComprado.DiplayFormat = #,##0.00;

OBS1: Esses DataSets configurados para inclusão, alteração e deleção não são propícios para utilização de “JOINS” (uniões entre tabelas). Visto que, o resultset retornado por este tipo de select não é atualizável. Contudo, através da utilização da tecnologia MIDAS, é possível fazer com que dados possam ser atualizados a partir dessa abordagem. Todavia, isso requer o emprego de uma técnica específica, a qual emprega uma configuração apropriada no TDataSetProvider para este fim. Veremos sobre está técnica adiante.

OBS2: No cado dos componentes da ADO altere a propriedade “LockType” para “ltBatchOptimistic”. Para habiltá-lo a trabalhar com Cache.
“Use the LockType ltBatchOptimistic to open a dataset in batch update mode.”

8 - Valores default deverão ser atribuídos no evento “OnNewRecord” do DataSet, caso seja sua opção fazer isso pelo front-end. Exemplo:


procedure TDM.AdsClientesNewRecord(DataSet: TDataSet);
begin
AdsClientesID_Cliente.AsInteger := GeraID(AdsClientesID_Cliente.FieldName);
AdsClientesStatus.AsString := 'S';
AdsClientesTipo.AsString := 'F';
AdsClientesData.AsDateTime := Now;
end;


Considerações finais:

Fiz referência, neste post a classe “TDataSet” que é a classe da qual derivam todos os objetos de seleção e manipulação de dados da VCL (biblioteca de componentes visuais, do Delphi), porque meu intuito é apresentar uma forma padronizada, genérica, para configuração de componentes usados em programas de cadastro. Ou seja se você procurar na palheta decomponentes por “DataSet” não vai encontrar nada. Uma questão quanto a isso seria que, nem todos os componentes que derivam de TDataSet são adequados para as configurações listadas por mim neste exemplo. Mas, apesar disso, os DataSets aos quais me refiro aqui são adequados para a funcionalidade de cadastro.

Outra coisa importante a destacar é que este exemplo não aborda uma metodologia definitiva, completa para todos os casos de CRUD. Meu objetivo é mostrar a importância de se definir um procedimento padrão, através de um exemplo, mais próximo da realidade que um desenvolvedor encontra no dia-a-dia, que serve como ponto de partida didaticamente formulado.

Artigo completo (View Full Post)

terça-feira, 22 de abril de 2008

TYPE CURSOR - Retornar um Resultset numa Procedure - Oracle & DBExpress

Nos artigos anteriores vimos como retornar um resultset num parâmetro de saída de uma procedure no Oracle (ADOStoredProc, ADODataset). Seguiremos dando continuidade ao assunto abordando o problema trocando a tecnologia de acesso a dados. Usaremos DBExpress para isso e documentaremos as adversidades que encontradas.

Construindo o Exemplo com DBExpress para testar a procedure com mais de um parâmetro de entrada:

Primeiro vamos criar uma outra procedure na package “MY_Pkg”:

procedure CalculaMediaStr(
Nota1 in VARCHAR2,
Nota2 in VARCHAR2,
Nota3 in VARCHAR2,
MediavalAprovacao in VARCHAR2,
ZnCursor OUT ZNCursorType) IS
BEGIN
/* Calcula a média de um aluno */

Media := (Nota1 + Nota2 + Nota3)/ 3;
IF (Media >= TO_NUMBER(MediavalAprovacao)) THEN
ResultadoAprovacao := 'Aprovado';
ELSE
ResultadoAprovacao := 'Reprovado';
END IF;

/* retornando no CURSOR o resultado do aluno */
OPEN ZnCursor FOR
SELECT 'Aluno Estação ZN: ' AS Nome,
ResultadoAprovacao AS ResultadoZN,
TO_Char(Media) AS ValorMedia
FROM dual;

end CalculaMediaStr;


Adicione mais uma página no PagControl1. Além disso adicione um SQLConnection, um SQLStoredProc, um DataSetProvider, um ClientDataSet, um DataSource. Na nova TabSheet, adicione um Panel, quatro Edits, um BitBtn (BtnMediaStr), um DBGrid. Conecte todos os componentes dataware, configure o SQLStoredProc conforme ilustração abaixo:



Veja abaixo a listagem de parâmetros do SQLStoredProc:



Uma vantagem da DBExpress é que você não precisa deletar o parâmetro cursor. Conect os componentes da DBExpress (SQLConnection e SQLStoredProc), com os componentes Midas(DataSetProvider e ClientDataset):

Componentes Dataware - * indica a propriedade para associação entres os componentes







No ClientDataSet, com o botão direito do mouse selecione “Fetch Params”, em seguida adicione os campos persistentes no “Fields Editor”.



Componentes MIDAS:









O Componente SQLStoredProc perde os parâmetros quando efetua uma execução da procedure “CALCULAMEDIASTR”. Por isso somos obrigados a montar toda lista de parâmetros manualmente. Antes de codificar o evento OnClick do “BtnMediaStr”, onde faremos de fato a chamada a execução da “proc” vamos implementar um método que montará a lista de parâmetros do “SQLStoredProc”. Já que criamos uma proceedure nova para este exemplo, visto que teríamos que trabalhar somente com tipo não numéricos retornados ou enviados ao banco de dados, aproveitei e mudei um pouco a lógica da procedure “CALCULAMEDIASTR” em relação a calcula média anterior. Neste nova versão, o valor referência para aprovação é um parâmetro de entrada: “MediavalAprovacao”.


procedure TForm1.BuildParams;
var
i: Integer;

procedure AddParameter(Dataset: TClientDataSet; DataType: TFieldType;
Name: String; ParamType: TParamType);
var
MyParameter: TParam;
begin
{Somos obrigados a criar dinamicamente os parâmetros}
MyParameter := TParam.Create(DataSet.Params);
MyParameter.DataType := DataType;
MyParameter.Name := Name;
MyParameter.ParamType := ParamType;
DataSet.Params.AddParam(MyParameter);
end;

begin

with ClientDataSet do
begin
Close;

Params.Clear;
AddParameter(ClientDataSet, ftInteger, 'MEDIAVALAPROVACAO', ptInput);
AddParameter(ClientDataSet, ftInteger, 'NOTA3', ptInput);
AddParameter(ClientDataSet, ftInteger, 'NOTA2', ptInput);
AddParameter(ClientDataSet, ftInteger, 'NOTA1', ptInput);
AddParameter(ClientDataSet, ftCursor, 'ZnCursor', ptOutput);
end;
end;


Codificando o evento OnClick do “BtnMediaStr”

BuildParams;
with ClientDataSet do
begin
Close;
Params[0].AsString := EdtMediaAprovacao.Text;
Params[1].AsString := EdtNota1.Text;
Params[2].AsString := EdtNota2.Text;
Params[3].AsString := EdtNota3.Text;
Open;
end;


Testando a plicação:



Tivemos que converter, no comando SQL a variável “Media”, para tipo caractere. Segue código da package atual:


create or replace package MY_Pkg is

-- Author : GMottazn
-- Created : 12/03/2008 09:58:08
-- Purpose :

-- Public type declarations
TYPE ZNCursorType IS REF CURSOR;

-- Public variable declarations
-- ;

-- Public function and procedure declarations
procedure CalculaMedia(
Nota1 in INTEGER,
Nota2 in INTEGER,
Nota3 in INTEGER,
Nota4 in INTEGER,
ZnCursor OUT ZNCursorType);

PROCEDURE RetCircunferencia(
ZnCursor1 OUT ZNCursorType,
Raio IN NUMBER DEFAULT 0);


procedure CalculaMediaStr(
Nota1 in VARCHAR2,
Nota2 in VARCHAR2,
Nota3 in VARCHAR2,
MediavalAprovacao in VARCHAR2,
ZnCursor OUT ZNCursorType);

end MY_Pkg;
/
create or replace package body MY_Pkg is

-- Public constant declarations
ValorAprovacao constant NUMBER := 6;
PI CONSTANT NUMBER := 3.1416; -- Constante usada na procedure "RetCricunferencia"

-- Private variable declarations
ResultadoAprovacao VARCHAR2(20);
Media NUMBER;
-- Function and procedure implementations
procedure CalculaMedia(
Nota1 in INTEGER,
Nota2 in INTEGER,
Nota3 in INTEGER,
Nota4 in INTEGER,
ZnCursor OUT ZNCursorType) IS
BEGIN
/* Calcula a média de um aluno */

Media := (Nota1 + Nota2 + Nota3 + Nota4)/ 4;
IF (Media >= ValorAprovacao) THEN
ResultadoAprovacao := 'Aprovado';
ELSE
ResultadoAprovacao := 'Reprovado';
END IF;

/* retornando no CURSOR o resultado do aluno */
OPEN ZnCursor FOR
SELECT 'Aluno Estação ZN: ' AS Nome,
ResultadoAprovacao AS ResultadoZN,
Media AS ValorMedia
FROM dual;

end CalculaMedia;


PROCEDURE RetCircunferencia(
ZnCursor1 OUT ZNCursorType,
Raio IN NUMBER DEFAULT 0) IS
vResultado NUMBER;
BEGIN
/* Calcula a retificação da circunferência */

vResultado := 2 * (Raio * PI);

OPEN ZNCursor1 FOR
SELECT
'Retificação da Circuferência' AS Descricao,
VResultado AS Resultado
FROM
Dual;
END RetCircunferencia;


procedure CalculaMediaStr(
Nota1 in VARCHAR2,
Nota2 in VARCHAR2,
Nota3 in VARCHAR2,
MediavalAprovacao in VARCHAR2,
ZnCursor OUT ZNCursorType) IS
BEGIN
/* Calcula a média de um aluno */

Media := (Nota1 + Nota2 + Nota3)/ 3;
IF (Media >= TO_NUMBER(MediavalAprovacao)) THEN
ResultadoAprovacao := 'Aprovado';
ELSE
ResultadoAprovacao := 'Reprovado';
END IF;

/* retornando no CURSOR o resultado do aluno */
OPEN ZnCursor FOR
SELECT 'Aluno Estação ZN: ' AS Nome,
ResultadoAprovacao AS ResultadoZN,
TO_Char(Media) AS ValorMedia
FROM dual;

end CalculaMediaStr;

end MY_Pkg;
/


Artigo completo (View Full Post)

TYPE CURSOR - Oracle & TADODataSet

Dando continuidade ao tema “Cursor Type” no Oracle, conforme o artigo anterior pretendo tratar da utilização do ADODataSet para executar uma procedure no Oracle, aqual retorna um cursor, tendo ainda como particularidade vários parâmetros de entrada.
Retomando o assunto, vejamos a procedure “CalculaMedia”:


procedure CalculaMedia(
Nota1 in out NUMBER,
Nota2 in NUMBER,
Nota3 in NUMBER,
Nota4 in NUMBER,
ValorAprovacao IN NUMBER,
Media out NUMBER,
ZnCursor IN OUT ZNCursorType) is
begin
Media := (Nota1 + Nota2 + Nota3 + Nota4)/ 4;
IF (Media >= ValorAprovacao) THEN
ResultadoAprovacao := 'Aprovado';
ELSE
ResultadoAprovacao := 'Reprovado';
END IF;
open ZnCursor FOR
SELECT 'Aluno Estação ZN: ' AS Nome,
ResultadoAprovacao AS ResultadoZN
FROM dual;

end CalculaMedia;


Construindo o Exemplo com ADODataSet para testar a procedure com mais de um parâmetro de entrada:
Crie uma nova pagina no PagControl1: Adicione um DBGrid, um DataSource, um ADODataSet, um Panel, quatro Edits, um BitBtn. Conforme ilustrado na imagem abaixo:



Configurações obrigatórias no ADODataSet:

  1. Conecte no ADOConnection.
  2. Altere a propriedade “CommandType” para “cmdStoredProc”.
  3. Na propriedade “CommandText” digite o nome da procedure: “[owner].my_pkg.calculamedia”
  4. Delete o parâmetro cujo tipo é ftInterface (referente ao cursor).
  5. Altere a propriedade “DataType” dos demais parâmtros de “ftBCD” para “ftFloat”.
  6. Altere a propriedade “EnableBCD” do ADOStoredProc para “False”.
  7. Garanta que o ADOConnection esteja desconectado e adicione os campos persistentes (Fields Editor – Botão direito sobre o ADODataSet).




Codificando o evento OnClick do BtMedia:


procedure TForm1.BtnMediaClick(Sender: TObject);
begin
with ADODataSet1 do
begin
Parameters[0].value := StrtoFloat(Edit1.Text);
Parameters[1].Value := StrToFloat(Edit2.Text);
Parameters[2].Value := StrToFloat(Edit3.Text);
Parameters[3].Value := StrtoFloat(Edit4.Text);
Open;
end;
end;


Na próxima ilustração estou executando o exemplo construido:



Artigo completo (View Full Post)

sexta-feira, 11 de abril de 2008

ZN Ringtones - Come Together ...

Estação ZN sem preconceitos...
Bem, estava faltando o hino do "Braço de união Brasil-Portugal" (hehehehe ...) para representarmos os principais times do RJ ... seguindo na mesma idéia sobre criar toques para celular postado anteriormente:
Não estou muito preocupado com a ortodoxia do idolatrado rock britânico. Boas idéias estão ai para serem usadas. Suponho, presumo, assim espero.
Nestes ringtones resolvi usar a idéia do riff (Guitar, Drum and Bass) do imortal e sensacional "Come Together" para acompanhamento do Hino do Vasco(Em homenagem ao meu amigo Glaucio Mota, guerrero bom de bola) e do Fluminense.


Come Together - Flu
Vasco da Gama - Together ...
Vasco da Gama II- Together ...










Artigo completo (View Full Post)

quarta-feira, 9 de abril de 2008

terça-feira, 8 de abril de 2008

Zn Ringtones with ReBirth

Faz algum tempo eu postei sobre criar toques para celular usando um software Rebirth, na ocasião não havia a disponibilidade de eu fazer upload do arquivo e deixar uma mostra. Bem agora isso é possível ....
Segue alguns exemplo de ringtones que eu tenho criado, sem nenhuma intenção comercial, com a Rebirth e outros softwares para edição de áudio que eu costumo usar.
Aceito sugestões e idéias de outros toques, poste em comentário sua idéia, sugestão ou solicitação. Segue alguns links para download do material que tenho composto. Repito não tenho nenhuma intenção de comercializar esse material.

Enjoy yourself ...

ZN Ringtones:


More ...

Time de Futibol:

Fla
ZNRingFla

Flu
ZnFluBig
ZnFlu1
ZnFlu2
ZnFluShort
ZnFunkFlu
ZnFunkFluBig
ZnTranceTechFlu







Artigo completo (View Full Post)

segunda-feira, 7 de abril de 2008

Módulo de consulta para CRUD win32 - For Dummies

Definindo uma forma metódica de construir um modulo de consulta para CRUD.

Passo 1 – Crie um Data Module (menu file ▶ new ▶ Data Module), se por caso ainda não houver um pronto para isso:
Adicione ao DM um conector com o banco de dados: ADOConnection, SQLConnection ou DataBase, dependendo da tecnologia de acesso a dados. Configure a conexão, botão direito sobre o componente escolha a opção de configuração de conexão. No caso do ADOConnection: EditConnectionString.

Passo 2 – Adicione um DataSet. Este será responsável por recuperar os registros que você deseja retornar na consulta do CRUD. Por Exemplo, num cadastro de produtos para alterar/editar ou excluir um determinado registro é imprescindível buscar, recuperar, o registro no banco de dados. Se você está trabalhando com ADO, adicione um ADODataSet. Se a tecnologia de acesso a dados que você usa é DBExpress adicione um SQLDataSet.

Passo 3 - Configure o DataSet conforme exemplificado em: Configuração de um DataSet de Consulta - CRUD - For Dummies
Passo 4 – Criar um método público no DM para executar a consulta, cujo o argumento é o parâmetro esperado do DataSet criado anteriormente que fará a consulta. Exemplificando abaixo o método ConsultarClientes:


type
TDM = class(TDataModule)
ADOConnection: TADOConnection;
AdsClientes: TADODataSet;
public
function ConsultarClientes(const Nome: String): Boolean;


com o class complete – Ctrl + Shift + C, codifique o corpo do método.


function TDM.ConsultarClientes(const Nome: String): Boolean;
begin
AdsClientesCons.Close;
AdsClientesCons.Parameters[0].Value := Nome;
AdsClientesCons.Open;
(* retorna verdadeiro se a consulta obtiver sucesso *)
Result := not AdsClientesCons.IsEmpty;
end;


Essa idéia pode ser aplicada a qualquer outro CRUD por exemplo:


function TDM.ConsultarProdutos(const Descricao: String): Boolean;
begin
AdsProdutosCons.Close;
AdsProdutosCons.Parameters[0].Value := Descricao;
AdsProdutosCons.Open;

Result := not AdsProdutosCons.IsEmpty;
end;


Estou tentando fazer um grupo de posts sobre técnicas de CRUD para alunos, estagiários e programadores jr. Nesse primeiro momento minha principal preocupação é introduzir a idéia através de exemplos simples para sedimentar a importância de uma forma padronizada de se construir programas. Nosso objetivo não é apenas definir uma forma padronizada, mas também uma forma otimizada podendo assim ser usada satisfatoriamente em diversas situações. É importante destacar também que o ganho em se padronizar uma metodologia de desenvolvimento não fica restrito apenas no que tange a produtividade na fase de construção do módulo. O principal ganho, na minha opinião, é posteriormente na manutenção e evolução do módulo.

Passo 5 – Adicione um Form para a interface da consulta: menu file ▶ new ▶ Form
Configure as seguintes propriedades do form:
Name = ClientesLstFrm
BorderStyle = bsDialog
Position = poMainFormCenter
Caption = ‘Consulta Clientes’

Adicione os seguintes componentes:
BitBtn1 = BtnConsultar

object BtnConsulta: TBitBtn
Caption = 'Pesquisar'
OnClick = BtnConsultaClick
end


BitBtn2 = BtnOk

object BtnOk: TBitBtn
.
.
Kind = bkOK
end

BitBtn3 = BtnSair

object BtnSair: TBitBtn
Caption = '&Sair'
ModalResult = mrCancel
.
.
end


Adicione um TDataSource. A propriedade “Name” vou alterar para DsDados. Em Seguida associe ele ao DataSet que se encontra no DM, criado no passo 1. Para fazer isso será necessário fazer com que essa unit, do ClientesLstFrm faça “uses” da unit do DM. Portanto, Alt + F11para fazer u Use Unit do DM. Agora sim você pode associar a propriedade DataSet do DataSource o AdsClientesCons.
Adicione um TEdit, um Label e um DBGrid. As configurações do DBGrid mais importantes são:

Name: Vou chamá-lo de GrdDados.

Propriedade do Grid: DataSource: Deverá ser associada ao DataSource (DsDados) associado ao DataSet que configuramos anteriormente no passo 2 (AdsClientesCons).

Propriedade Columns: Adicione colunas de acordo com os campo do AdsClientesCons que você deseja que sejam listados no Grid.



Cada coluna deve ter as propriedade FieldName e Title/Caption configuradas. Exemplo:



Esse módulo de consulta vai se comunicar com o módulo de cadastro. A idéia é que ele seja uma listagem, no caso, de “Clientes” para que o usuário possa seleciona um registro para alterá-lo ou excluí-lo. Portanto, é muito importante cuidar da comunicação deste Form com qualquer outro que use da sua funcionalidade. Uma técnica comum e eficiente é criar propriedades neste Form onde poderemos persistir os valores que desejamos comunicar para outro módulo.
Na seção “public” codifique conforme exemplificado abaixo:

public;
property ClienteID: Integer;
property NomeCliente: String;
property CPF: String;
end;


Chame o class complete para completar o código das propriedades: Ctrl + Shift + C. Veja como deve estar a sua unit agora:

type
TClientesLstFrm = class(TForm)
EditPesq: TEdit;
Label1: TLabel;
BtnConsulta: TBitBtn;
DsDadosLst: TDataSource;
Panel1: TPanel;
GrdDados: TDBGrid;
BtnSair: TBitBtn;
BtnOk: TBitBtn;

private
FClienteID: Integer;
FCPF: String;
FNomeCliente: String;
procedure SetClienteID(const Value: Integer);
procedure SetCPF(const Value: String);
procedure SetNomeCliente(const Value: String);
{ Private declarations }
public
property ClienteID: Integer read FClienteID write SetClienteID;
property NomeCliente: String read FNomeCliente write SetNomeCliente;
property CPF: String read FCPF write SetCPF;
end;



Em seguida, codifique o evento OnClick dos botões: BtnConsulta e BtnOk.

procedure TClientesLstFrm.BtnConsultaClick(Sender: TObject);
begin
if not DM.ConsultarClientes(EditPesq.Text +'%') then
ShowMessage('Nenhum registro encontrado!!!');
end;



procedure TClientesLstFrm.BtnOkClick(Sender: TObject);
begin
if GrdDados.DataSource.DataSet.IsEmpty then Exit;
(* Valores de output do módulo de consulta *)

SetClienteID(GrdDados.DataSource.DataSet.FieldByName('ID_Cliente').AsInteger);
SetNomeCliente(GrdDados.DataSource.DataSet.FieldByName('Nome').AsString);
SetCPF(GrdDados.DataSource.DataSet.FieldByName('CPF_CNPJ').AsString);

end;


Fechando o DataSet de consulta ao sair do módulo: No evento OnClose do From.

procedure TClientesLstFrm.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
// Garantindo que o DataSet seja fechado ao término da consulta
GrdDados.DataSource.DataSet.Close;
end;


Artigo completo (View Full Post)

 
BlogBlogs.Com.Br