Mostrando postagens com marcador Banco de Dados. Mostrar todas as postagens
Mostrando postagens com marcador Banco de Dados. Mostrar todas as postagens

sexta-feira, 30 de julho de 2010

Commitou o que não era pra comittar? Dá "Rollback"!

Fala ai, pessoal!

Se você é de TI, com certeza já passou por uma situação como essa:
Atualizando dados de uma tabela em um banco de dados Oracle, você alterou um ou vários campos com o valor errado, ou até mesmo excluiu um ou mais registros e deu COMMIT. E agora?!?! Fedeu?!?! NÃO!!! Você pode recuperar os dados...
Fala ai, pessoal!

Se você é de TI, com certeza já passou por uma situação como essa:
Atualizando dados de uma tabela em um banco de dados Oracle, você alterou um ou vários campos com o valor errado, ou até mesmo excluiu um ou mais registros e deu COMMIT. E agora?!?! Fedeu?!?! NÃO!!! Você pode recuperar os dados através do Oracle Flashback.

Para isso, a tarefa é muito simples. Basta fazer um select na tal tabela, normal mesmo, com os campos e condições que você quer e, no from, após o nome da tabela, colocar "as of timestamp systimestamp - interval 'X' minute", onde esse "X" é o tempo que passou desde a bobagem que você fez até agora.

Por exemplo: Tenho uma tabela CLIENTE na minha base de dados Oracle e vou atualizar os clientes que não fazem compras há mais de 1 mês para Inativos.

Então fiz lá meu update, atualizando o campo STATUS_CLIENTE para "I", depois de fazer um select que retorna os tais clientes que não compraram no último mês. Dei o COMMIT. Alguns desses clientes estavam com o STATUS "A" de Ativo, "D" de Devedor, "V" de VIP.

Daí, chega o meu chefe, 30 minutos depois que eu fiz o update, dizendo que esse update não pode ser feito em clientes VIP e eu... DANÇO? Não! Eu faço o seguinte:

select ID_CLIENTE
from CLIENTE
as of timestamp systimestamp - interval '30' minute
where STATUS_CLIENTE = 'V';

PRONTO! Peguei todo mundo que tava com o campo STATUS_CLIENTE = 'V' 30 minutos atrás.
Com os IDs, eu faço um novo update, passando essa galera, que está com o STATUS = 'I', pra 'V'.

Salvei meu emprego e deixei meu chefe feliz!

PS.: Agradecimentos ao camarada Willian Rodrigues que ajudou nesse post!

Abraço a todos!

Artigo completo (View Full Post)

sábado, 23 de maio de 2009

Cursor with parameters in PL/SQL

Ver este post em Portugûes

Here I'm gonna show another technique to work with cursors in PL/SQL. I had to do something at work where it was very useful: cursor that take arguments.

The biggest advantages of parametrized queries is that the server doesn't have to pass through the parse and plan phases ever again (after the first time, of course) and the compile-time checking for syntax errors (when we use string queries we only know any syntax errors in runtime).

That said let's go to examples:


cursor ProductCursor(pname in varchar2) is
select *
from product
where name like pname;


Nice, isn't it? It's like a procedure in terms of syntax. And opening the cursor is like this:


open ProductCursor('A%');


It'll open the cursor with all the products which name starts with 'A'.

We can create a rowtype based var from this cursor:


prod ProductCursor%rowtype;


Now I'm gonna join it all in a script:


declare
-- Cursor
cursor ProductCursor(pname in varchar2) is
select *
from product
where name like pname;

-- Simple loop
prod ProductCursor%rowtype;

-- bulk collect loop
type Tprods is table of ProductCursor%rowtype;
prods Tprods;
i integer;

begin
-- simple loop
open ProductCursor('A%');
loop
fetch ProductCursor into prod;
exit when ProductCursor%notfound;
DBMS_OUTPUT.put_line(prod.nome);
-- other commands
end loop;
close ProductCursor;

-- bulk collect loop
open ProductCursor('A%');
fetch ProductCursor bulk collect into prods;
for i in prods.first .. prods.last loop
DBMS_OUTPUT.put_line(prods(i).nome);
-- another commands using prods(i)
end loop;
close ProductCursor;
end;


Cool, isn't it? See you next time.

Artigo completo (View Full Post)

Cursor com parâmetros em PL/SQL

View this post in English

Aqui vou mostrar outra técnica para trabalhar com cursores em PL/SQL. Eu tive que fazer um trabalho recentemente onde isso foi muito útil: Cursores que aceitam argumentos.

As maiores vantagem de usar queries parametrizadas no banco de dados é que o servidor não precisa fazer o parse e traçar um plano de execução (ele só faz isso na primeira vez que a query é executada) e ela fica certa em tempo de compilação (ao contrário das queries em string que nós só sabemos se há um erro de sintaxe em tempo de execução).

Dito isso vamos a um exemplo:


cursor ProdutoCursor(pnome in varchar2) is
select *
from produto
where nome like pnome;


Legal, não? A sintaxe fica muito parecida com uma procedure. E o método de abrir o cursor também é legal:


open ProdutoCursor('A%');


Aqui vai abrir o cursor trazendo todos os produtos onde o nome começa com a letra 'A'.

Podemos ainda criar um rowtype a partir deste cursor:


prod ProdutoCursor%rowtype;


Agora vou criar um script para juntar tudo:


declare
-- Cursor
cursor ProdutoCursor(pnome in varchar2) is
select *
from produto
where nome like pnome;

-- Para loop simples
prod ProdutoCursor%rowtype;

-- Para loop com bulk collect
type Tprods is table of ProdutoCursor%rowtype;
prods Tprods;
i integer;

begin
-- Loop simples
open ProdutoCursor('A%');
loop
fetch ProdutoCursor into prod;
exit when ProdutoCursor%notfound;
-- comandos a serem executados com o registro prod
DBMS_OUTPUT.put_line(prod.nome);
end loop;
close ProdutoCursor;

-- Loop com bulk collect
open ProdutoCursor('A%');
fetch ProdutoCursor bulk collect into prods;
for i in prods.first .. prods.last loop
-- comandos a serem executaos com o registro prods(i)
DBMS_OUTPUT.put_line(prods(i).nome);
end loop;
close ProdutoCursor;
end;


Muito legal, né? Até a próxima.

Artigo completo (View Full Post)

terça-feira, 30 de dezembro de 2008

Oracle - Pl/SQL No Alter Table: Constraints e Checks, sem usar o comando

No artigo anterior demonstrei varias possibilidades de usar o camando “ALTER TABLE” no Oracle. Contudo, algumas vezes acho mais conveniente para mim definir as constraints e checks imediatamente quando estou criado a tabela. Acho que para a prática de documentação, versionamento de código/script, se toda a definição estiver no mesmo comando é mais eficiente o versionamento do script da tabela durante a evolução e manutenção do banco de dados.
A partir do que foi exemplificado no artigo anterior, vou definir todas as constraints e checks na criação das tabelas “ENDERECO_ZN” e “Tipo_EnderecoZN”. Veja a seguir ...



DROP TABLE TIPO_ENDERECOZN;
CREATE TABLE TIPO_ENDERECOZN (
TIPO_ENDERECOID NUMBER(10) NOT NULL,
TIPO_ENDERECO VARCHAR2(100) NOT NULL,
DATACADASTRO DATE NOT NULL,
CONSTRAINT PK_TIPO_ENDEZN PRIMARY KEY (TIPO_ENDERECOID),
CONSTRAINT CHK_TIPO_ENDERECO CHECK (LENGTH(TIPO_ENDERECO) > 5),
CONSTRAINT CHK_DATACADASTRO_TP CHECK (DATACADASTRO > TO_DATE('31/12/2000', 'DD/MM/YYYY'))
);

