quarta-feira, 16 de setembro de 2015

Saiba mais sobre o dbExpress e como usar esta arquitetura em suas aplicações Delphi envolvendo banco de dados


Uma das características mais significativas do Delphi é seu suporte para os mais diferentes bancos de dados usando diferentes tecnologias de acesso: BDE, dbExpress, InterBase Express, ADO, Borland Data Providers for .NET, etc. Nesta dica abordarei o dbExpress devido à sua forte aceitação no mercado.

Durante as versões iniciais do Delphi houve tentativas de se criar uma API comum para o acesso a vários e diferentes bancos de dados. No entanto, todas as soluções apresentaram um ou mais problemas. Algumas abordagens se tornaram demasiadas complexas, lentas e dificil de distribuir. Outras apresentavam problemas relacionados à complexidade de se escrever os drivers para os bancos de dados, tornando-as limitadas em funcionalidade, lentas e cheias de bugs.

O dbExpress (apresentado pela primeira vez no Delphi 6) supera todos estes problemas ao combinar a abordagem de fornecer uma API comum para vários bancos de dados com a arquitetura provide/resolve da Borland para gerenciar o processo de edição e atualização de dados. 

A arquitetura dbExpress

O dbExpress (anteriormente chamado de DBXpress) foi desenvolvida para atingir os seguintes objetivos:

a) Minimizar o tamanho e uso de recursos do sistema.
b) Maximizar a velocidade.
c) Fornecer suporte cross-platform (independente de plataforma).
d) Fornecer fácil distribuição.
e) Facilitar o desenvolvimento de drivers.
f) Fornecer ao desenvolvedor um maior controle sobre o uso de memória e tráfego de rede.

Os drivers do dbExpress são pequenos e rápidos porque eles fornecem uma funcionalidade muito limitada. Cada driver é implementado como uma DLL única na plataforma Windows e como um único objeto compartilhado na plataforma Linux. Um driver dbExpress implementa cinco interfaces que suportam a obtenção de metadados, a execução de instruções SQL e stored procedures e o retorno de um cursor unidirecional somente leitura para um conjunto de resultados (result set). Contudo, quando usado em conjunto com os componentes DataSetProvider e ClientDataSet para implementar a estratégia de acesso de dados provide/resolve, o dbExpress nos oferede um sistema completo de alta concorrência e de alta performance para o desenvolvimento de aplicações que lidam com bancos de dados SQL.

Os componentes do dbExpress são:

TSQLConnection - Define uma conexão com um banco de dados, similar ao TDatabase.

TSQLDataSet - Representa um conjunto de dados unidirecional de propósito geral que executa a instrução SQL definida na propriedade CommandText. O valor desta propriedade pode ser uma instrução SELECT que retorna um conjunto de dados, uma instrução SQL que não retorna dados ou executa uma stored procedure.

TSQLQuery - Suporta instruções SQL a serem executadas e que retornam um conjunto de dados unidirecional ou atualizam dados ou esquemas de banco de dados.

TSQLStoredProc - Executa uma stored procedure. Se houver um conjunto de dados como retorno este será unidirecional.

TSQLTable - Fornece acesso unidirecional a uma tabela da base de dados.

TSQLMonitor - Usado para interceptar e exibir mensagens transferidas entre um TSQLConnection e o banco de dados.

TSimpleClientDataSet - Combina um TSQLDataSet e TDataSetProvider em um mesmo componente para suportar dados em cache de memória.

terça-feira, 15 de setembro de 2015

Como obter uma substring de uma string

*Fonte Arquivo de Códigos

Em algumas situações precisamos obter uma substring de uma string. Em Delphi isso pode ser feito por meio da função AnsiMidStr(). Esta função requer a string a partir da qual a substring será obtida, a posição inicial da substring (começando em 1) e a quantidade de caracteres que comporâo a substring. O retorno será uma nova string contendo a substring obtida. Veja o exemplo:

procedure TForm1.Button1Click(Sender: TObject);
var
  frase, substring: string;
begin
  frase := 'Programar em Delphi é muito bom';

  // vamos obter a substring "Delphi"
  substring := AnsiMidStr(frase, 14, 6);

  // vamos exibir o resultado
  ShowMessage('Resultado: ' + substring);
end;

Não se esqueça de adicionar a unit StrUtils no uses do seu formulário.

Para questões de compatibilidade, esta dica foi escrita usando Delphi 2009.

Programação orientada a objetos em Delphi: Classes, objetos, métodos e variáveis de instância