Na linha 1, primeiro excluo a tabela do banco, para em seguida recriá-la.
a partir da linha 6 começamos a definir as constraints.
Na Lina 6, defino quem é a chave primária.
Na linha 7 validação para a coluna “TIPO_ENDERECO”.
Na linha 8 validação para a coluna “DATACADASTRO”.

Agora vamos fazer o mesmo para a tabela “ENDERECO_ZN”:

DROP TABLE ENDERECO_ZN;
CREATE TABLE ENDERECO_ZN
(
ENDERECO_ZNID NUMBER(10) NOT NULL,
TIPO_ENDERECOID NUMBER(10),
LOGRADOURO VARCHAR2(130) NOT NULL,
COMPLEMENTO VARCHAR2(170),
BAIRRO VARCHAR2(50),
CIDADE VARCHAR2(50),
ESTADO VARCHAR2(2),
CEP VARCHAR2(10),
NUMERO VARCHAR2(10),
DATACADASTRO DATE NOT NULL,
CONSTRAINT PK_ENDERECOZN PRIMARY KEY (ENDERECO_ZNID),
CONSTRAINT FK_ENDERECO_ZN_TP_END FOREIGN KEY (TIPO_ENDERECOID) REFERENCES TIPO_ENDERECOZN (TIPO_ENDERECOID),
CONSTRAINT CHK_ESTADO CHECK (LENGTH(ESTADO) > 1),
CONSTRAINT CHK_CIDADE CHECK (LENGTH(CIDADE) > 4),
CONSTRAINT CHK_DATACADASTRO CHECK (DATACADASTRO > TO_DATE('31/12/2000', 'DD/MM/YYYY'))

);


Artigo completo (View Full Post)

Oracle - Pl/SQL Alter Table (Variações sobre o tema): Modify, Add Constraint, Add, Drop e Rename

Com o comando “ALTER TABLE” podemos realizar diversas modificações estruturais em tabelas de banco de dados. A seguir, experimentaremos como isso pode ser feito em PL/SQL.


Trabalharemos com a tabela exemplificada abaixo:

CREATE TABLE ENDERECO_ZN
(
CODENDERECO_ZN NUMBER(10) NOT NULL,
ID_TIPO_ENDERECO NUMBER(10),
LOGRADOURO VARCHAR2(100),
COMPLEMENTO VARCHAR2(50),
BAIRRO VARCHAR2(50),
CIDADE VARCHAR2(50),
ESTADO VARCHAR2(2),
CEP VARCHAR2(10),
NUMERO VARCHAR2(10)
);


A primeira coisa que vou fazer é alterar o nome de uma das colunas:

Alterando o nome da coluna: De “CODENDERECO_ZN” para “ENDERECO_ZNID”

ALTER TABLE
ENDERECO_ZN
RENAME COLUMN
CODENDERECO_ZN
TO
ENDERECO_ZNID


Agora vamos alterar algumas outras coisas numa coluna. Que tal o tamanho e torná-la obrigatória?


-- Alterando o tamanho da coluna e tornando-a obrigatória

ALTER TABLE ENDERECO_ZN MODIFY COMPLEMENTO varchar2(150) not null;

Veja como está a nossa tabela após essas primeiras alterações ...
-- Create table
create table ENDERECO_ZN
(
ENDERECO_ZNID NUMBER(10) not null,
ID_TIPO_ENDERECO NUMBER(10),
LOGRADOURO VARCHAR2(100),
COMPLEMENTO VARCHAR2(150) not null,
BAIRRO VARCHAR2(50),
CIDADE VARCHAR2(50),
ESTADO VARCHAR2(2),
CEP VARCHAR2(10),
NUMERO VARCHAR2(10)
);


Podemos aplicar modificações em mais de uma coluna no mesmo comando. Veja ilustrado abaixo como fazer:

-- Alterando mais de uma coluna no mesmo comando
ALTER TABLE ENDERECO_ZN MODIFY (COMPLEMENTO varchar2(170) null, LOGRADOURO varchar2(130) not null);


No exemplo acima alteramos tanto o tamanho das duas colunas, quanto a obrigatoriedade das mesmas. Aprimeira definimos para aceitar valores nulos e a segunda para não aceitar. Vejamos como ficou a tabela “ENDERECO_ZN”.


create table ENDERECO_ZN
(
ENDERECO_ZNID NUMBER(10) not null,
ID_TIPO_ENDERECO NUMBER(10),
LOGRADOURO VARCHAR2(130) not null,
COMPLEMENTO VARCHAR2(170),
BAIRRO VARCHAR2(50),
CIDADE VARCHAR2(50),
ESTADO VARCHAR2(2),
CEP VARCHAR2(10),
NUMERO VARCHAR2(10)
);


Podemos também adicionar mais de uma coluna com o mesmo comando
-- Adicionando novas colunas

Alter table ENDERECO_ZN
ADD ( Pais varchar2(50),
DataCadastro Timestamp not null);


Mais uma vez, a tabela ENDERECO_ZN refletindo o comando anterior:
     
create table ENDERECO_ZN
(
ENDERECO_ZNID NUMBER(10) not null,
ID_TIPO_ENDERECO NUMBER(10),
LOGRADOURO VARCHAR2(130) not null,
COMPLEMENTO VARCHAR2(170),
BAIRRO VARCHAR2(50),
CIDADE VARCHAR2(50),
ESTADO VARCHAR2(2),
CEP VARCHAR2(10),
NUMERO VARCHAR2(10),
PAIS VARCHAR2(50),
DATACADASTRO TIMESTAMP(6) not null
)


Supondo que a coluna “Pais” não seja adequada ao modelo de negócio em questão, vamos excluí-la da tabela.


-- Dropnado uma coluna
Alter table ENDERECO_ZN drop column Pais


Agora vamos alterar o tipo de dado de uma das colunas

-- Alterando o tipo de dado de uma coluna
ALTER TABLE ENDERECO_ZN MODIFY DATACADASTRO Date;


Outra vez, alteramos a tabela ...

create table ENDERECO_ZN
(
ENDERECO_ZNID NUMBER(10) not null,
ID_TIPO_ENDERECO NUMBER(10),
LOGRADOURO VARCHAR2(130) not null,
COMPLEMENTO VARCHAR2(170),
BAIRRO VARCHAR2(50),
CIDADE VARCHAR2(50),
ESTADO VARCHAR2(2),
CEP VARCHAR2(10),
NUMERO VARCHAR2(10),
DATACADASTRO DATE not null
)



O Comando “ALTER TABLE” também é uma forma de definirmos constraits. Vejamos ...


Definindo uma Chave primária: Suponha que você esta trabalhando com uma tabela que foi crianda a muitos anos por outros programadores. Esses programadores não definiram nenhuma coluna como chave primária. Mas hoje, você precisa fazer isso. Hoje você precisa que esta tabela possua uma PK. Vaja uma forma de fazer isso ilustrada abaixo:



-- Pk
alter table ENDERECO_ZN add primary key (ENDERECO_ZNID);


Note que eu preparei a tabela para estar relaciona a outra. A coluna “ID_TIPO_ENDERECO” deveria ser uma chave estrangeira para uma tabela que armazenasse os tipos de Endereço. Esse tipo de modelagem atende a uma normalização muito comum. Portanto, antes de declararmos a chave estrangeira vamos criar a tabela de tipo de endereço:


-- Crinado a tabela de Tipo de Endereço
Create Table Tipo_EnderecoZN (
ID_TIPO_ENDERECO NUMBER(10) not null,
Tipo_Endereco Varchar2(100) not null
);

alter table Tipo_EnderecoZN add primary key (ID_TIPO_ENDERECO);

Na linha 7 do trecho de código acima, repeti o mesmo comando, que usei para criar a chave primária para tabela Enreco_ZN, para definir a coluna “ID_TIPO_ENDERECO” como PK (Primary Key – Chave primária) em “Tipo_EnderecoZN”.

Agora vamos criar a constraint que garantirá a integridade referencial entre as tabelas:


Alter table Endereco_ZN add constraint FK_Endereco_TpEndereco foreign key (ID_TIPO_ENDERECO) references Tipo_EnderecoZN (ID_TIPO_ENDERECO);


Qualidade


Para garantir a qualidade dos dados que serão persistidos nessas tabelas podemos definir regras de validação dos dados (Veja mais sobre isso em “Banco de Dados ou Bando de Dados? ”).


-- Definido regras de validação de dados - checks
Alter table Tipo_EnderecoZN Add CONSTRAINT chk_Tipo_Endereco CHECK (LENGTH(Tipo_Endereco) > 5);
Alter table Endereco_ZN Add CONSTRAINT chk_DATACADASTRO CHECK (DATACADASTRO > TO_DATE('01/01/2000', 'DD/MM/YYYY'));
Alter table Endereco_ZN Add CONSTRAINT chk_BAIRRO CHECK (LENGTH(BAIRRO) > 3);
Alter table Endereco_ZN Add CONSTRAINT chk_ESTADO CHECK (LENGTH(ESTADO) > 1);


Qunado for necessário "dropar" uma constraint ...

ALTER table Endereco_ZN drop constraint FK_Endereco_TpEndereco;


Observe que não referenciei o nome da constraint entre plics.

Obviamente, você deve abusar de ser criterioso ao definir uma regra como essas. Visto que, se ela não definida com exatidão em total harmonia com as regras de negócio (da empresa, para qual o sistema gerenciador de banco de dados está sendo desenvolvido) você terá sérios problemas. Por exemplo, com relação ao trecho de código anterior:
Na linha 1 definimos que na tabela Tipo_EnderecoZN, a coluna Tipo_Endereco não vai aceitar nenhum valor cujo número de caracteres seja menor que 5. Portanto, se tentarem inserir o valor “Resid” (abreviação de “Residencial”) será frustrado. Isso tanto pode ser muito útil, evitando que valores lixo sejam inseridos no banco, mas pode ser prejudicial caso exista alguma possibilidade de uma valor de, por exemplo, três caracteres precise ser inserido na coluna em questão.
Na linha 2, definimos um valor mínimo para a coluna “DataCadastro”, da tabela “ENDERECO_ZN”. Isso vai evitar valores de data do tipo “01/02/0009”. Esse valor de data não é uma valor inválido, entretanto pode causar problema.


Artigo completo (View Full Post)

segunda-feira, 15 de dezembro de 2008

Trabalhando com Controles Lookup

Trabalhando com Controles Lookup

No Delphi chamamos de “Lookup” o mecanismo que representa o relacionamento entre duas tabelas dinamicamente e de forma automatizada para a manipulação de uma delas. Isso consiste em duas operações:
A primeira é de exibir a descrição de um dado a qual não existe no registro da tabela que esta sendo manipulada.
A segunda é, ao mesmo tempo que lista a descrição, sincronizadamente, atribui o valor do campo chave, de relacionamento entra as tabelas envolvidas no lookup, para a tabela que esta sendo manipulada.



Por exemplo, vejamos o relacionamento entre duas tabelas: “Produtos” e “Categoria de Produtos” (as quais usamos no artigo anterior). Primeiro a tabela Producs, abaixo:




Temos o ID da Categoria, mas não temos a descrição dela nesta tabela. A descrição da Categoria encontra-se na tabela Categories.



Existe um relacionamento entre elas ... (Mas isso não é obrigatório para se fazer o Lookup). Essa relação entre os campos pode ser feita pela aplicação, basta que exista um relacionamento lógico entre as colunas das tabelas que serão relacionadas.



O que essa estrutura me força previamente entender? _ Devo entender que para atualizar a tabela de “Produtos” dependerei sempre dos valores existentes na tabela “Categorias”. Isso porque, os valores possíveis para a categoria de produtos está armazenado na tabela Categoria, e a constraint que define a integridade referencial entre as duas tabelas jamais permitirá que seja inserido um valor para categoryID na tabela “Products” que não exista em “Categories”. Isso é muito bom que seja dessa forma.

O Lookup permite reproduzirmos essa relação, respeitando a referencia entre as tabelas de forma automática, suprimindo totalmente a necessidade da codificação de sequer uma linha de código para isso.


Os Controles de Lookup mais comuns são:

DBLookupComboBox: TDBLookupComboBox;
DBLookupListBox: TDBLookupListBox;

Intraweb Framework
IWDBLookupComboBox: TIWDBLookupComboBox;
IWDBLookupListBox: TIWDBLookupListBox;

Dev Express
cxDBLookupComboBox: TcxDBLookupComboBox;
cxDBCheckComboBox: TcxDBCheckComboBox;

Jedi
JvDBLookupComboEdit: TJvDBLookupComboEdit;

Campo Virtual LookUp

Tfield fkLookup: A mesma lógica descrita acima é aplicada também aos Datasets, especificamente quando, através deles trabalhamos com o que a literatura chama de campos persistentes. Trata-se de objetos da classe Tfield. Quando manipulamos dados usando Datasets (TDataset) podemos criar objetos que representam a referência linha/coluna de uma tabela. Esses objetos chamamos de campos de um Dataset, eles nos permitem acessar um determinado dado de um registro. Os Tfields podem ser de vários tipos. Cada tipo determina um grupo de operações que poderá realizar o Tfield. A Propriedade FieldKind determina o tipo do Tfield.
fkData, fkCalculated, fkLookup, fkInternalCalc, fkAggregate são os valores possiveis para a propriedade FieldKind. A Classe TFieldKind, definida na unit DB, define esses valores:



type TFieldKind = (fkData, fkCalculated, fkLookup, fkInternalCalc, fkAggregate);


O Tfield usado para fazermos Lookup é do tipo “fkLookup”. Isso quer dizer que a propriedade FieldKind é “fkLookup”.

Usamos a técnica de Lookups com os Fields (TFild) de um Dataset (Um TclientDataSet por exemplo) quando existe a necessidade de acessarmos (disponibilizarmos, visualizarmos) dados provenientes de tabelas diferentes num único resultset. Como por exemplo, ao apresentar uma listagem de “Pedidos” precisamos explicitamente exibir na tela: O nome do cliente que efetuou a compra, a data do pedido e a descrição dos produtos vendidos. Obviamente, a primeira coisa que vem a mente é o recurso de utilizarmos um join em SQL.