A melhor forma de entender a programação orientada a objetos é começar com uma analogia simples. Suponha que você queira dirigir um carro e fazê-lo ir mais rápido pressionado o acelerador. O que deve acontecer antes que você seja capaz de fazer isso? Bem, antes que você possa dirigir um carro, alguém tem que projetá-lo. Um carro geralmente começa com desenhos feitos pelos engenheiros responsáveis por tal tarefa, tal qual a planta de uma casa. Tais desenhos incluem o projeto de um acelerador que possibilita ao carro ir mais rápido. O pedal do acelerador "oculta" os mecanismos complexos responsáveis por fazer o carro ir mais rápido, da mesma forma que o pedal de freio "oculta" os mecanismos que fazem o carro ir mais devagar e o volante "oculta" os mecanismos que fazem com que o carro possa virar para a direita ou esquerda. Isso permite que pessoas com pequeno ou nenhum conhecimento de motores possam facilmente dirigir um carro.

Infelizmente, não é possível dirigir o projeto de um carro. Antes que possamos dirigí-lo, o carro deve ser construído a partir do projeto que o descreve. Um carro já finalizado tem um pedal de aceleração de verdade, que faz com que o carro vá mais rápido. Ainda assim, é preciso que o motorista pressione o pedal. O carro não acelerará por conta própria.

Agora vamos usar nosso exemplo do carro para introduzir alguns conceitos de programação importantes à programação orientada a objetos. A execução de uma determinada tarefa em um programa exige um método. O método descreve os mecanismos que, na verdade, executam a tarefa. O método oculta tais mecanismos do usuário, da mesma forma que o pedal de aceleração de um carro oculta do motorista os mecanismos complexos que fazem com que um carro vá mais rápido. Em Delphi, começamos criando uma unidade de programa chamada classe para abrigar um método, da mesma forma que o projeto de um carro abriga o design do pedal de acelerador. Em uma classe fornecemos um ou mais métodos que são projetados para executar as tarefas da classe. Por exemplo, a classe que representa uma conta bancária poderia conter muitos métodos, incluindo um método para depositar dinheiro na conta, outro para retirar dinheiro, um terceiro para verificar o saldo, e assim por diante.

Da mesma forma que não podemos dirigir o projeto de um carro, nós não podemos "dirigir" uma classe. Da mesma forma que alguém teve que construir um carro a partir de seu projeto antes que pudessémos dirigí-lo, devemos construir um objeto de uma classe antes de conseguirmos executar as tarefas descritas nela.

Quando dirigimos um carro, o pressionamento do acelerador envia uma mensagem ao carro informando-o da tarefa a ser executada (neste caso informando-o de que queremos ir mais rápido). Da mesma forma, enviamos mensagens aos objetos de uma classe. Cada mensagem é uma chamada de método e informa ao objeto qual ou quais tarefas devem ser executadas.

Até aqui nós usamos a analogia do carro para introduzir classes, objetos e métodos. Já é hora de saber que um carro possui atributos (propriedades) tais como cor, o número de portas, a quantidade de gasolina em seu tanque, a velocidade atual, etc. Tais atributos são representados como parte do projeto do carro. Quando o estamos dirigindo, estes atributos estão sempre associados ao carro que estamos usando, e cada carro construído a partir do projeto sofrerá variações nos valores destes atributos em um determinado momento. Da mesma forma, um objeto tem atributos associados a ele quando o usamos em um programa. Estes atributos são definidos na classe a partir da qual o objeto é instanciado (criado) e são chamados de variáveis de instância da classe.

Veremos agora como definir uma classe em Delphi e usar um objeto desta classe em um programa. Para isso siga atentamente os passos abaixo:

1) Vá em File -> New -> Unit - Delphi. Isso vai gerar uma nova unit parecida com:

unit Unit2;

interface

implementation

end.

2) Salve esta unit com o nome de Cliente.pas e altere o seu código para:

unit Cliente;

interface

type
  TCliente = class
    private
      Nome: string;

    public
      // uma procedure que permite definir o nome do cliente
      procedure DefinirNome(Nome: String);
      // uma função que permite obter o nome do cliente
      function ObterNome: String;
  end;

implementation

procedure TCliente.DefinirNome(Nome: String);
begin
  // atribui ao membro Nome o valor recebido como argumento
  Self.Nome := Nome;
end;

function TCliente.ObterNome;
begin
  // retorna o valor do membro Nome
  Result := Self.Nome;
end;

end.

Note que esta classe possui um membro de instância privado chamado Nome e dois métodos públicos: uma procedure que recebe um valor e o atribui ao membro Nome e uma função que retorna o valor deste mesmo membro. Vamos agora criar um objeto desta classe a partir de outro formulário.

3) Em um outro formuário da aplicação, vá em File -> Use Unit e inclua a unit Cliente (uses Cliente;). Em seguida coloque o código abaixo no evento Click de um botão:

procedure TForm1.Button1Click(Sender: TObject);
var
  c: TCliente;
begin
  // vamos criar um objeto da classe Cliente
  c := TCliente.Create;

  // vamos definir o nome do cliente
  c.DefinirNome('Osmar J. Silva');

  // vamos obter o nome do cliente
  ShowMessage('O nome do cliente é: ' + c.ObterNome);
end;

Execute o programa e veja o resultado. Funcionou como esperado? Bem-vindo à programação orientada a objetos usando Delphi.

Para fins de compatibilidade, esta dica foi escrita usando Delphi 2009.

Formatando datas e horas em Delphi usando a função FormatDateTime()


Em algumas situações precisamos formatar um TDateTime e exibir seus valores de data e hora em formatos mais amigáveis ao usuário. Para isso o Delphi nos fornece a função FormatDateTime(), presente na unit SysUtils. Esta função recebe uma string de formatação e um TDateTime e retorna uma string contendo a data e hora formatadas. Veja um exemplo:

procedure TForm1.Button1Click(Sender: TObject);
var
  data: TDateTime;
  formatada: string;
begin
  // vamos obter a data de hoje
  data := Now;

  // vamos formatar
  formatada := FormatDateTime('dddd, dd "de" mmmm "de" yyyy',
    data);

  // vamos exibir o resultado
  ShowMessage(formatada);
end;

Aqui a data será exibida em um formato semelhante à "sexta-feira, 22 de outubro de 2008", ou seja, o formato de data longa do Windows.

Para tirar o máximo proveito da função FormatDateTime(), é importante conhecer os caracteres de formatação permitidos na função. Veja:

c - Exibe a data usando o formato dado pela variável global ShortDateFormat, seguida pelas horas usando o formato dado pelo variável global LongTimeFormat. As horas não serão exibidas se o valor das horas indicarem meia-noite.

d - Exibe o dia como um número não precedido de zero (1-31).

dd - Exibe o dia como um número precedido de zero (01-31).

ddd - Exibe o dia como uma abreviação (Dom-Sáb) usando as strings fornecidas pela variável global ShortDayNames.

dddd - Exibe o dia com o nome completo (Domingo-Sábado) usando as strings dadas pela variável global LongDayNames.

ddddd - Exibe a data usando o formato dado pela variável global ShortDateFormat.

dddddd - Exibe a data usando o formato dado pela variável global LongDateFormat.

e - (Windows somente) - Exibe o ano na era/período atual como um número não precedido por zero (somente os locales Japanese, Korean e Taiwanese).

ee - (Windows somente) - Exibe o ano na era/período atual como um número precedido por zero (somente os locales Japanese, Korean e Taiwanese).

g - (Windows somente) - Exibe a era/período atual como uma abreviação (somente os locales Japanese e Taiwanese).

gg - (Windows somente) - Exibe a era/período atual com um nome completo (somente os locales Japanese e Taiwanese).

m - Exibe o mês como um número não precedido por zero (1-12). Se o especificador m seguir imediatamente um especificador h ou hh, os minutos, e não é mês, são exibidos.

mm - Exibe o mês como um número precedido por zero (01-12). Se o especificador m seguir imediatamente um especificador h ou hh, os minutos, e não é mês, são exibidos.

mmm - Exibe o mês como uma abreviação (Jan-Dez) usando as string dadas pela variável global ShortMonthNames.

mmmm - Exibe o mês com um nome completo (Janeiro-Dezembro) usando as strings dadas pela variável global LongMonthNames.

yy - Exibe o ano com dois dígitos (00-99).

yyyy - Exibe o ano com quatro dígitos (0000-9999).

h - Exibe a hora não precedida por zero (0-23).

hh - Exibe a hora precedida por zero (00-23).

n - Exibe os minutos não precedidos por zero (0-59).

nn - Exibe os minutos precedidos por zero (00-59).

s - Exibe os segundos não precedidos por zero (0-59).

ss - Exibe os segundos precedidos por zero (00-59).

z - Exibe os milisegundos não precedidos por zero (0-999).