SELECT
C.NomeCliente,
P.DataPedido,
I.Quantidade,
I.PrecoVenda,
(I.Quantidade * I.PrecoVenda) Total,
P.DescricaoProduto
FROM
Clientes C
inner join Pedidos P on
C.ClienteID = P.ClikenteID
inner join Itens I on
I.PedidoID = P.PedidoID
inner join Produtos Pr on
Pr.ProdutoID = I.ProdutosID


Contudo, num Dataset, isto impossibilitaria a utilização do mesmo para qualquer atualização nestes dados (Obviamente, isso é verdadeiro se não consideramos a técnica de gerenciarmos explicitamente, via código, o evento “BeforeUpdateRecord” do DataSetProvider – Falaremos sobre está técnica mais adiante).
No Delphi, o campo (TField) “virtual” lookUp funciona, no que tange a visualização de dados, de forma semelhante ao join. Ou seja, podemos configurar um determinado Dataset trazendo dados através de um comando SQL genérico (Select * from ) de uma única tabela, como o exemplo anterior, “Products”, e adicionarmos a ele um campo virtual que irá conter informações de um outro Dataset. A exemplo da relação entre Products e Categories, demonstrado acima. A grande vantagem desta técnica é porque mesmo disponibilizando dados de tabelas diferentes e ainda assim podermos atualizar os dados usando os comandos convencionais do próprio Dataset. Para fazermos uso do campo LookUp basta que os Datasets possuam um campo de relacionamento.

Vejamos agora, a utilização do campo LookUp:

Suponha que neste momento queremos criar um cadastro (CRUD) de produtos. Mas temos um problema, o banco apresenta um normalização para a tabela produtos de maneira que o dado categoria do produto esta em outra tabela. A tabela Categorias (no caso Categories) é uma tabela de referência. Ela não é transacional e possui um número relativamente pequeno de registros.
Lembre-se que, na hora de incluirmos novos Produtos precisamos digitar, na interface, os dados necessários da tabela de produtos, sendo que para os campos “CategoryID” e “SupplierID” presimos apresentar as descrições de cada um dos campos. Entretanto, o dado, descrição da categoria, por exemplo, encontra-se na tabela de Categories. Ou seja, temos que ler da tabela de Categories: a descrição (Categories.Description), e o valor do respectivo vampo de relacionamento (Categories.CategoryID). Para, então, atribuir a Produtos (Products.CategoryID).

Para isso usaremos um Dataset, o CdsProdutos, criaremos nele um campo lookUp que apontará para o campo Description de Categories no CdsCategorias.
Existe o campo de relacionamento entre essas duas tabelas, esses dois campos estão presentes tanto no CdsProdutos (Products.CategoryID), quanto no CdsCategorias (Categories.CategoryID) possibilitando desta forma um “join virtual”, entre CdsProdutos e CdsCategorias. Consequentimente, podemos ainda assim a atualizar o recordset do CdsProdutos. Outro bonus fundamental dessa técnica é, o que que propositalmente guardei para relembrar no final, de que com o campo LookUp a atribuição de valor ao campo “Products.CategoryID” e feita automaticamente sem a necessidade de código para isso, proveniente do link feito com Categories.CategoryID. Isso ocorre imediatamente a ação do usuário selecionar a descrição da categoria no controle lookup disponibilizado na interface.




As linhas vermelhas indicam as propriedades envolvidas na configuração de um de um controle DBLookup (DBLookupComboBox). AS Linhas verdes indicam os valores, e suas origens, que devem ser associadas as respectivas propriedades.

Criando o Campo Virtual LookUp

Com o botão direito do mouse sobre o CdsProdutos, selecione “Fields Editor ...”



Para criar um novo Field, botão direito no “Fields Editor” e selecione “New Field” (Ou digite “Ctrl + N”).




No Diálogo de definição do novo Field configure as propriedades conforme ilustrado na figura abaixo.




Na propriedade “Name” será definido o nome da coluna/campo virtual. Automaticamente, enquanto você digitar o Delphi gera o nome do objeto Tfield em “Component”. A propriedade “Type” define o tipo de dado que o Tfield irá trabalhar, internamente isso irá definir a propriedade DataType cujo o tipo é “TfieldType”, por sua vez isso refletirá na definição de uma classe que especializa o Tfield a qual o Field criado instanciará.
Dependendo do tipo escolhido em “Type” será imprescindível definir o tamanho do Field. Isso quer dizer, por exemplo, se o campo for do tipo String, o limite máximo quanto ao número de caracteres que o Field poderá armazenar. Logo, na propriedade “Size” digite um valor adequado para o tamaho, limite de caracteres, no campo “CategoriaVirt”. É mais que aconselhável você conferir no banco qual o tamanho da coluna “Categories.CategoryName”, visto que será os valores armazenados por ela listados por esse novo campo.




Em Field Type marque Lookup, em resposta a essa ação os campos de “Lookup definition” serão habilitados, em “Key Fields” e “Lookup Keys” selecionamos as colunas de relacionamento entre os Datasets envolvidos no Lookup. Todavia, para habilitar a propriedade Dataset (onde devemos definir o Dataset que disponibilizara os dados para Lookup, no nosso caso CdsCategorias), temos que selecionar primeiro a coluna do CdsProdutos que faz o relacionamento com Categorias (CategoryID).

Na propriedade DataSet, repetindo, é onde definimos o Dataset de Lookup. Selecione CdsCategorias.
Na propriedade “Lookup Keys”, selecionamos a coluna, do Dataset o qual escolhemos na propriedade “Dataset”, que se relaciona com o CdsProdutos (CategoryID).
Por fim, na propriedade “Result Field” selecionamos a coluna do CdsCategorias que servirá para listar os dados da descrição da categoria. Ou melhor, a coluna para a qual nosso campo virtual “CategoriaVirt” apontará. Selecione “CategoryName”.




Portanto, olhando a tamanho da coluna em “Disign Table” no Enterprise Manager, podemos definir o valor 15 para a propriedade “Size”.


Para finalizar, após definir todas as propriedades, click em “OK”

Se você fizer um Drag and Drop do novo Field virtual Lookup para o Form veja que será criado um controle DbLookupCombobox associado ao CdsProdutos pelo DataSource “DsProdutos”.






Para testar, adicione um DbGrid ao Form1, associe ele ao DataSource DsProdutos (através da propriedade “DataSource” do DbGrid, no Object Inspector). No Evento OnCreate Do Form1 abra os dois Cds (CdsProdutos e CdsCategorias).



procedure TForm1.FormCreate(Sender: TObject);
begin
CdsCategotias.Open;
CdsProdutos.Open;
end;




Observações:

Embora apresente um ganho extraordinário para o desenvolvimento no front-end ,em situações onde trabalhamos com CRUD que envolve tabelas normalizadas, a técnica de lookup nem sempre será adequada. Observamos diversas situações em que o emprego do Lookup trará grande inconveniência, tanto no para usabilidade quanto para outros pontos importantes como: Performance e manutenibilidade. Um caso onde o Lookup é desaconselhado é quando a tabela de lookup possui muitos registros.

Em substituição a técnica de Lookup devemos usar, em conjunto, mais de uma técnica. Um exemplo comum é o join no próprio SQL do Dataset que manipula os dados, para tratar o pacote transacional posteiormente no evento BeforeUpdateRecord do DatasetProvider. Mas isso exige conhecimento intermediário em DataSnap. Em Breve abordaremos esse tema!

Artigo completo (View Full Post)

Delphi Intraweb 8 – Acessando dados – BDS2006