zzz - Exibe os milisegundos precedidos por zero (000-999).

t - Exibe as horas usando o formato dado pela variável global ShortTimeFormat.

tt - Exibe as horas usando o formato dado pela variável global LongTimeFormat.

am/pm - Usa o relógio de 12 horas para os especificadores h ou h precedentes e exibe "am" para as horas antes do meio-dia e "pm" para as horas depois do meio-dia. O especificador am/pm pode ser em letras minúsculas, maiúsculas ou uma combinação destas.

a/p - Usa o relógio de 12 horas para os especificadores h ou h precedentes e exibe "a" para as horas antes do meio-dia e "p" para as horas depois do meio-dia. O especificador a/p pode ser em letras minúsculas, maiúsculas ou uma combinação destas.

ampm - Usa o relógio de 12 horas para os especificadores h ou hh e exibe o conteúdo da variável global TimeAMString para qualquer hora antes do meio-dia e o conteúdo de TimePMString para as horas depois do meio-dia.

/ - Exibe o caractere de separador de datas dado pela variável global DateSeparator.

: - Exibe o caractere de separador de horas dado pela variável global TimeSeparator.

'xx'/"xx" - Caracteres em aspas simples ou duplas não são formatados.

Para fins de compatibilidade, esta dica foi escrita usando Delphi 2009.

segunda-feira, 14 de setembro de 2015

Como usar a função FormatFloat() para formatar valores de ponto-flutuante em Delphi


A função FormatFloat() é muito útil quando queremos formatar valores de ponto-flutuante (valores que possuem a parte fracionária) em Delphi. Esta função recebe um padrão de formatação e o valor a ser formatado e retorna uma string. Veja um exemplo no qual formatamos o valor de PI com 2 casas decimais:

procedure TForm1.Button1Click(Sender: TObject);
var
  resultado: string;
begin
  // vamos formatar o valor de PI com 2 casas decimais
  resultado := FormatFloat('#.00', PI);

  // vamos exibir o resultado
  ShowMessage(resultado);
end;

O resultado será exibido como 3,14. Note que aqui nós informamos o ponto como separador decimal. No entanto, o Delphi busca o separador decimal na variável global DecimalSeparator, usada para facilitar a internacionalização, visto que este valor é obtido a partir das configurações regionais do Windows.

Para tirar o máximo proveito da função FormatFloat(), é necessário conhecer os especificadores de formato:

0 - Marcador de dígito. Se o valor a ser formatado tiver um dígito na posição ocupada por "0" na string de formatação, então este dígito é copiado para a string resultante. Do contrário, um "0" é guardado nesta posição na string resultante. Veja, por exemplo, como podemos formatar um valor sempre com 5 posições antes da vírgula:

procedure TForm1.Button1Click(Sender: TObject);
var
  valor: double;
  resultado: string;
begin
  valor := 4.50;

  // vamos formatar o valor com 5 posições antes da vírgula
  resultado := FormatFloat('00000.00', valor);

  // vamos exibir o resultado
  ShowMessage(resultado);
end;

# - Marcador de dígito. Se o valor a ser formatado tiver um dígito na posição ocupada por "0" na string de formatação, então este dígito é copiado para a string resultante. Do contrário, nada é guardado nesta posição na string resultante.

. - O primeiro caractere "." encontrado na string de formatação determina a posição do separador decimal na string resultante. Quaisquer caracteres "." encontrados após o primeiro "." serão ignorados. O caractere do separador decimal é determinado pela variável global DecimalSeparator ou seu equivalente TFormatSettings.

, - Separador de milhares. Se a string de formatação tiver um ou mais caracteres ".", o resultado terá separadores de milhares entre cada grupo de três dígitos à esquerda do ponto decimal. A posição e quantidade de "." não afeta o resultado, exceto para informar que os separadores de milhares são necessários. O caractere do separador decimal é determinado pela variável global ThousandSeparator ou seu equivalente TFormatSettings. Veja um exemplo no qual exibimos o valor 43765,15 com o separador de milhar:

procedure TForm1.Button1Click(Sender: TObject);
var
  valor: double;
  resultado: string;
begin
  valor := 43765.15;

  // vamos formatar o valor usando o separador de milhares
  resultado := FormatFloat(',.00', valor);

  // vamos exibir o resultado
  ShowMessage(resultado);
end;