Neste artigo pretendo demonstrar como usar os componentes dataware do framwork Intraweb 8.
Tenho observado muitos problemas com essa versão da Intraweb. Graças a Deus parece que ninguém ousou usar esse framework, com algumas raras exceções. Se você veio aqui procurando saber se deve ou não iniciar um projeto com essa tecnologia, minha sugestão é: Procure outra coisa, ou na falta de alternativa use Delphi 7 com a versão 5.o do Intraweb.

Vamos construir uma aplicação que vai acessar a base de dados Northwind do SQL Server. Northwind, é uma base criada por default no SQL server, na instalação, cujo objetivo é didático. Ela é usada nos treinamentos oficiais da Microsoft, e exemplifica integralmente um banco de dados usado em um cenário real, profissional



Explicando sobre a base de dados

OBS:
Caso você já conheça a base Northwind, pode pular essa parte indo direto para “Iniciando um projeto Intraweb”.


Vamos trabalhar com as tabelas Categories (Refere-se as categorias dos produtos) e Products (Produtos).
Com o botão direito do mouse sobre “Diagrams”, na tree view, dentro do nó “Northwind”, podemos criar um DER (Diagram Entidade Relacionamento) das tabelas e entender como os dados se relacionam neste data base.



Nosso exemplo estará restrito ao contexto demonstrado na figura abaixo:



O relacionamento demonstrado acima indica que uma “Categoria” pode classificar muitos produtos. Sendo que o “Produto” somente pode ser classificado por uma “Categoria”. Este tipo de relacionamento chama-se “Um para N” (1-N). No relacionamento “Um para N” a chave (campo de relacionamento) aponta para a tabela “N”, no caso “Produtos”.
Isso quer dizer que na tabela Producs, existe uma coluna que referencia a tabela “Categories”. Em outras palavras: A coluna “CategoryID”, de “Producs” aponta para a “CategoryID” de “Categories”.


Iniciando um projeto Intraweb

Inicie um novo projeto do DBS2006: No menu File ►New ► Other ►Intraweb, selecione “Intraweb Application Wizard”.



No diálogo seguinte, “Intraweb Application Wizard”, definiremos alguns parâmetros da nova aplicação que criaremos. Configure conforme ilustrado na imagem abaixo:



Adicione na Unit1 os seguintes componentes:

IWDBEdit1: TIWDBEdit
IWDBListbox1: TIWDBListbox
IWDBNavigator1: TIWDBNavigator
IWDBLookupComboBox1: TIWDBLookupComboBox
IWButton1: TIWButton
IWCheckBox1: TIWCheckBox
ADOConnection1: TADOConnection
ADODataSet: TADODataSet, altere a propriedade “Name” para: AdsCategotias.
DataSetProvider: TdataSetProvider , altere a propriedade “Name” para: DspCategotias
ClientDataSet: TClientDataSet, altere a propriedade “Name” para: CdsCategotias
DataSource: TDataSource, altere a propriedade “Name” para: DsCategotias
ADODataSet: TADODataSet, altere a propriedade “Name” para: AdsProdutos
DataSetProvider: TDataSetProvider, altere a propriedade “Name” para: DspProdutos
ClientDataSet: TClientDataSet, altere a propriedade “Name” para: CdsProdutos
DataSource: TDataSource, altere a propriedade “Name” para: DsProdutos
OBS: A partir do DBS 2005 foi inroduzido na IDE do Delphi um novo conceito para a “Tool Palette”. Para vizualizá-la acesse o menu Vew ► Tool Palette. Hot key “Ctrl + Alt + P” ou digite “Alt” seguido de “V” seguido de “L”.



Uma forma fácil de adicionar um novo componente ao seu projeto é clickar sobre o ícone de filtro na Tool Palette e digitar o nome do componente. Veja imagem abaixo:



Veja o meu Form como ficou em tempo de projeto:




Conecte os componentes de acesso a dados da seguinte forma:

Selecione o IWEdit1, acesse o Objetc Inspector (F11). Associe IWDbEdit1, através da propriedade DataSource, ao DsProdutos. Defina a coluna (campo) que será associada ao IWEdit na propriedade “DataField”. Selecione “ProductName”.

Selecione o DsProdutos, acesse o Objetc Inspector (F11). Associe DsProdutos, através da propriedade DataSet, ao CdsProdutos.

Selecione o CdsProdutos, acesse o Objetc Inspector (F11). Associe CdsProdutos, através da propriedade ProviderName, ao DspProdutos.

Selecione o DspProdutos, acesse o Objetc Inspector (F11). Associe DspProdutos, através da propriedade “DataSet”, ao AdsProdutos.

Selecione o AdsProdutos, acesse o Objetc Inspector (F11). Associe AdsProdutos, através da propriedade “Connection”, ao ADOConnction1.


Conectando o acesso a categoria de produtos:

Selecione o DsCategotias, acesse o Objetc Inspector (F11). Associe DsCategotias, através da propriedade DataSet, ao CdsCategotias.

Selecione o CdsCategotias, acesse o Objetc Inspector (F11). Associe CdsCategotias, através da propriedade ProviderName, ao DspCategotias.

Selecione o DspCategotias, acesse o Objetc Inspector (F11). Associe DspCategotias, através da propriedade “DataSet”, ao AdsCategotias.

Selecione o AdsCategotias, acesse o Objetc Inspector (F11). Associe AdsCategotias, através da propriedade “Connection”, ao ADOConnction1.


Conectando o IWDBLookupComboBox1:


Selecione o IWDBLookupComboBox1, acesse o Objetc Inspector (F11). Associe IWDBLookupComboBox1, através da propriedade DataSource, ao DsProdutos. Defina a coluna (campo) que será associada ao IWDBLookupComboBox1 na propriedade “DataField”. Selecione “CategoryID”. A associação ao CdsCategorias deve ser feita através das propriedades:

1 – “ListSource”, nela selecione “DsCategotias”.
2 - “KeyField”, nela selecione “CategoryID”.
3 - “ListField”, nela selecione “CategoryName”

Esses três campos são do CdsCategorias. Veja mais detalhes sobre a técnica de Lookup ...




Conectando o IWDBListbox1:

Selecione o IWDBListbox1, acesse o Objetc Inspector (F11). Associe IWDBListbox1, através da propriedade DataSource, ao DsProdutos. Defina a coluna (campo) que será associada ao IWDBListbox1 na propriedade “DataField”. Selecione “Discontinued”. Este campo indica se o produpo foi descontinuado ou não.


Definindo os valores no DBListBox:

Na propriedade “Items”, click para acessar o editor. Digite “True”, em seguida, na linha de baixo, digite “False”. Como o CdsProdutosDiscontinued é um “TbooleanField” isso vai funcionar.





Na propriedade ItemsHaveValues, Selecione “False”.

Para a propriedade Height digite 41.


Conectando o IWDBNavigator:


Selecione o IWDBNavigator1, acesse o Objetc Inspector (F11). Associe IWDBNavigator1, através da propriedade DataSource, ao DsProdutos.


String connection no ADOConnection


Provider=SQLOLEDB.1;Persist Security Info=True;User ID=sa;Initial Catalog=Northwind;Use Procedure for Prepare=1;Auto Translate=True;Packet Size=4096;Workstation ID=Landjah;Use Encryption for Data=False;Tag with column collation when possible=False

Conectei no SQL Server, usarei as tabelas Categories e Products do banco “Northwind”. Ele é o banco padrão do SQL Server para exemplo e estudo.

Comando SQL nos Ads:
AdsCategorias
Propriedade CommandText:
select CategoryID, CategoryName from Categories