E+ - Notação científica. Se qualquer uma das strings 'E+', 'E-', 'e+' ou 'e-' estiver contida na string de formatação, o valor será formatado usando notação científica. Um grupo de até quatro caracteres "0" poderá ser inserido após 'E+', 'E-', 'e+', ou 'e-' para determinar o número máximo de dígitos no expoente. O 'E+' e 'e+' provocará um sinal de positivo para a formatação de números positivos e um sinal de negativo para a formatação de números negativos. O 'E-' e 'e-' provocará um sinal negativo apenas para expoentes negativos.
'xx'/"xx" - Caracteres em asplas simples ou duplas são exibidos sem formatação.

; - Usado para separar seções para números positivos, negativos e zeros na string de formatação. Usamos isso quando queremos que valores positivos, negativos ou zerados sejam formatados de forma diferente.

Veja um último exemplo, desta vez formatando um valor em moeda brasileira (durante a autoria desta dica, a moeda usada é reais):

procedure TForm1.Button1Click(Sender: TObject);
var
  valor: double;
  resultado: string;
begin
  valor := 43765.15;

  // vamos formatar o valor usando o separador de milhares
  // e a moeda brasileira: reais
  resultado := FormatFloat('"R$ ",.00', valor);

  // vamos exibir o resultado
  ShowMessage(resultado);
end;

Aprenda a usar arrays (matrizes ou vetores) em Delphi


Em programação de computadores, um array, também conhecido como vector (para arrays uni-dimensionais) ou matriz (para arrays bi-dimensionais), é uma das mais simples estruturas de dados. Os arrays mantêm uma série de elementos de dados, geralmente do mesmo tamanho e tipo de dados. Elementos individuais são acessados por sua posição no array. A posição é dada por um índice, também chamado de subscrição. O índice geralmente utiliza uma seqüência de números inteiros, (ao contrário de um array associativo) mas o índex pode ter qualquer valor ordinal. Alguns arrays são multi-dimensionais, significando que eles são indexados por um número fixo de números inteiros, por exemplo, por um seqüência (ou sucessão) finita de quatro números inteiros. Geralmente, arrays uni- e bi-dimensionais são os mais comuns.

Os arrays podem ser considerados como as estruturas de dado mais simples que é possível imaginar. Têm a vantagem de que os seus elementos são acessíveis de forma rápida, mas têm uma notável limitação: são de tamanho fixo, mas podem ser incrementados ou diminuídos com determinados algoritmos, geralmente envolvendo a cópia de elementos de um array para outro e reinicializando o original com a nova dimensão. Os vetores podem ser implementados desta forma.

Em Delphi um array é declarado da seguinte forma:

var
  valores: array[1..10] of Integer;

Aqui nós temos um array chamado valores que contém 10 elementos do tipo Integer. Estes elementos podem ser acessados por índices que variarão de 1 a 10, ou seja, podemos acessar o 5º elemento da seguinte forma:

procedure TForm1.Button1Click(Sender: TObject);
var
  valores: array[1..10] of Integer;
begin
  valores[5] := 20;
end;

Este tipo de array que ora criamos é chamado de array estático, em contraposição aos arrays dinâmicos, os quais podem ter seus tamanhos redimensionados durante a execução do programa.

A forma mais prática de se trabalhar com arrays em Delphi é usando laços. Veja:

procedure TForm1.Button1Click(Sender: TObject);
var
  valores: array[1..5] of Integer;
  i, soma: Integer;
begin
  // vamos preencher o array com os valores de 1 a 5
  for i := 1 to 5 do
    begin
      valores[i] := i;
    end;

  // vamos percorrer o array novamente e obter a soma dos
  // valores de seus elementos
  soma := 0;
  for i := 1 to 5 do
    begin
      soma := soma + valores[i];
    end;

  // vamos exibir o resultado
  ShowMessage('A soma dos valores é: ' + IntToStr(soma));
end;

Aqui nós declaramos um array de 5 elementos do tipo Integer e inicializamos seus elementos com os valores de 1 a 5. Em seguida percorremos todo o array novamente para obter a soma dos valores dos elementos.

É possível também declarar e já inicializar um array. Veja:

procedure TForm1.Button1Click(Sender: TObject);
const
  valores: array[1..5] of Integer = (3, 2, 6, 12, 9);
var
  i, soma: Integer;
begin
  // vamos percorrer o array novamente e obter a soma dos
  // valores de seus elementos
  soma := 0;
  for i := 1 to 5 do
    begin
      soma := soma + valores[i];
    end;

  // vamos exibir o resultado
  ShowMessage('A soma dos valores é: ' + IntToStr(soma));
end;