AdsProdutos
Propriedade CommandText:
select * from Products


Codificando o evento OnClick do IWButton1:
procedure TTADo.IWButton1Click(Sender: TObject);
begin
CdsCategotias.Open;
CdsProdutos.Open;
end;


Podemos também trabalhar com o evento OnCreate do Form.
procedure TTADo.IWAppFormCreate(Sender: TObject);
begin
IWButton1Click(IWButton1);
end;

Agora você pode executar a aplicação e testar, navegando, alterando, inserindo, ou excluindo dados.


Veja a imagem ilustrando as conexões data ware no Delphi:



Para rodar o exemplo pressione F9, quando aparecer o diálogo referente ao servidor, pressione F9 novamente.



No IWCheckBox1, defina para a propriedade Caption = 'Editar Produto'. No evento OnClick programe:
procedure TTADo.IWCheckBox1Click(Sender: TObject);
begin
if IWCheckBox1.Checked then
CdsProdutos.Edit;
end;


Agora no evento AfterPost do CdsProdutos sicronise o comportamento do IWCheckBox:
procedure TTADo.CdsProdutosAfterPost(DataSet: TDataSet);
begin
IWCheckBox1.Checked := False;
end;


Testando o comando do IWCheckBox



Salvando as alterações realizadas




Sucesso!

Artigo completo (View Full Post)

segunda-feira, 3 de novembro de 2008

Banco de Dados ou Bando de Dados?

O fato de se gastar na ordem dos milhares por uma tecnologia de banco de dados relacional, tipo Oracle, MS SQL Server, IBM DB2, etc, não garante por si só que você terá informações consistentes.
Se você deseja algum dia extrair informações que agreguem valor ao seu negócio, trate de garantir que o que entra no seu banco de dados não seja lixo.
Supondo que, no que tange a modelagem de dados seu banco seja impecável. Suponhamos ainda, que você comprou o que existe de mais poderoso em termos de hardware, ainda assim existe a possibilidade desses dois fatores serem totalmente irrelevantes caso não exista mecanismos de checagem, neste suposto data base, a fim de garantir que o dado que é “inputado” não possui qualidade.
Para isso existem as constraints, checks e domains. Através deles programamos regras no banco de dados que trabalharão para que tudo que for inserido nele seja consistente, compreensível, relevante (Leia mais sobre ... ).

Veja um exemplo desse tipo de controle:

-- Criando a tabela de Tipo de Contato
CREATE TABLE ZnTipo_Contato(
TIPO_ContatoID NUMBER (8,0) PRIMARY KEY,
DESCRICAO VARCHAR2(20) NOT NULL,
DT_CADASTRO TIMESTAMP NOT NULL,
UpdateDate TIMESTAMP NOT NULL,
USERUPDATE NUMBER (8,0) NOT NULL,
CONSTRAINT chk_DESCRICAO CHECK (LENGTH(DESCRICAO) > 4)
);


No trecho de código acima criei uma tabela que possui nela duas constraints, ou seja, duas checagens de controle. Uma que não permitirá valores repetidos (Primary Key) na coluna “Tipo_ContatoID” (linha 3). A outra, não vai permitir valores com menos de 4 caracteres na coluna “DESCRICAO” (linha 8).

Comentários nos Objetos de Banco de Dados

Outro ponto importante que vai ser de extrema relevância para que seu banco de dados passe longe de ser o “bando de dados” mais high tech do mundo é o cuidado em comentar cada objeto construído no banco. Isso deve ser considerado uma cultura a ser desenvolvida, tanto pela equipe, num âmbito gerencial, quanto individualmente (Ou seja, aonde quer que você vá leve esse bom hábito).

Pense, com que cara você vai ficar quando daqui a três meses alguém lhe perguntar qual o significado da coluna “ValPerJurosPgto” e você não lembrar? Todavia, para a mesma situação, se houver um comentário na coluna sua orelha vai ser eternamente grata por continuar cinco palmos menor (hehehhe), além disso seu bolso irá lhe agradecer o salário continuar entrando.

COMMENT ON TABLE ZnTipo_Contato IS 'Tabela de referência. Armazena os possíveis Tipos de Contato. Exemplo: Email, Telefone, Celular';
COMMENT ON COLUMN ZnTipo_Contato.TIPO_ContatoID IS 'Primary key da tabela ZnTipo_Contato.';
COMMENT ON COLUMN ZnTipo_Contato.DESCRICAO IS 'Descrição do Tipo de Contato.';
COMMENT ON COLUMN ZnTipo_Contato.DT_CADASTRO IS 'Data de Cadastro do registro na tabela ZnTipo_Contato.';
COMMENT ON COLUMN ZnTipo_Contato.UpdateDate IS 'Data em que o usuário do sistema que atualizou um registro de Tipo de Contato.';
COMMENT ON COLUMN ZnTipo_Contato.USERUPDATE IS 'Usuário do sistema que atualizou um registro de Tipo de Contato.';


Agora vamos fazer alguns testes ...

-- Criando a Sequence para geração de Uk para a tabela ZnTipo_Contato
CREATE SEQUENCE SQ_ZnTipo_Contato
MINVALUE 1
MAXVALUE 999999999999999999999999999
START WITH 1
NOCYCLE
NOORDER
CACHE 20;



A seguir, vou inserir alguns registros na nova tabela. Pretento, em dado momento testar a constraint "chk_DESCRICAO".



-- Inserindo registros de Tipo de Contato em ZnTipo_Contato

INSERT INTO ZnTipo_Contato(
TIPO_CONTATOID
, DESCRICAO
, DT_CADASTRO
, UPDATEDATE
, USERUPDATE
) VALUES
(
SQ_ZnTipo_Contato.NEXTVAL
, 'Email'
, SYSDATE
, SYSDATE
, 1
);

INSERT INTO ZnTipo_Contato(
TIPO_CONTATOID
, DESCRICAO
, DT_CADASTRO
, UPDATEDATE
, USERUPDATE
) VALUES
(
SQ_ZnTipo_Contato.NEXTVAL
, 'Telefone Residencial'
, SYSDATE
, SYSDATE
, 1
);

INSERT INTO ZnTipo_Contato(
TIPO_CONTATOID
, DESCRICAO
, DT_CADASTRO
, UPDATEDATE
, USERUPDATE
) VALUES
(
SQ_ZnTipo_Contato.NEXTVAL
, 'Telefone Comercial'
, SYSDATE
, SYSDATE
, 1
);

INSERT INTO ZnTipo_Contato(
TIPO_CONTATOID
, DESCRICAO
, DT_CADASTRO
, UPDATEDATE
, USERUPDATE
) VALUES
(
SQ_ZnTipo_Contato.NEXTVAL
, 'Telefone Celuar'
, SYSDATE
, SYSDATE
, 1
);

INSERT INTO ZnTipo_Contato(
TIPO_CONTATOID
, DESCRICAO
, DT_CADASTRO
, UPDATEDATE
, USERUPDATE
) VALUES
(
SQ_ZnTipo_Contato.NEXTVAL
, 'Gtalk'
, SYSDATE
, SYSDATE
, 1
);

INSERT INTO ZnTipo_Contato(
TIPO_CONTATOID
, DESCRICAO
, DT_CADASTRO
, UPDATEDATE
, USERUPDATE
) VALUES
(
SQ_ZnTipo_Contato.NEXTVAL
, 'Skype'
, SYSDATE
, SYSDATE
, 1
);

INSERT INTO ZnTipo_Contato(
TIPO_CONTATOID
, DESCRICAO
, DT_CADASTRO
, UPDATEDATE
, USERUPDATE
) VALUES
(
SQ_ZnTipo_Contato.NEXTVAL
, 'Orkut Profile'
, SYSDATE
, SYSDATE
, 1
);

COMMIT;


Ok, agora vamos provocar a validação. Vou inserir um tipo de contato cujo tamanho será menor que 4 caracteres.

---- Testanto a constraint, inserindo um contato cujo o tamanho é menor que 4

INSERT INTO ZnTipo_Contato(
TIPO_CONTATOID
, DESCRICAO
, DT_CADASTRO
, UPDATEDATE
, USERUPDATE
) VALUES
(
SQ_ZnTipo_Contato.NEXTVAL
, 'Msn'
, SYSDATE
, SYSDATE
, 1
);




Verificando os registros inseridos


SELECT * FROM ZnTipo_Contato;



Como posso ver os comentários que colocamos nas colunas da tabela?

SELECT * FROM ALL_COL_COMMENTS WHERE table_name = 'ZNTIPO_CONTATO'



Artigo completo (View Full Post)

quarta-feira, 29 de outubro de 2008

Importação e Exportação no Oracle

Olá, pessoal.

Estou passando por aqui porque tenho visto algumas pessoas com problemas para importar e exportar dados de um banco Oracle e, como venho fazendo isso com certa freqüência, resolvi fazer um post para mostrar os simples passos para a execução desta tarefa.

Primeiramente, você deve abrir o prompt do DOS (Iniciar > Executar > Digite "cmd" (sem aspas) > OK) e se posicionar dentro da pasta onde o executável do exp e do imp estão. No meu caso, tenho instalado na máquina um Oracle XE.
A pasta dos executáveis é a pasta BIN, que fica dentro da pasta onde o Oracle foi instalado. Supondo que o mesmo foi instalado em C:\Arquivo de Programas, o caminho seria algo assim: C:\Arquivos de Programas\oraclexe\app\oracle\product\10.2.0\server\BIN.


Então, no prompt, dê um "cd\" e vá para a pasta, fazendo "cd Arquivos de Programas\oraclexe\app\oracle\product\10.2.0\server\BIN".

Feito isso, para exportar, devemos executar o seguinte comando:

exp username/password@database file=arquivo.dmp log=arquivo.log full=yes

Onde:
username: Usuário do banco
password: Senha do Usuário
database: Instância do banco
arquivo.dmp: Caminho do arquivo de exportação
arquivo.log: Caminho do arquivo de log

Artigo completo (View Full Post)

quarta-feira, 22 de outubro de 2008

Front End x Back End – UDFS no Servidor SGBD


UDF: “User Defined Function”, nos SGDBs, são funções criadas pelo desenvolvedor. Os principais fornecedores de tecnologia de banco de dados disponibilizam essa feature nos seus produtos.

O modelo Cliente/Servidor caracteriza-se por centralizar a programação referente a regra de negócio no servidor SGBD. Neste artigo, veremos como executar uma função no banco Oracle (PL/SQL) a partir da aplicação em Delphi.

No Back-And

Primeiro vamos criar a função no Oracle, a qual posteriormente evocaremos de uma interface (um aplicativo, front-end), um programa desenvolvido em Delphi.


create or replace function DeterminaMaior(ZNValor1 in NUMBER, ZNValor2 in NUMBER, ZNValor3 in NUMBER) return number is
Result number;
begin
IF (ZNValor1 > ZNValor2) AND (ZNValor1 > ZNValor3) THEN
RESULT := ZNValor1;
ELSE
IF (ZNValor2 > ZNValor1) AND (ZNValor2 > ZNValor3) THEN
RESULT := ZNValor2;
ELSE
RESULT := ZNValor3;
END IF;
END IF;
return(Result);
end DeterminaMaior;



Compile a função “DeterminaMaior” e pronto! Finalizamos aqui a parte de programação no servidor.

No Front-End

Inicie uma aplicação (no menu - File, New, Application), adicione no form1 os Seguintes componentes:

1- TADOConnection (Palheta ADO): configure a conexão com o banco na propriedade “ConnectionString”. Em seguida, Altere a propriedade “LoginPrompt” para “False”.

2- TADOStoredProc(Palheta ADO): Associe ele ao ADOConnection através da propriedade “Connection”. Em seguida, na propriedade “ProcedureName” digite o nome da função que acabamos de criar. Exemplo: “DeterminaMaior”. Pode ser conveniente digitar o nome do schema ponto o nome da função, tipo: “[eschemaName]. DeterminaMaior”.

Feto isso, click na propriedade parameters e veja alista re parâmetros que ele recupera automaticamente. Veja a ilustração abaixo:




Adicione também um TBitBtn (Palheta Additional). Na propriedade “Caption” defina: “Determinar Maior”.

Preciso adicionar três edits (TEdit – Palheta Standard) e um Memo (TMemo – Palheta Standard).




Codificando o evento OnClick do BitBtn1: Digite conforme exemplificado abaixo:


procedure TForm1.BitBtn1Click(Sender: TObject);
const
ZnConstMsg = 'www.estacaozn.blogspot.com - O Valor maior é %s';
Var
ZnMsg: String;
begin

with ADOStoredProc1 do
begin
Parameters[0].Value := 0;
Parameters[1].Value := GetValorEdit(Edit1);
Parameters[2].Value := GetValorEdit(Edit2);
Parameters[3].Value := GetValorEdit(Edit3);
ExecProc;
end;
ZnMsg := Format(ZnConstMsg,
[VarTOStr(ADOStoredProc1.Parameters[0].Value)]);
Memo1.Lines.Add(ZnMsg);
MessageDlg(ZnMsg, mtInformation, [mbOK], 0);
end;

Nas linhas 2 e 3, defini como constante o valor da mensagem a ser exibida como resultado do processamento da UDF que criamos.

Nas linhas 4 e 5, declarei uma variável para auxiliar no out put do processamento que estamos realizando. Quando recuperar o valor retornado pela UDF vamos usá-la para compor a mensagem para o usuário.

Na liha 6, a palavra reservada “begin” inidca o início do bloco de comando executados pelo procedimento “BitBtn1Click”.

Na linha 7, espaço em branco. Devemos deixar espaços em branco em alguns casos onde desejamos que, na leitura do nosso código, o entendimento fique mais fácil.

Da linha 9 a 12, passamos os valores para os parâmetros do “ADOStoredProc1”. Note que criei uma função “GetValorEdit” para poder recuperar o valor dos edits de forma segura. veremos o código dela mais adiante.

Na linha 13, chamamos o método ExecProc, de TADOStoredProc, o qual executa a UDF, “DeterminaMaior”, no banco.

Na linha 15, formatamos o valor da mensagem que deverá ser exibida composta do valor retornado do processamento no banco.

Na linha 17, adiciono ao Memo1 a mensagem.

Na linha 18, chamamos a função “MessageDlg”, API do Windows, para exibir o resultado do processamento para o usuário.


Codificando o Método “GetValorEdit”:

Na seção “private” vamos codificar a declaração método “GetValorEdit”. Segue trecho de código ilustrando o corpo do método:



function TForm1.GetValorEdit(Edt: TEdit): Double;
var
AuxNum: Double;
begin
try
AuxNum := StrToFloat(Edt.Text);
except
on EConvertError do
AuxNum := 0;
end;