Note que aqui eu declarei o array como uma constante. Isso aconteceu porque o Delphi não permite que inicializemos variáveis locais ([DCC Error] Unit1.pas(32): E2195 Cannot initialize local variables). Caso você realmente precise do array como variável e não constante, e deseje inicializá-lo juntamente com a declaração, mova-o para a seção interface do formulário ou classe.

Para finalizar, veja que é possível criar arrays de todos os tipos em Delphi. Veja no trecho de código abaixo como usamos um array de Char para guardar uma palavra e exibí-la normal e depois invertida:

procedure TForm1.Button1Click(Sender: TObject);
const
  letras: array[1..5] of Char = ('O', 's', 'm', 'a', 'r');
var
  i: Integer;
  resultado: String;
begin
  resultado := '';

  // vamos exibir a palavra na forma normal
  for i := 1 to 5 do
    resultado := resultado + letras[i];

  // exibe o resultado
  ShowMessage(resultado);

  // vamos exibir a palavra invertida
  resultado := '';
  for i := 5 downto 1 do
    resultado := resultado + letras[i];

  // exibe o resultado
  ShowMessage(resultado);
end;

Para fins de compatibilidade, esta dica foi escrita usando Delphi 2009.

Aprenda a executar comandos SQL usando o método ExecSQL() da classe TSQLDataSet


O método ExecSQL() da classe TSQLDataSet é usado quando queremos executar comandos SQL que não retornam um conjunto de dados. Este comando pode ser INSERT, UPDATE, DELETE, CREATE TABLE, etc, exceto SELECT.

Veja a assinatura deste método:

function ExecSQL(ExecDirect: Boolean = False): Integer; override;

ExecDirect é usado para indicar que a query não precisa ser preparada antes de ser executada. Este parâmetro pode ser definido como True se o comando não incluir nenhum parâmetro. Se o valor for False, a query será preparada antes de ser executada.

Vamos ver um exemplo? Veja um trecho de código no qual usamos o método ExecSQL() para disparar um comando SQL UPDATE. Note que aqui estamos usando um comando SQL preparado (pré-compilado):

procedure TForm3.Button1Click(Sender: TObject);
var
  nome: string;
  id: integer;
begin
  nome := 'OSMAR J. SILVA';
  id := 2; // id do registro a ser atualizado

  // vamos definir o comando SQL a ser executado
  SQLDataSet1.CommandText := 'UPDATE contatos SET nome = :nome WHERE id = :id';
  SQLDataSet1.Params[0].Name := 'nome';
  SQLDataSet1.Params[0].Value := nome;
  SQLDataSet1.Params[1].Name := 'id';
  SQLDataSet1.Params[1].Value := id;

  // como o comando é preparado, vamos definir o valor
  // False para o parâmetro ExecDirect
  SQLDataSet1.ExecSQL(False);

  // vamos mostrar uma mensagem indicando o sucesso da operação
  ShowMessage('Comando SQL executado com sucesso.');
end;

É importante observar que o método ExecSQL() retorna o número de linhas afetadas pelo comando. O valor retornado se torna o valor da propriedade RowsAffected. Veja como modificar o código anterior para retornar a quantidade de linhas afetadas:

procedure TForm3.Button1Click(Sender: TObject);
var
  nome: string;
  id: integer;
  linhasAfetadas: integer;
begin
  nome := 'OSMAR J. SILVA';
  id := 2; // id do registro a ser atualizado

  // vamos definir o comando SQL a ser executado
  SQLDataSet1.CommandText := 'UPDATE contatos SET nome = :nome WHERE id = :id';
  SQLDataSet1.Params[0].Name := 'nome';
  SQLDataSet1.Params[0].Value := nome;
  SQLDataSet1.Params[1].Name := 'id';
  SQLDataSet1.Params[1].Value := id;

  // como o comando é preparado, vamos definir o valor
  // False para o parâmetro ExecDirect
  linhasAfetadas := SQLDataSet1.ExecSQL(False);

  // vamos mostrar uma mensagem indicando o sucesso da operação
  ShowMessage('Comando SQL executado com sucesso. ' +
    IntToStr(linhasAfetadas) + ' linhas afetadas.');
end;

Lembre-se que não podemos usar ExecSQL() com comandos que retornam dados. Estes comandos incluem todos os comandos do tipo ctTable, queries SELECT e stored procedures que retornam um cursor. Quando o comando retornar dados, devemos usar o método Open ou definir a propriedade Active do SQLDataSet como True.

Curso de Delphi: 7.Consultas SQL