Result := AuxNum;
end;


Agora execute a aplicação (pressione F9) e teste ...



A seguir, código completo da unit ...
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons, DB, ADODB;

type
TForm1 = class(TForm)
BitBtn1: TBitBtn;
ADOStoredProc1: TADOStoredProc;
ADOConnection1: TADOConnection;
Memo1: TMemo;
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
procedure BitBtn1Click(Sender: TObject);
private
function GetValorEdit(Edt: TEdit): Double;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.BitBtn1Click(Sender: TObject);
const
ZnConstMsg = 'www.estacaozn.blogspot.com - O Valor maior é %s';
Var
ZnMsg: String;
begin

with ADOStoredProc1 do
begin
Parameters[0].Value := 0;
Parameters[1].Value := GetValorEdit(Edit1);
Parameters[2].Value := GetValorEdit(Edit2);
Parameters[3].Value := GetValorEdit(Edit3);
ExecProc;
end;
ZnMsg := Format(ZnConstMsg,
[VarTOStr(ADOStoredProc1.Parameters[0].Value)]);
Memo1.Lines.Add(ZnMsg);
MessageDlg(ZnMsg, mtInformation, [mbOK], 0);
end;

function TForm1.GetValorEdit(Edt: TEdit): Double;
var
AuxNum: Double;
begin
try
AuxNum := StrToFloat(Edt.Text);
except
on EConvertError do
AuxNum := 0;
end;

Result := AuxNum;
end;

end.


Artigo completo (View Full Post)

Pl/SQL Sequence

A “Sequence” é um objeto de banco de dados cujo aprincipal e única função é permitir que vários usuários possam gerar valores inteiros isentos de duplicidade (não repetidos). Essa funcionalidade é usada quando precisamos gerar valores para uma coluna Unique Key (UK). Ou seja,uma coluna cujos valores são únicos. Uma coluna “Uk” pode ser definida como chave primária (PK).
Outros SGBDSR, além do Oracle, também trabalham com ess conceito.
Observe que, embora o nome seja “sequence” não há nela nehum comprometimento em gerar sequencias de valores. A sequence tem a responsabilidade apenas de gerar valores únicos.
Abaixo veja a sintaxe para criação de uma “Sequence”:

CREATE SEQUENCE [schema.]sequence
[INCREMENT BY integer]
[START WITH integer]
[MAXVALUE integer]
[MINVALUE integer]
[CYCLE | NOCYCLE]
[CACHE integer | NOCACHE]
[ORDER | NOORDER]


Sobre os Parâmetros

schema :
Nome do usuário dono da sequence.
Sequence: Nome da sequence.
INCREMENT BY: Define o intervalo entre os números gerados.
MINVALUE: Define o valor mínimo que a sequence pode assumir.
MAXVALUE: Valor máximo que a sequence pode assumir.
START WITH: O primeiro valor gerado pela sequence.
CYCLE: Define a sequence como cíclica. Ou seja, recomeçará, do valor mínuimo, a contagem quando atingir os extremos.
NOCYCLE: Define a sequence como não cíclica. Incrementando até atingir o limite estipulado.
CACHE: Otimiza o processo de geração de UK. Define quantos valores da sequence o ORACLE ira manter na memória para um acesso mais rápido.
NOCACHE: Não terá valores pré-alocados.
ORDER: Garante que o numero gerado pela sequence obedece a ordem de requisição.
NOORDER: Não garante que os números seqüenciais gerados obedecem à ordem de requisição.




Exemplo I
O comando seguinte cria uma sequence com incremento de 10 começando do 1:

CREATE SEQUENCE ZnVSqc
INCREMENT BY 10


Exemplo II
O comando a seguir cria uma sequence com incremento de 1 começando do 11:

CREATE SEQUENCE ZnVSqc_MusicUk
INCREMENT BY 1
START WITH 11;

Para usar a sequence e gerar um valor “uk” novo, ou verificar qual o valor do último gerado, podemos através de comandos SQL retornar valor desejado. Veja conforme ilustração abaixo:

-- retorna o valor coorente da sequence
SELECT ZnVSqc_MusicUk.currval FROM dual;
-- Gera um novo uk e retorna o valor gerado (Nextval).
SELECT ZnVSqc_MusicUk.nextval FROM dual;








Artigo completo (View Full Post)

Conexão ADO & Oracle – Configurando uma conexão TADOConnection

Este post pretende exemplificar como configurar, no Delphi, uma conexão com Oracle usando a middleware de acesso a dados OLE DB.

Para configurar a conexão com o banco temos que acessar a propriedade “ConnectionString” de TADOConnection. Em tempo de projeto, pelo Object Inspector, podemos usar o wizard de configuração da string de conexão. Para isso, dê um duplo click na propriedade, ou com o botão direito do mouse sobre o componente ADOConnectio (que estiver no seu form ou datamodule), selecione “Edit ConnectionString”.




No botão “Build” acessamos o diálogo para definir o driver de acesso que vamos usar (nativamente a MS OLE DB provê drivers para algumas tecnologias de banco de dados).




Selecione OLE DB Provider for Oracle ... em seguida click no botão “Avançar >>”


Em Nome do Servidor, digite o nome da conexão que esta definida no arquivo “tnsnames.ora” (Normamente fica em \oracle\product\[versão]\server\NETWORK \ADMIN).



XEZn =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 123.1.22.22)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = XEZn)
)
)




O login de acesso você digita em “Nome do Usuário” e “Senha”. Marque “Permitir salvamento de senha”. Após digitar esses valores click em “Testar Conexão”.
Ao receber a mensagem de que a conexão foi feita com sucesso, click em “OK”.


Para finalizar, configure a propriedade “LoginPrompt” para “False”. Fazemos isso quando não desejamos que, ao ativarmos a conexão, seja exibido o diálogo para digitação do login (usuário/senha).






Sua string de conexão deverá ter sido montada semelhante ao exemplificado abaixo:
Provider=MSDAORA.1;Password=blavlablaval;User ID=EstacaoZN;Data Source=XEZn;Persist Security Info=True 


OBS:
No dia a dia profissional, corriqueiramente usamos a sigla referente aos objetos de acesso a dados (ADO ActiveX Data Objects) como se isso fosse o nome da middleware da Microsoft. Esse hábito pode causar algumas confusões para quem esta tendo um primeiro contado com essa tecnologia.
Existem dois drivers na OLE DB para conexões Oracle. Um deles é o nativo da OLE DB: “Microsoft OLE DB Privider for Oracle”. O Segundo é um driver da própria Oracle: “Oracle Provider for OLE DB”. O OraOLEDB provider é um componente COM. A versão 10.0.1.2.0 suporta Oracle Grids, além de suportar os seguintes datatypes nativos do Oracle Database 10g:

BINARY_DOUBLE
BINARY_FLOAT
O Microsoft OLE DB Privider for Oracle possui incompatibilidade com os tipos "LOB" nativos do Oracle, CLOB (Character Large Object) e BLOB (Binary Large Object).


A versão 9.2.0.4.0 trouxe suporte aos seguintes datatypes introduzidos no Oracle9i:
- TIMESTAMP
- TIMESTAMP WITH TIME ZONE
- TIMESTAMP WITH LOCAL TIME ZONE
- INTERVAL YEAR TO MONTH
- INTERVAL DAY TO SECOND

Artigo completo (View Full Post)

 
BlogBlogs.Com.Br