92
FORO DELPHI

Full Delphi

Embed Size (px)

DESCRIPTION

Delphi en español

Citation preview

Page 1: Full Delphi

FORO DELPHI

Page 2: Full Delphi

Serialización de facturas y albaranes con Delphi

En este artículo os explicamos paso a paso, con capturas de pantalla y con todas las explicaciones

necesarias cómo implementar en nuestras aplicaciones las facturas serializadas, según la serie elegida la aplicación generará el contador correspondiente. Utilizaremos Delphi como lenguaje de

programación, aunque es aplicable a cualquier lenguaje de programación. Serialización de facturas y albaranes con Delphi

La serialización de facturas y albaranes es una práctica muy común en casi todas las empresas que

requieren de una aplicación de facturación. Por ejemplo, se recomienda que las facturas de abono tengan su propio contador, independiente del contador general de las facturas "normales". Para implementar esta distinción en una aplicación informática podremos utilizar la serialización que,

además, nos servirá para otros muchos usos. Por ejemplo, para llevar contadores independientes según el tipo de factura.

Como ya hemos comentado, utilizaremos Delphi cómo lenguaje de programación y MySQL como motor de base de datos. Aunque la base de este manual sirve para cualquier lenguaje de

programación (con los cambios pertinentes) y para cualquier motor de base de datos.

En primer lugar necesitaremos dos tablas en la base de datos para guardar los contadores y las series de las facturas/albaranes. En una tabla guardaremos las series disponibles y la tabla a la que se podrán asignar, a continuación os mostramos el script sql necesario para crearla:

CREATE TABLE serie (

codigo int(10) unsigned NOT NULL auto_increment, nombre char(2) NOT NULL, tabla varchar(50) NOT NULL,

PRIMARY KEY (codigo), UNIQUE KEY serie_tabla_nombre USING BTREE (nombre, tabla)

) Por otro lado necesitaremos una segunda tabla donde se guardará el número por el que va cada serie

de cada tabla, con el script sql siguiente:

CREATE TABLE contador ( codigo int(10) unsigned NOT NULL auto_increment, tabla varchar(100) NOT NULL,

contador int(10) unsigned, serie char(2) NOT NULL,

PRIMARY KEY USING BTREE (codigo), UNIQUE KEY contador_tabla_serie USING BTREE (tabla, serie) )

Lógicamente necesitaremos también una tabla para alojar las facturas, con el siguiente script sql de

creación: CREATE TABLE factura (

codigo int(10) unsigned NOT NULL auto_increment, numexpediente varchar(15),

Page 3: Full Delphi

numerofactura varchar(25) NOT NULL, serie char(2) NOT NULL, codigocliente int(10),

matricula varchar(35), cobrado char(1),

fechacobro datetime, importetotal float, clientecontacto varchar(100),

fechacarga datetime, telefono varchar(40),

email varchar(100), observacion varchar(255), porcentajebeneficio float,

importebeneficio float, importetransportista float,

codigotransportista int(10), pagadotransportista char(1), fechapagotransportista datetime,

codusuarioa int(10) unsigned, codusuariom int(10) unsigned,

fechaa datetime, fecham datetime, pesonetototal float,

envasestotales float, paletstotales float, fecha datetime,

fechavencimiento datetime, PRIMARY KEY USING BTREE (codigo),

UNIQUE KEY factura_numerofactura USING BTREE (numerofactura, serie) )

En la tabla "factura", podremos observar que los dos campos utilizados para la serialización son "numerofactura" y "serie".

Para crear estas tablas podremos utilizar la aplicación AjpdSoft Administración Bases de Datos. Una vez creadas las tablas necesarias en la base de datos para la serialización de las facturas y

albaranes, pasaremos ahora a explicar cómo programar cada opción en la aplicación que estemos desarrollando:

Crearemos un formulario para la inserción y modificación de las series de la factura:

Page 4: Full Delphi

Se trata del formulario donde podremos introducir la Serie y la Tabla para la que la utilizaremos, en nuestro caso para la tabla "Factura". Los componentes de este formulario estarán enlazados con la tabla "Serie" creada anteriormente.

Crearemos un formulario para la inserción y modificación de los contadores:

Este formulario contendrá los controles enlazados con la tabla "Contador" creada anteriormente.

Este formulario mostrará el contador (número) y la serie, ambos se generarán de forma automática desde el formulario de la factura. Desde este formulario podremos modifcarlos en caso necesario.

Crearemos un formulario para la inserción y modificación de las facturas:

En este formulario será donde utilicemos las series y el contador, a continuación os mostramos el código fuente en Delphi del código que insertaremos en el evento OnClick del botón

bGenerarNumFactura que es el que hay en la parte derecha del campo del número de factura. Este botón generará el número de forma automática según la serie introducida en el campo anterior (txtSerie):

procedure TformGFactura.bGenerarNumFacturaClick(Sender: TObject);

var ano, mes, dia : word; begin

if txtSerie.Text = '' then

Page 5: Full Delphi

begin MessageDlg('La serie de la factura debe tener un valor.', mtWarning, [mbok], 0); txtSerie.SetFocus;

end else

begin decodeDate(now, ano, mes, dia); md.tFacturanumerofactura.AsString := llenarCadena(floattostr(generarNumeroSerie (

txtSerie.Text, vtTablaFactura)),6,'0', false) + '/' + inttostr(ano); end;

end; Donde:

txtSerie: es el TDBComboBox que contendrá un desplegable con las series disponibles para

la tabla actual (Facturas).

md.tFactura: es el componente TTable enlazado con la tabla "Facturas", donde se guardan

los datos de la factura.

llenarCadena: es una función que rellena una cadena dada con el carácter indicado y con el

tamaño indicado. A continuación os mostramos el código de esta función: function llenarCadena ( cadena : string; numero : integer;caracter : Char;

derecha : Boolean) : string; begin

while Length(cadena) < numero do begin if derecha then

cadena := cadena + caracter else

cadena := caracter + cadena; end; llenarCadena := cadena;

end;

Esta función generará un número con el formato: 000032/2007. generarNumeroSerie: esta función accede a la tabla "Contador" y obtiene el número por el que vaya

el contador según la serie y la tabla que se le pase como parámetro. También incrementa el contador de esta tabla y serie. El código de esta función es el siguiente:

function generarNumeroSerie (serie, tabla : string) : integer; var

contador : integer; begin

result := 1; with md.tcContador do begin

Close; //obtenemos el contador de la tabla contadores

SQL.Clear;

Page 6: Full Delphi

SQL.Add('SELECT *'); SQL.Add('FROM ' + vtTablaContador); SQL.Add('WHERE tabla = :pTabla and serie = :pSerie');

ParamByName('pTabla').DataType := ftString; ParamByName('pTabla').AsString := tabla;

ParamByName('pSerie').DataType := ftString; ParamByName('pSerie').AsString := serie; Open;

if not (FieldByName('Contador').AsInteger = 0) then begin

try contador := FieldByName('contador').AsInteger + 1; //Incrementamos el contador de la tabla contadores

Close; SQL.Clear;

SQL.Add('UPDATE ' + vtTablaContador + ' SET contador = :pContador' + ' WHERE tabla = :pTabla' + ' and serie = :pSerie'); ParamByName('pContador').DataType := ftInteger;

ParamByName('pContador').AsInteger := contador; ParamByName('pTabla').DataType := ftString;

ParamByName('pTabla').AsString := tabla; ParamByName('pSerie').DataType := ftString; ParamByName('pSerie').AsString := serie;

ExecSQL; close; result := contador;

except Close;

result := 1; MessageDlg ('El código no ha podido ' + 'generarse automáticamente.',mtError, [mbOK], 0); end;

end else

//si no existe el registro de contador para la tabla actual, lo creamos begin try

Close; SQL.Clear;

SQL.Add('INSERT INTO ' + vtTablaContador + ' (tabla, serie, contador) ' + ' VALUES (:pTabla, :pSerie, 1)'); ParamByName('pTabla').DataType := ftString;

ParamByName('pTabla').AsString := tabla; ParamByName('pSerie').DataType := ftString;

ParamByName('pSerie').AsString := serie; ExecSQL; result := 1;

Close; except

Close; MessageDlg ('El contador no se ha ' + 'guardado correctamente.',mtError, [mbOK], 0);

Page 7: Full Delphi

end; end; end;

end;

Donde: md.tcContador: es el TTable enlazado con la tabla "Contador", donde se guarda un registro por

cada serie y factura con el número por el que vaya actualmente el contador. La aplicación funcionando tendrá este aspecto:

Page 8: Full Delphi

Splash Screens en Delphi

Las Splash Screens son la pantallas de carga de los programas, algunas tardan segundos y

otras minutos, dependiente si la aplicación tiene un peso considerable para nuestra

computadora, también se caracterizan por incluir una imagen o una barra de carga para

saber cuando se inicializara el entorno para el usuario.

Primer paso

Agregamos un form nuevo en el proyecto File->New->Form

Le ponemos un nombre fácil de recordar name: SplashForm

Normalmente las Splash Screens no tienen borde y están centradas en la pantalla

bordestyle: bsNone

position: poScreenCenter

Después agregamos una imagen con el control Timage y asignamos la fotografía en la

propiedad picture, para que se ajuste a la imagen poner autosize: true también al

SplashForm autosize: true con esto hacemos que el splashscreen tenga el mismo tamaño

que la imagen

Segundo paso:

Tendremos que decir a Delphi que nuestra aplicación no la auto cree como las otras, por

eso vamos a Project->Options Pestaña Forms, Seleccionamos splashForm y la ponemos a

AVailable forms

Vamos al código del poyecto Project->View Source. Tenemos que tener parecido a esto

program Project1;

uses

Forms,

Unit1 in „Unit1.pas‟ {Form1},

Unit2 in „Unit2.pas‟ {SplashForm};

{$R *.res}

begin

Application.Initialize;

Application.CreateForm(TForm1, Form1);

Application.Run;

end.

Page 9: Full Delphi

Tercer paso:

Nuestra splash screen se debe crear antes de todos los demás form, y al terminar la carga de

las forms, esconderla y liberar su memoria

begin

SplashForm := TSplashForm.Create(Application);

SplashForm.Show;

SplashForm.Update;

Ahora tenemos que poner los forms que se deben cargar al inicio

Application.CreateForm(TForm1, Form1);

Antes que nuestra applicación muestre la pantalla principal tenemos que, esconder la splash

screen y liberar su memoria

SplashForm.Hide;

SplashForm.Free;

Application.Run;

Finalizando:

Si compilamos veremos que nuestra splash screen no tiene tiempo de aparecer, si queremos

que se muestre unos segundos, agregamos la siguiente línea antes de SplashForm.Hide

Sleep(2000);

Función Sleep es de la unidad SysUtils, para poderla utilizar debemos cargarla en uses del

proyecto

uses

Forms, Unit1 in „Unit1.pas‟ {Form1}, Unit2 in „Unit2.pas‟ {SplashForm}, SysUtils;

Ya podemos compilar y ver nuestra primera splash screen

Page 10: Full Delphi

Configurar o Firewall do Windows XP com SP2 para Interbase/Firebird

O pacote de atualização Service Pack 2 (SP2) do Windows XP inclui um Firewall para proteção da redecontra acesso não autorizado, seja pela internet ou através da rede local. Este programa bloqueiaautomaticamente quase todas as portas de acesso do protocolo TCP/IP, incluindo a porta 3050 que porpadrão é usada pelos bancos de dados Interbase e Firebird.

Então para que outros computadores possam acessar um banco de dados Interbase ou Firebird em umservidor com Windows XP com SP2 que esteja com Firewall ativado é necessário adicionar uma exceção,ou seja, informar ao Firewall que a porta 3050 não deve ser bloqueada. Para fazer isto siga os os passosabaixo:

Clique em Iniciar/Configurações/Painel de controle;Abra o item denominado Firewall do Windows;Vá para Exceções;Clique em Adicionar porta;No campo Nome digite Firebird ou Interbase;No campo Número da Porta digite 3050;Escolha o protocolo TCP e clique em Ok.

Após este procedimento a porta 3050 estará desbloqueada e o banco de dados Interbase ou Firebird estaráacessível através da rede.

Tabelas e views:

SELECT RDB$RELATION_NAME FROM RDB$RELATIONS;

Somente tabelas:

SELECT RDB$RELATION_NAME FROM RDB$RELATIONSWHERE RDB$VIEW_BLR IS NULL;

Somente views:

SELECT RDB$RELATION_NAME FROM RDB$RELATIONSWHERE NOT RDB$VIEW_BLR IS NULL;

Observação:

Para não incluir as tabelas e views de sistema, acrescente o filtro (RDB$SYSTEM_FLAG = 0 ORRDB$SYSTEM_FLAG IS NULL) na cláusula WHERE. Exemplo:

SELECT RDB$RELATION_NAME FROM RDB$RELATIONSWHERE RDB$VIEW_BLR IS NULL AND (RDB$SYSTEM_FLAG = 0 OR RDB$SYSTEM_FLAG IS NULL);

Listar as tabelas e views do banco de dados

Page 11: Full Delphi

Backup e restore com gbak

O InterBase/FireBird possui uma ferramenta de linha de comando específica para fazer e restaurar cópias desegurança (backup). No Windows o nome do programa é gbak.exe e no Linux seu nome é gbak (semextensão). Em ambos os sistemas a localização deste arquivo é o sub-diretório bin do InterBase/FireBird.

As sintaxes básicas deste comando são:

Para fazer um backup:

gbak -b -user usuario -password senha arquivo_banco arquivo_backup

Para restaurar um backup:

gbak -r -user usuario -password senha arquivo_backup arquivo_banco

Onde:

usuario: é o nome de login do usuário (geralmente SYSDBA).senha: é a senha do usuário.arquivo_banco: é o arquivo de banco de dados (geralmente com extensão .gdb).arquivo_backup: é o arquivo de backup (geralmente com extensão .gbk).

Exemplo de backup:

gbak -b -user SYSDBA -password masterkey c:\sistema\dados.gdb c:\backup\dados.gbk

Exemplo de restore:gbak -r -user SYSDBA -password masterkey c:\backup\dados.gbk c:\sistema\dados.gdb

Obter o valor de um generator

Para obter o valor de um generator devemos usar a função GEN_ID do InterBase/FireBird. A sintaxe é:

GEN_ID(NomeDoGenerator, Incremento);

Exemplos:

GEN_ID(Gen_Cliente_Codigo, 1);GEN_ID(Gen_Cliente_Codigo, 0);

No primeiro exemplo o generator será incrementado e o novo valor será retornado. Já no segundo exemplo ogenerator não será incrementado e seu valor atual será retornado.

Dentro de um trigger podemos atribuir o valor de um generator a um campo da tabela, como mostra oexemplo a seguir:

CREATE TRIGGER TRIG_Cliente_Inclusao FOR Cliente BEFORE INSERT ASBEGIN NEW.Codigo = GEN_ID(Gen_Cliente_Codigo, 1); END^

Page 12: Full Delphi

Reiniciar a contagem de um generator

Para re-iniciar a contagem de um generator basta executar o comando abaixo:

SET GENERATOR TO X;

Onde X é um número inteiro.

O exemplo abaixo define o valor do generator GEN_Cliente_Codigo igual a zero:

SET GENERATOR GEN_Cliente_Codigo TO 0

Observação:

O valor obtido com GEN_ID(GEN_Cliente_Codigo, 1) após o exemplo dado anteriormente será 1 (um),pois a função GEN_ID retorna o valor do generator já incrementado.

Para obter o valor de um generator através de uma aplicação, podemos executar o comando SELECTmostrado a seguir sobre uma tabela que possua apenas um registro:

SELECT GEN_ID(NomeDoGenerator, 1) FROM NomeTabela

Onde NomeTabela é o nome de uma tabela do banco de dados que precisa ter um, e somente um, registro.Geralmente usamos a tabela de sistema RDB$DATABASE para este propósito. Eis um exemplo:

SELECT GEN_ID(Gen_Cliente_Codigo, 1) FROM RDB$DATABASE;

Criar e usar domínios (domain's)

No InterBase e FireBird domínios são como tipos de dados. Tais domínios têm grande semelhança com oconceito de domínio aplicado à matemática, ou seja, um domínio define um conjunto de valores válidos parauma dada situação.

Podemos criar qualquer banco de dados sem fazer uso explícito de domínios. No entanto usar domíniosexplicitamente pode deixar o banco de dados mais organizado, com regras claras e bem definidas, e aindaconseguir uma economia substancial de mão de obra na construção e manutenção do banco.

Para demonstrar a utilidade dos domínios, vamos criar dois exemplos.

Excluir generator

No InterBase 6.0.x:

DELETE FROM RDB$GENERATORS WHERE RDB$GENERATOR_NAME = 'NOME_DO_GENERATOR';

No FireBird:

DROP GENERATOR NOME_DO_GENERATOR;

Page 13: Full Delphi

Exemplo 1 - Sem uso explícito de domínios:

CREATE TABLE Cliente( Codigo INTEGER NOT NULL, Nome VARCHAR(40) NOT NULL, Fone VARCHAR(20), Fax VARCHAR(20), Celular VARCHAR(20), Renda NUMERIC(9,2) DEFAULT 0 NOT NULL, CONSTRAINT PK_Cliente PRIMARY KEY(Codigo), CONSTRAINT CHK_Cliente_Codigo CHECK(Codigo > 0), CONSTRAINT CHK_Cliente_Renda CHECK(Renda >= 0));

Exemplo 2 - Com uso explícito de domínios:

CREATE DOMAIN DM_ChavePrimaria INTEGER NOT NULL CHECK(VALUE > 0);CREATE DOMAIN DM_NomePessoa VARCHAR(40) NOT NULL;CREATE DOMAIN DM_Fone VARCHAR(20);CREATE DOMAIN DM_Renda NUMERIC(9,2) DEFAULT 0 NOT NULL CHECK(VALUE >= 0);

CREATE TABLE Cliente( Codigo DM_ChavePrimaria, Nome DM_NomePessoa, Fone DM_Fone, Fax DM_Fone, Celular DM_Fone, Renda DM_Renda, CONSTRAINT PK_Cliente PRIMARY KEY(Codigo));

Comentários:

O benefício imediato do uso explícito de domínios é a organização do código que define as tabelas.Como um mesmo domínio será usado em várias tabelas (exemplo: DM_NomePessoa), ganharemosmuito tempo ao definir outras tabelas que comporão o banco de dados.O domínio DM_Fone é um exemplo que demonstra como um mesmo domínio pode ser usado paracolunas diferentes que possuem conteúdos semelhantes.Os domínios DM_ChavePrimaria e DM_Renda mostram aspectos mais interessantes na declaraçãode domínios, tais como a especificação de um valor padrão (DEFAULT) e regras para validação(CHECK).Se mais tarde resolvermos alterar os nomes de pessoas para 50 caracteres, ou seja, VARCHAR(50),bastará alterar a definição do domínio DM_NomePessoa e todos os campos definidos com estedomínio serão automaticamente ajustados. Neste caso bastaria o comando ALTER DOMAINDM_NomePessoa TYPE VARCHAR(50).Nos bancos de dados que crio, uso domínios explicitamente para todos os campos de todas as tabelas,mesmo onde aparentemente são desnecessários. Mas é bom lembrar que domínios mal definidos podemtrazer mais prejuízos do que benefícios. Portanto, antes de sair criando domínios deliberadamente, façaum estudo minucioso do banco de dados a ser construído.

Page 14: Full Delphi

Trocar o tipo de um campo

Para alterar o tipo de um campo no FireBird (ou InterBase 6.0 ou superior) execute o comando SQL abaixo:

ALTER TABLE NomeDaTabela ALTER NomeDoCampo TYPE NovoTipo

Exemplos:

ALTER TABLE Cliente ALTER Nome TYPE VARCHAR(40);ALTER TABLE Venda ALTER Total TYPE NUMERIC(18, 2);

Obs:

Em geral este comando não funciona se a troca de tipo implicar em perda de dados.

Sugestão:

Onde aparece NovoTipo você poderá usar um nome de domínio.

Alterar o tamanho de um campo

Para alterar o tamanho de um campo CHAR ou VARCHAR no FireBird (ou InterBase 6.0 ou superior)basta executar o comando SQL abaixo:

ALTER TABLE NomeDaTabela ALTER NomeDoCampo TYPE NovoTipo;

Exemplo:

ALTER TABLE Cliente ALTER Nome TYPE VARCHAR(50);

Obs:

Este comando não funciona se a alteração de tamanho implicar em perda de dados, ou seja, não serve parareduzir o tamanho de um campo.

Transação multi-banco com IBX

Embora seja um recurso pouco conhecido, o InterBase/FireBird suporta uma única transação vinculada adois ou mais bancos e os componentes InterBase Express (IBX) suportam este recurso de formatransparente. Para usar este recurso com IBX siga os passos abaixo:

Coloque um IBDatabase para cada banco de dados.Coloque apenas um IBTransaction.Conecte cada IBDatabase ao IBTransaction pela propriedade DefaultTransaction.Coloque quantos IBSQL ou IBDataSet forem necessários.Conecte cada IBSQL ou IBDataSet ao respectivo IBDatabase pela propriedade Database.Conecte cada IBSQL ou IBDataSet ao mesmo IBTransaction pela propriedade Transaction.Pronto, agora é só trabalhar normalmente.

Importante

Deixe a propriedade DefaultDatabase do IBTransaction sem preencher.

Page 15: Full Delphi

Sugestão

Use esta técnica sempre que precisar transferir dados de um banco de dados para outro.

Excluir código-fonte de stored procedure

Uma grande preocupação que tem tomado conta da cabeça de muitos programadores é a possibilidade de umprogramador concorrente pegar o código-fonte das stored procedures armazenadas em banco de dadosInterBase/FireBird. Uma solução encontrada é apagar o código-fonte diretamente da tabela de sistema onde oInterBase grava as informações relativas às stored procedures. Para fazer isto execute o comando abaixo:

UPDATE RDB$PROCEDURES SET RDB$PROCEDURE_SOURCE = 'empty'

Observações

A mesma coisa pode ser feita com triggers. No entanto é importante lembrar que você não deve atribuirNULL, pois havia um bug no InterBase que fazia o trigger ser disparado duas vezes caso o código-fonteestivesse NULL. Não sei se o bug foi corrigido. De qualquer forma, atribua uma string qualquer, tal como noexemplo acima.

Obter os campos da chave-primária

Execute o comando SELECT abaixo para obter os nomes dos campos da chave-primaria de uma tabela do InterBase ouFireBird.

SELECT RDB$FIELD_NAMEFROM RDB$RELATION_CONSTRAINTS C, RDB$INDEX_SEGMENTS SWHERE C.RDB$RELATION_NAME = 'NomeDaTabela' AND C.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' AND S.RDB$INDEX_NAME = C.RDB$INDEX_NAMEORDER BY RDB$FIELD_POSITION

Observações

Estes objetos com nomes iniciados com RDB$ são chamados de objetos de sistema e são usados internamentepelo InterBase/FireBird. As tabelas começadas com RDB$ contém dados sobre a estrutura do banco dedados.

Para mudar a propriedade "Forced Writes" de um banco de dados InterBase usando o gfix faça:

Para ativar:gfix banco -write sync -user sysdba -password senha

Para desativar:gfix banco -write async -user sysdba -password senha

Definir forced writes usando o gfix

Page 16: Full Delphi

Onde:

banco = Caminho completo do banco de dados (arquivo .gdb).senha = senha do sysdba.

Observações

Você também poderá usar o IBConsole para alterar esta propriedade.

Definir sweep interval com gfix

Para definir o "sweep interval" de um banco de dados InterBase usando o gfix, execute:

gfix banco -housekeeping n -user sysdba -password senha

Onde:

banco = Caminho completo do banco de dados (arquivo .gdb).n = Intervalo de sweep.senha = senha do sysdba.

Observações

Você também poderá alterar esta propriedade do banco de dados usando o IBConsole.

Obter a data do servidor

Isto é facilmente possível se você usa um banco de dados Client/Server, tal como Interbase, SQL Server, Oracle, etc. No Interbase6 execute a Query abaixo:

SELECT CURRENT_DATE FROM RDB$DATABASE;

O resultado é a data do servidor onde está rodando o Interbase Server.

Instalar ZeosDBO 6.6.4 en Delphi 2007

Nos dirigimos a la carpeta Packages y abrimos el fichero ZeosDbo.groupproj de la

carpeta delphi11. Ahora seleccionamos la librería ZCore110.bpl, y con el botón derecho

del mouse, hacemos build all from here. Esto nos creará los ficheros .dcu en la carpeta

build dentro de la carpeta delphi11.

Ahora, añadimos las carpetas en la configuración del proyecto. Nos dirigimos a Tools -

> Options, Dentro de Library path, introducimos la ruta del build, donde están todos los

.dcu, y en Browsing path, añadimos la ruta de todas las fuentes.Ahora, seleccionamos el package ZComponentDesign110.bpl y con el botón derecho

"Install".

Page 17: Full Delphi

Instalacion de RxLib 2.7.7

Tools > Options…Environment Options > Delphi Options > Library – Win32;

Library path, clic en el botón con los 3 puntos…Pon la ruta de las units (ejemplo C:\delphi\rxlib-2.7.7\packages\delphi2007) y clic en Add;Digiten al final $(BDS)\ rxlib-2.7.7 y luego clic en Add;

Ahora abra el archivo Rxlib.groupprojProject > Compile all projects;

View > Project Manager, haz clic con el botón izquierdo y elije Install, en los 3 archivos: dclrxbd100.bpldclrx100.bpl

dclrxdb100.bpl

Instalacion QuickReport Professional 4.07

Tools > Options…

Environment Options > Delphi Options > Library – Win32;Library path, clic en el botón con los 3 puntos…

Digiten al final $(BDS)\QuickRep y luego clic en Add;Component > Install Packages…Clic en el botón Add…

Seleccione QR4DesignD2007.bpl y listo.

No ingresar 2 proposiciones

CaracteresValidos = [#1..#31, #8, 'p', 'q', 'r', 's', '<', '>', '(', ')', '^', '-'];

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);begin if not (Key In CaracteresValidos) then

begin Key := #0;

Beep; end else

if (key = anterior) then begin

Key := #0; Beep; application.MESSAGEBOX('Imposible ingresar dos proposiciones consecutivas', '¡Error!')

end else

if anterior in CaracteresValidos then begin Key := #0;

Beep; application.MESSAGEBOX('Imposible ingresar dos proposiciones consecutivas', '¡Error!')

end else anterior := Key;

end;

Page 18: Full Delphi

En el evento OnExit del control Edit1 pon el código de validación y si no se cumple lleva el foco al

control. Funciona muy bien.

if Edit1.text=´´ then

begin

ShowMessage(´Ingrese texto´);

edit1.setfocus;

end;

Para validar un Edit tienes que hacer la validación en el campo del TTable, para esto primero hace doble clic sobre el ttable y te aparecerá la lista de campos, selecciona el que vas a validar y anda al object inspector a la pestaña events y da doble clic en onValidate, allí podrás escribir la validación

para dicho campo abortando con "Abort" en el caso que no sea correcto el tipo de dato.

procedure TFrmCliente.Tbl1CuitValidate(Sender: TField);

begin

if Tbl1Cuit.value=´´ then

Abort;

end;

Para validar un DBEdit

En el evento OnSetText del TField asociado a ese DBEdit pon:

try

Sender.AsDateTime := Text; except on E:Exception do

ErrorDialog('Error en fecha: '+E.Message, E.HelpContext); end;

Validar ingreso de solo números

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);

begin if not (Key in ['0'..'9']) then

begin Beep; MessageDlg('¡Debe ingresar solo números!', mtInformation,[mbOK],0);

end;end;

Como validar el precio en un DBtext (Double)

try

StrToFloat(Text); //probamos a convertir Sender.AsString := Text; // si no hay fallos al convertir, asignamos el nuevo valor

except ShowMessage('mi fallo'); sysutils.Abort; // excepción silenciosa.

end;

Page 19: Full Delphi

Como capturar un error de base de datos

if

(pass.Text='') or

(pass2.Text='') or

(nom.Text='') or

(userr.Text='') then

begin

guardar.enabled:=false;

application.messagebox('Hay

campos vacios','Validacion',mb_ok+mb_iconerror);

end

else

begin

try

tuser.Post;

tuser.First;

pass2.Text:='';

except

on

E:Exception do

begin

application.messagebox('Usuario existente','Validacion',mb_ok+mb_iconerror);

cancelarClick(Sender);

end;

end;

end;

Capturar errores al hacer un Post validar registros

Cuando usamos

controles DataAware tales como DBNavigator o DBGrid, y se pueden añadir

registros, es posible que el usuario introduzca dos registros con el mismo campo clave, generándose por tanto una excepción. ¿Como podemos capturar dicha excepción?, dado que el Post lo hace el

correspondiente control de base de datos (DBGrid, etc.) Pues muy fácil, los errores generados a la hora de hacer el Post en una tabla, son centralizados en el evento OnPostError del propio TTable... sólo tendremos que usarlo.

Por ejemplo, metiendo un código similar a éste:

procedure TForm1.Table1PostError(DataSet: TDataSet; E: EDatabaseError;

var Action: TDataAction);

begin

{Error in the Post}

ShowMessage('Error al dar de alta un nuevo registro'+#13+'Motivo:'+E.Message);

Action:=daAbort;

end;

Con el parámetro Action, podemos especificar que es lo que hay que hacer con el Post que generó el error. En el ejemplo, utilizamos daAbort para abortar dicho Post.

Page 20: Full Delphi

Capturar errores de edición -

edit -

y validación -

post -

de una tabla y mostrar un mensaje personalizado

Ejemplo que muestra cómo capturar errores de Base de Datos Paradox en Delphi, utilizando los eventos "EditError" y "PostError" del componente TTable:

En el evento "EditError" del TTable de nuestro módulo de datos digitamos

el siguiente código:

Procedure

TDatos.TDistribuidorEditError(DataSet: TDataSet;

E: EDatabaseError; var Action: TDataAction);

Begin

if e is EDBEngineError then

Begin

Case

EDBEngineError(E).Errors[0].ErrorCode of

10241:

begin

messagedlg ('El registro actual está siendo modificado por el usuario: ' +

UpperCase(copy(e.Message, pos('User:', E.Message) + 6, length(e.Message))) + chr(13) +

chr(13) + ' Espere a que éste termine para modificarlo.', mterror, [mbok], 0);

end;

8708:

begin

messagedlg ('El registro actual ha sido ELIMINADO por otro usuario.' +

‘Pulse

refrescar para actualizar los cambios.', mterror, [mbok], 0);

end;

9727:

begin

messagedlg ('Ya existe un producto con este nombre.' +

‘Cambie

el nombre o cancele las modificaciones.', mterror, [mbok], 0);

end;

else

messagedlg ('Se ha producido un error al intentar editar el registro.', mterror, [mbok], 0));

End;

Action: =

daAbort;

End;

End;

En el evento "PostError" del TTable colocaremos el siguiente código:

Procedure

TDatos.TDistribuidorPostError(DataSet: TDataSet;

E: EDatabaseError; var Action: TDataAction);

Begin

If

e is EDBEngineError then

Begin

Case

EDBEngineError(E).Errors[0].ErrorCode of

9729:

begin

fp.mserror ('Registro existe.' + ' Cancele las modificaciones.', 'Valor duplicado.');

end;

else

fp.mserror ('Error al intentar guardar los datos del registro actual.', 'Error al validar...');

end; Action := daAbort; end;

end;

Page 21: Full Delphi

Funciones y procedimientos para fecha y hora

Si hay algo de lo que no podemos escapar los programadores de gestión es el tener que lidiar con

campos de fecha y hora tales como cálculo de d ías entre fechas, averiguar en que fecha caen los días festivos, cronometrar el tiempo que tardan nuestras rutinas, etc.

Para la mayoría de funciones

tenemos que añadir la unidad DateUtils :

uses

Windows, Messages, ..., DateUtils;

Veamos entonces que funciones nos pueden ser útiles para ello:

function DayOfTheMonth( const AValue: TDateTime ): Word;

Esta función extrae el número de día de una fecha en concreto sin tener que utilizar la función

DecodeDate.

var Fecha: TDate;

begin

Fecha := StrToDate( '23/08/2007' );

ShowMessage( IntToStr( DayOfTheMonth( Fecha ) ); // muestra 23

end;

function DayOfTheWeek( const AValue: TDateTime ): Word;

Nos díce en que día de la semana (1-7) cae una fecha en concreto (el primer día es el Lunes, al contrario de otras funciones de fecha y hora donde el primer día es el Domingo).

Fecha := StrToDate( '5/08/2007' );

ShowMessage( IntToStr( DayOfTheWeek( Fecha ) ) ); // devuelve 7 (Domingo)

Fecha := StrToDate( '10/08/2007' );

ShowMessage( IntToStr( DayOfTheWeek( Fecha ) ) ); // devuelve 5 (Viernes)

Fecha := StrToDate( '23/08/2007' );

ShowMessage( IntToStr( DayOfTheWeek( Fecha ) ) ); // devuelve 4 (Jueves)

function DayOfWeek( Date: TDateTime ): Integer;

Esta función es igual a la función DayOfTheWeek

con la diferencia de que el primer día de la

semena es el domingo.

Fecha := StrToDate( '5/08/2007' );

ShowMessage( IntToStr( DayOfWeek( Fecha ) ) ); // devuelve 1 (Domingo)

Fecha := StrToDate( '10/08/2007' );

ShowMessage( IntToStr( DayOfWeek( Fecha ) ) ); // devuelve 6 (Viernes)

Fecha := StrToDate( '23/08/2007' );ShowMessage( IntToStr( DayOfWeek( Fecha ) ) ); // devuelve 5 (Jueves)

Page 22: Full Delphi

function DayOfTheYear( const AValue: TDateTime ): Word;

Al pasarle una fecha nos devuelve el número de día que corresponde a lo largo del año.

Fecha := StrToDate( '5/08/2007' );

ShowMessage( IntToStr( DayOfTheYear( Fecha ) ) ); // devuelve 217

Fecha := StrToDate( '10/08/2007' );

ShowMessage( IntToStr( DayOfTheYear( Fecha ) ) ); // devuelve 222

Fecha := StrToDate( '23/08/2007' );

ShowMessage( IntToStr( DayOfTheYear( Fecha ) ) ); // devuelve 235

function DaysBetween( const ANow, AThen: TDateTime ): Integer;

Devuelve el número de días que hay entre las fechas ANow

y AThen.

var

Fecha1, Fecha2: TDate;

begin

Fecha1 := StrToDate( '10/08/2007' );

Fecha2 := StrToDate( '23/08/2007' );

ShowMessage( IntToStr( DaysBetween( Fecha1, Fecha2 ) ) ) ; // devuelve 13

end;

function DaysInMonth( const AValue: TDateTime ): Word;

Nos dice cuantos días tiene el mes que le pasamos como fecha.

DaysInMonth( StrToDate( '01/01/2007' ) ) devuelve 31

DaysInMonth( StrToDate( '01/02/2007' ) ) devuelve 28

DaysInMonth( StrToDate( '01/04/2007' ) ) devuelve 30

function DaysInYear( const AValue: TDateTime ): Word;

Nos dice el número de días que tiene un año según

la fecha que le pasamos.

DaysInYear( StrToDate( '01/01/2007' ) ) devuelve 365

function DaySpan( const ANow, AThen: TDateTime): Double;

Devuelve el número de días de diferencia entre dos fechas y horas incluyendo la parte fraccional.

var

FechaHora1, FechaHora2: TDateTime;

begin

FechaHora1 := StrToDateTime( '10/08/2007 13:00' );

FechaHora2 := StrToDateTime( '23/08/2007 19:00' );

Page 23: Full Delphi

ShowMessage( FloatToStr( DaySpan( FechaHora1, FechaHora2 ) ) ); // devuelve 13,25 end;

procedure DecodeDate( Date: TDateTime; var Year, Month, Day: Word );

Este procedimiento convierte un valor de fecha TDate en valores enteros para el año, mes y día. var

wAnyo, wMes, wDia: Word; begin

DecodeDate( StrToDate( '23/08/2007' ), wAnyo, wMes, wDia ); Memo.Lines.Add( 'Día: ' + IntToStr( wDia ) ); Memo.Lines.Add( 'Mes: ' + IntToStr( wMes ) );

Memo.Lines.Add( 'Año: ' + IntToStr( wAnyo ) ); end;

procedure DecodeTime( Time: TDateTime; var Hour, Min, Sec, MSec: Word );

Este procedimiento convierte un valor de hora TTime en valores enteros para la hora, minutos, segundos y milisegundos.

var wHora, wMinutos, wSegundos, wMilisegundos: Word;

begin DecodeTime( StrToTime( '14:25:37' ), wHora, wMinutos, wSegundos, wMilisegundos ); Memo.Lines.Add( IntToStr( wHora ) + ' horas' );

Memo.Lines.Add( IntToStr( wMinutos ) + ' minutos' ); Memo.Lines.Add( IntToStr( wSegundos ) + ' segundos' );

Memo.Lines.Add( IntToStr( wMilisegundos ) + ' milisegundos' ); end;

procedure DecodeDateTime( const AValue: TDateTime; out AYear, AMonth, ADay, AHour,

AMinute, ASecond, AMilliSecond: Word );

Este procedimiento decodifica un valor TDateTime en valores enteros para el año, mes, día, hora, minutos, segundos y milisegundos.:

var

wAnyo, wMes, wDia: Word; wHora, wMinutos, wSegundos, wMilisegundos: Word; begin

DecodeDateTime( StrToDateTime( '24/08/2007 12:34:53' ), wAnyo, wMes, wDia, wHora, wMinutos, wSegundos, wMilisegundos );

Memo.Lines.Add( 'Día: ' + IntToStr( wDia ) ); Memo.Lines.Add( 'Mes: ' + IntToStr( wMes ) ); Memo.Lines.Add( 'Año: ' + IntToStr( wAnyo ) );

Memo.Lines.Add( IntToStr( wHora ) + ' horas' ); Memo.Lines.Add( IntToStr( wMinutos ) + ' minutos' );

Memo.Lines.Add( IntToStr( wSegundos ) + ' segundos' );

Page 24: Full Delphi

Memo.Lines.Add( IntToStr( wMilisegundos ) + ' milisegundos' ); end;

function EncodeDate( Year, Month, Day: Word ): TDateTime;

Convierte los valores enteros de año, mes y día a un valor TDateTime o TDate. EncodeDate( 2007, 8, 24 ) devuelve 24/08/2007

function EncodeTime( Hour, Min, Sec, MSec: Word ): TDateTime;

Convierte los valores enteros de hora, minutos, segundos y milisegundos en un valor TDateTime o TTime.

EncodeTime( 12, 34, 47, 0 ) devuelve 12:34:47

function EncodeDateTime( const AYear, AMonth, ADay, AHour, AMinute, ASecond,

AMilliSecond: Word ):TDateTime;

Convierte los valores enteros de año, mes, día, hora, minutos, segundos y milisegundos en un valor

TDateTime. EncodeDateTime( 2007, 8, 24, 12, 34, 47, 0 ) devuelve 24/08/2007 12:34:47

function EndOfADay( const AYear, ADayOfYear: Word ): TDateTime; overload;

function EndOfADay( const AYear, AMonth, ADay: Word ): TDateTime; overload;

Devuelve un valor TDateTime que representa la última fecha y hora de un día en concreto.

EndOfADay( 2007, 8, 13 ) devuelve 13/08/2007 23:59:59 EndOfADay( 2007, 1, 1 ) devuelve 01/01/2007 23:59:59

EndOfADay( 2007, 2, 1 ) devuelve 01/02/2007 23:59:59 EndOfADay( 2007, 8, 23 ) devuelve 08/23/2007 23:59:59

EndOfADay( 2007, 1 ) devuelve 01/01/2007 23:59:59 EndOfADay( 2007, 32 ) devuelve 01/02/2007 23:59:59

NOTA IMPORTANTE: La función con tres parámetros es erronea en la versión de Delphi 7

Build 4.453. Da los siguientes valores:

EndOfADay( 2007, 8, 13 ) devuelve 12/09/2007 23:59:59 (mal) EndOfADay( 2007, 1, 1 ) devuelve 31/01/2007 23:59:59 (mal)

EndOfADay( 2007, 2, 1 ) devuelve 28/02/2007 23:59:59 (mal) EndOfADay( 2007, 8, 23 ) devuelve 12/09/2007 23:59:59 (mal)

EndOfADay( 2007, 1 ) devuelve 01/01/2007 23:59:59 (bien) EndOfADay( 2007, 32 ) devuelve 01/02/2007 23:59:59 (bien)

Con lo cual es recomendable actualizarse a una versión superior (yo me he actualizado a la versión Delphi 7.0 Build 8.1 y sigue sin hacerme ni puto caso).

Page 25: Full Delphi

function EndOfAMonth( const AYear, AMonth: Word ): TDateTime; Devuelve un valor TDateTime que representa la última fecha y hora de un mes.

EndOfAMonth( 2007, 1 ) devuelve 31/01/2007 23:59:59

EndOfAMonth( 2007, 2 ) devuelve 28/02/2007 23:59:59 EndOfAMonth( 2007, 8 ) devuelve 31/08/2007 23:59:59

function EndOfAWeek( const AYear, AWeekOfYear: Word; const ADayOfWeek: Word = 7

): TDateTime;

Devuelve un valor TDateTime que representa la última fecha y hora de una semana. El parámetro AWeekOfYear representa el número de semana a lo largo del año.

EndOfAWeek( 2007, 1 ) devuelve 07/01/2007 23:59:59

EndOfAWeek( 2007, 2 ) devuelve 14/01/2007 23:59:59 EndOfAWeek( 2007, 3 ) devuelve 21/01/2007 23:59:59

function EndOfAYear( const AYear ): TDateTime;

Devuelve un valor TDateTime que representa la última fecha y hora del año que le pasemos. EndOfAYear( 2007 ) devuelve 31/12/2007 23:59:59

EndOfAYear( 2008 ) devuelve 31/12/2008 23:59:59 EndOfAYear( 2009 ) devuelve 31/12/2009 23:59:59

function IncDay( const AValue: TDateTime; const ANumberOfDays: Integer = 1 ):

TDateTime;

Devuelve el valor fecha y hora AValue incrementando el número de días especificado en ANumberOfDays (por defecto 1).

IncDay( StrToDate( '24/08/2007' ) ) devuelve 25/08/2007

IncDay( StrToDate( '24/08/2007' ), 10 ) devuelve 03/09/2007 function IncMonth( const Date: TDateTime; NumberOfMonths: Integer = 1 ): TDateTime;

Devuelve el valor fecha y hora AValue incrementando el número de meses especificado en

NumberOfMonths (por defecto 1). IncMonth( StrToDate( '24/08/2007' ) ) devuelve 24/09/2007

IncMonth( StrToDate( '24/08/2007' ), 3 ) devuelve 24/11/2007

procedure IncAMonth( var Year, Month, Day: Word; NumberOfMonths: Integer = 1 ); Este procedimiento es similar a la función IncMonth pero en vez de pasarle la fecha en formato

TDateTime se le pasa en formato año, mes y día.

var wAnyo, wMes, wDia: Word;

Page 26: Full Delphi

begin wDia := 24; wMes := 8;

wAnyo := 2007; IncAMonth( wAnyo, wMes, wDia );

Memo.Lines.Add( 'Día: ' + IntToStr( wDia ) ); Memo.Lines.Add( 'Mes: ' + IntToStr( wMes ) ); Memo.Lines.Add( 'Año: ' + IntToStr( wAnyo ) );

end;

function IncWeek( const AValue: TDateTime; const ANumberOfWeeks: Integer = 1 ):

TDateTime;

Devuelve el valor fecha y hora AValue incrementando el número de semanas especificado en ANumberOfWeeks (por defecto 1).

IncWeek( StrToDate( '24/08/2007' ) ) devuelve 31/08/2007 IncWeek( StrToDate( '24/08/2007' ), 2 ) devuelve 07/09/2007

function IncYear( const AValue: TDateTime; const ANumberOfYears: Integer = 1 ):

TDateTime; Devuelve el valor fecha y hora AValue incrementando el número de años especificado en

ANumberOfYears (por defecto 1). IncYear( StrToDate( '24/08/2007' ) ) devuelve 24/08/2008

IncYear( StrToDate( '24/08/2007' ), 2 ) devuelve 24/08/2009

Page 27: Full Delphi

Filtro DBEdit y DBGrid Es un DBEdit que filtra un DBGrid y que este a la vez filtra otro, me explico, DBGrid1 OT, DBGrid2 Productos, DBEdit1 muestra el Numero de OT Del DBGrid1 y Filtra los Productos en el DBGrid2, el problema es cuando no hay OT's pendientes en productos me muestra todos los que hay en la base de datos y necesito quede en blanco cuando no hay con que filtrar el DBGrid2. Suponiendo Table1 y TWOT abiertas y DBEdit1 con su DataSource apuntando al campo de la tabla1, Pon esto en el OnChange del DBEdit (* aplicar filtro sobre tabla TWOT *) procedure TForm1.DBEdit1Change(Sender: TObject); begin TWOT.Filtered:= False; TWOT.Filter:='OT ='+ QuotedStr(DBEdit1.Text); TWOT.Filtered:= True; end;

Búsqueda Incremental Estoy haciendo una aplicación y quiero que tenga Edit que sirva para buscar y filtrar solamente el registro deseado. procedure TFormPrincipal.Edit1Change(Sender: TObject); begin ClienDataSet1.Encomiendas_vista2.Filtered := False; ClienDataSet1.Encomiendas_vista2.Filter := 'UPPER(Nombre) Like ' + QuotedStr(UpperCase(Edit1.Text)+'%'); ClienDataSet1.Encomiendas_vista2.Filtered:= True; end;

Búsqueda Incremental con Query procedure TForm1.Edit1Change(Sender: TObject); begin with Query1 do begin Close; SQL.Text:= 'SELECT * FROM ZTABLE3'+ ' WHERE CODIGO >= ' + QuotedStr(ComboBox1.Text)+ ' AND CODIGO <= ' + QuotedStr(Edit1.Text); Open; end end;

Page 28: Full Delphi

Búsqueda incremental con ComboBox procedure TProductos.Edit1Change(Sender: TObject); Var Valor, Valor1: String; begin if Edit1.text = '' then begin BDatos.ZTable3.Filtered := false; exit; end; BDatos.ZTable3.Locate(ComboBox1.Text, Edit1.Text,[loPartialKey,loCaseInsensitive]); valor := Edit1.Text; Valor1 := Valor; inc(valor1[length(Valor1)]); BDatos.ZTable3.Filter := ''+ComboBox1.Text+' >= '+QuotedStr(Valor)+ ' and '+ComboBox1.Text+' < ' +QuotedStr(valor1); BDatos.ZTable3.Filtered := true; end; end.

También en el OnChange del ComboBox incluí esto: procedure TProductos.ComboBox1Change(Sender: TObject); begin Edit1.Clear; end;

Con esto nos aseguramos hacer una búsqueda en blanco por cada criterio elegido. Consulta 1 Edit a 2 Columnas de una Tabla Tengo una Tabla que entre varias columnas existen "Nombre" y "Apellido Paterno", hasta ahora tengo la consulta para buscar o por nombre o por apellido y funciona perfecto, la duda: existe la forma de poder "Filtrar" las 2 columnas según el criterio de 1 "Edit"???, en este caso algo así: Nombre - Apellido Juan - Tapia María - Mora José - Salas La idea es que al escribir "1" queden en este caso filtrados la fila 1 y 2, ya que 1 tiene "1" en el apellido y 2 en el nombre.

Page 29: Full Delphi

procedure TClientes.Edit2Change(Sender: TObject); const // suponiendo que esta sea tu consulta STRSQL = 'Select * from CONTACTOCLIENTE '; STRORDER = ' ORDER BY NOMBRES'; begin BDatos.QContactoCliente.Close; // Está vacío if (Edit2.Text = '') then begin BDatos.QContactoCliente.SQL.Text := STRSQL; end else begin // montamos la sql BDatos.QContactoCliente.SQL.Text := STRSQL + // Añadimos el WHER ' WHERE Upper(NOMBRES) LIKE Upper(' + QuotedStr('%' + Edit2.Text + '%') + ')' + 'or Upper(APELLIDO) LIKE Upper(' + QuotedStr('%' + Edit2.Text + '%') + ')' + STRORDER; end; BDatos.QContactoCliente.Open; end;

Buscar Registros en Firebird Tengo una base de datos en Firebird e IbExpert llamada bdusuarios y tengo una tabla llamada usuarios con tres atributos clave, nombre, domicilio; también tengo un Form con sus respectivos Edit. Quisiera saber cómo es el código para que me busque un registro dando la clave en un Edit y pulsando un botón para que me muestre el nombre y el domicilio del usuario en los demás Edit. procedure TForm1.Button1Click(Sender: TObject); begin Query1.sql.text:= 'Select Clave,nombre,domicilio from Usuarios where Clave = :Cla'; Query1.Parameters[0].Value := Edit1.Text; Query1.Open; if not Query1.IsEmpty then begin Edit2.text:= Query1.filebyname('nombre').AsString; Edit3.text:= Query1.filebyname('domicilio').AsString end else begin MessageDlg('Clave Inválida',mtError, [mbOK], 0); Edit1.Text := ''; Edit1.SetFocus end; Query1.Active := False; end;

Page 30: Full Delphi

Cómo verificamos si una tabla o un Query tiene registros if ibquery1.IsEmpty then //pregunta si el Query está vacío begin Application.MessageBox( ‘No existe listado para la nómina ingresada’, ‘Lista vacía’); end; Utilizando el IBQuery para traer datos de más de una tabla Crear la conexión con la base de datos utilizando los componentes IBDatabase e IBTransaction. Agregar un IBQuery al formulario y relacionar con el IBDatabase. Modificar las siguientes propiedades del IBQuery: Database: colocar el nombre del componente IBDatabase. SQL: debemos crear la consulta SQL. Este es un ejemplo si usamos las tablas de la figura anterior: SELECT trabajadores.trabajador, trabajadores.apellido, trabajadores.nombre, nominas.horas_normales, nominas.horas_extras, nominas.mes, nominas.ano FROM nominas, trabajadores WHERE nominas.trabajador=trabajadores.trabajador

Y para terminar agregamos un DataSource y relacionar el DataSource con el IBQuery. Editando los valores del IBQuery en tiempo de ejecución para realizar búsquedas filtradas. Crear la conexión con la base de datos utilizando los componentes IBDatabase e IBTransaction. Agregar un IBQuery al formulario y relacionar con el IBDatabase. Modificar las siguientes propiedades del IBQuery. Ver punto anterior “Utilizando el IBQuery para traer datos de más de una tabla“. Agregar un DBGrid, un Edit y un botón al formulario. Relacionar el DBGrid con el DataSource del IBQuery. Y en el botón, en el evento clic, hacemos lo siguiente (por código). Desactivamos el IBQuery para poder cambiar los datos: IBQuery1.active:=false; Cambiamos el texto de la propiedad SQL del IBQuery: ibquery1.SQL.Text:=’SELECT trabajadores.trabajador, trabajadores.apellido, trabajadores.nombre, nominas.horas_normales, nominas.horas_extras, nominas.mes, nominas.ano FROM nóminas, trabajadores WHERE nominas.trabajador=trabajadores.trabajador and nominas.nomina=’+edit1.Text; Activamos el IBQuery.

Page 31: Full Delphi

Seleccionar varios registros de una tabla por un campo Queremos mostrar todos los registros de una tabla cuyo campo N.I.F. sea el mismo. Query1.Close; Query1.Sql.Clear; Query1.Sql.Add('Select * From MiTabla '); Query1.Sql.Add('Where NIF = '+QuotedStr(Edit1.Text));//En Edit1 se supone está el Nif. Query1.Open;

Con un Filtro MiTabla.Filter:='NIF ='+QuotedStr(Edit1.Text); MiTabla.Filtered:=True;

Realizar búsqueda en Firebird Tengo una tabla en Firebird 2.5, y quiero realizar dos tipos de búsqueda: El primero por el código (campo clave) y el segundo es por nombre de producto. Un ejemplo con TIBDataSet: procedure TForm1.Edit1Change(Sender: TObject); begin IBDataSet1.Close; IBDataSet1.SelectSQL.Text:= 'SELECT * FROM PRODUCTOS WHERE NOMBRE LIKE :BUSCADO'; IBDataSet1.ParamByName('BUSCADO').AsString:= Edit1.Text+'%'; IBDataSet1.Open; end;

Toma en cuenta que en este caso la cadena SQL que originalmente le asignaste a la propiedad SelectSQL es reemplazada por cada nueva asignación. Datos del PC: Nombre, IP y usuario Siempre es muy útil poder disponer de los datos relativos a la red del equipo en el que estamos ejecutando nuestra aplicación. He englobado los principales datos en una única función para simplificar el proceso y así obtener: - Nombre del PC - Dirección IP local - Nombre del usuario de Windows. Recordad añadir al uses lo siguiente: WinInet, WinSock;

Page 32: Full Delphi

Para simplificar los parámetros he creado un tipo de datos que debéis poner después del uses type TDatosPC = record Nombre, IP, Usuario :String; end;

Y esta es la función que nos devuelve los tres datos procedure ObtenerDatosPC (var Datos:TDatosPC ); const LARGO_MAXIMO = 50; var buffer:Array [0..LARGO_MAXIMO+1] of char; Largo:Cardinal; PuntHost: PHostEnt; PuntIP: PAnsichar; wVersionRequested: WORD; wsaData: TWSAData; begin Largo := LARGO_MAXIMO +1; Datos.Nombre := ''; If GetComputerName (buffer, Largo) then Datos.Nombre := buffer; Datos.Usuario := ''; if GetUserName(buffer, largo) then Datos.Usuario := buffer; wVersionRequested := MAKEWORD( 1, 1 ); WSAStartup( wVersionRequested, wsaData ); GetHostName( @buffer, LARGO_MAXIMO ); PuntHost := GetHostByName( @buffer ); PuntIP := iNet_ntoa( PInAddr( PuntHost^.h_addr_list^ )^ ); Datos.IP := PuntIP ; WSACleanup; end;

Meter los valores de una columna en un ComboBox Tengo unas tablas que estoy utilizando, todo va muy bien, hasta que necesito meter los valores de una columna en un ComboBox, por ejemplo digamos que tengo 2 columnas en una tabla, la columna 1 se llama idusuario y la columna 2 se llama promedio, por ejemplo digamos que este es el contenido de mi tabla:

idpaciente promedio

1 3.2

1 4.4

2 5.2

3 1.5

2 3.5

1 2.9

Page 33: Full Delphi

Y lo que yo necesito es que en el ComboBox aparezca por ejemplo en cada renglón los resultados que en este caso serían el 3.2, 4.4 y 2.9, el problema es que solo me aparece el primer resultado que es el 3.2. Añádele un while, ejemplo: query.Close; query.SQL.Clear; query.SQL.Add('select * from citas where idpaciente=1'); query.Open; while not query.eof do begin combobox2.Items.Add(query.FieldValues['promedio']); query.next; end;

Pasar de una tabla1 a una tabla2 la misma información Tengo una tabla1 que tiene campos campo1, campo2 Tengo otra tabla que tienen campos campo1, campo2, campo3 Como se hace para pasar toda la información de la tabla 1 a la tabla2. procedure TForm1.Button1Click(Sender: TObject); begin with TuDataset do begin SQL.Clear; SQL.Add('insert into tabla2(campo1, campo2)'); SQL.Add('select campo1, campo2 from tabla1'); ExecSQL; end; //Fin with end;

Llenar un ComboBox con los campos de una tabla Quiero llenar un ComboBox con los campos de una tabla no los datos sino los campos, me explico: tabla clientes: NOMCLI, DIRCLI, TELCLI, CC. En el ComboBox: Nombre->valor(NOMCLI) Dirección->valor(DIRCLI) Eso es para fines de búsqueda de datos como un filtro algo así. var q:Tquery; i:integer; begin q := Tquery.create(nil); q.databasename := 'c:\......';

Page 34: Full Delphi

q.sql.text := select * from tabla; q.FieldsDef.Update; with q do for i:=0 to FieldsDef.Count-1 do combo.items.Add(Fieldsdef[i].FieldName); freeandnil(q); end;

Cómo obligo el ingreso de datos a todos los DBEdit de un formulario procedure TForm1.Button1Click(Sender: TObject); var i: integer; errors: string; const MSG_SEPARATOR = #13#13; EMPTY_EDIT_MSG = '%s edit is empty'; begin errors := ''; for i := 0 to EditsPanel.ControlCount - 1 do begin if (EditsPanel.Controls[i] is TEdit) then begin if (Trim(TEdit(EditsPanel.Controls[i]).Text) = EmptyStr) then begin if (errors = EmptyStr) then begin errors := Format(EMPTY_EDIT_MSG, [TEdit(EditsPanel.Controls[i]).Name]); end else begin errors := errors + MSG_SEPARATOR + Format( EMPTY_EDIT_MSG, [TEdit(EditsPanel.Controls[i]).Name]); end; end; end; end; if (errors <> EmptyStr) then begin ShowMessage(errors); end else begin ShowMessage('All edits contain values'); end; end;

Copiar datos de una tabla a una Edit Debes tomar el valor de tu DataSet (que puede ser un Table, Query...) que se enlaza a tu DBGrid. procedure TForm1.DBGrid1DblClick(Sender: TObject); begin FormB.Edit1.Text := DataSet.FieldByName('ID_Cliente').AsString;

Page 35: Full Delphi

FormB.Edit2.Text := DataSet.FieldByName('NombCliente').AsString; FormSig.ShowModal; end;

Asignarle el Valor de un DBEdit a un DBGrid El DBEdit me captura un valor ejemplo el 4500, quiero que ese valor se coloque automáticamente en uno de mis campos del DBGrid el cual se llama Valor. Usa el dataset asociado al dbgrid: Table1.FieldByName('Valor').AsString := Edit1.Text;

Realmente como era un DBEdit le hice esta instrucción: IBDataSet.FieldByName('Valor').AsString:=DBEdit.Field.AsString

Buscar en un campo de una tabla por Caracteres Que tengo que hacer para buscar por caracteres en un campo alfanumérico de una tabla. Por ejemplo tengo campo que se llama nombre y quiero que al ingresar una letra me devuelva todos los nombres que empiezan con esa letra. En el evento OnChange de tu Edit, haces una consulta o un filtro sobre tu DataSet. Query.Close; Query.Sql.Text := 'Select * From Tabla Where nombre like '+QuotedStr(Edit1.Text+'%'); Query.Open;

O si es una Table Table.Filtered := False; Table.Filter := 'nombre like '+QuotedStr(Edit1.Text+'%'); Table.Filtered := True;

Buscar registros semejantes Tengo una pequeña base de datos, con los campos, NOMBRE1, NOMBRE2, APELLIDO1, APELLIDO2, NOMCOMERCIAL. El usuario ya ha seleccionado por cuál de los campos desea buscar, mi problema aparece es cuando deseamos buscar por uno de los campos por ejemplo la palabra 'ALBERTO', pero el usuario solo escribe 'ALBE', y deberían salir en mi DBGrid, todos los registros que el campo NOMBRE1, inicien con 'ALBE', hay algún comodín para usarlo, o alguna instrucción., y me lo envié a un DBGrid. Estoy usando Firebird y controles IBX

Page 36: Full Delphi

Enlazas al IBQuery aun componente DataSource (Propiedad DataSet colocas en nombre del IBQuery) y a este con el DBGrid en su propiedad DataSource. Quedaría algo así: IBuscar.SQL.Add('SELECT IDENTIFICADOR, NOMBRE1, NOMBRE2, APELLIDO1, APELLIDO2, NOMCOMERCIAL FROM NOMBRE WHERE NOMBRE1 starting with :NOMBRE ORDER BY NOMBRE2'); IBuscar.ParamByName('NOMBRE').Value := 'J' Datos Numeric y DBGrid, no muestra decimales Estoy trabajando con una base de datos Firebird en donde tengo una tabla Prestamos, los campos que debo manejar, entre otros, son uno de moneda y otro de porcentaje, los cuales me sirven para poner valores del tipo Numeric (10,2) y (4,2) respectivamente, ya que uno representa un valor monetario y el otro un porcentaje que bien podría ser 40.00 o 55.50. Lo que me pasa es que estos valores ya están cargados en la base de datos, estoy haciendo unas migraciones y están cargados en un Form, tengo un DBGrid en donde formateo uno por uno los campos a mostrar y NO logro que aparezcan los decimales de monto o porcentaje en las columnas de estos valores. Por ejemplo: - Tabla Préstamo (Nro./Monto/Porcentaje) - DBGrid de Prestamos 1 / 1500.50 / 25.66 1 / 1500.00 / 25.00 He formateado estos campos con los siguiente DisplayFormat: Monto, #0.00 (separa miles y decimales) y Porcentaje #0.00 Pero es como si no tuvieran decimales, si hago una suma es tal cual los muestra, solo la parte entera. Cambia el punto por la coma en el DisplayFormat y funcionara correctamente: TFloatField(IBQuery1.FieldByName('TU_CAMPO')).DisplayFormat := '0.00';

Copiar el valor de cada campo en un ComboBox Tengo una base de datos Materias con el índice Salón, con los campos: Salón *, Materia1, Materia2, Materia3, Materia4, Materia5; Lo que necesito es copiar el valor de cada campo en un ComboBox. Yo usaría el evento AfterScroll del DataSet que tengas asociado a tu tabla, y ahí añadiría uno a uno los campos:

Page 37: Full Delphi

ComboBox1.Items.Clear; ComboBox1.Items.Add(DataSet['Salon']); ComboBox1.Items.Add(DataSet['Materia1']); ComboBox1.Items.Add(DataSet['Materia2']);

De acuerdo a lo que entiendo de tus mensajes, sería: procedure TForm1.FormCreate(Sender: TObject); const SEP = ', '; var i: Integer; s: string; begin DataSet.Open; ComboBox1.Items.Clear; while not DataSet.Eof do begin s:= ''; for i:= 0 to DataSet.FieldCount-1 do s:= s + DataSet.Fields[i].AsString + SEP; SetLength(s,Length(s)-Length(SEP)); DataSet.Next; ComboBox1.Items.Add(s); end; ComboBox1.ItemIndex:= 0; end;

procedure TForm1.DBGrid1CellClick(Column: TColumn); const SEP = ', '; var i: Integer; s: string; begin s:=''; for i:= 0 to DataSet.FieldCount-1 do s:= s + DataSet.Fields[i].AsString + SEP; SetLength(s,Length(s)-Length(SEP)); ComboBox1.ItemIndex:= ComboBox1.Items.IndexOf(s); end;

Consulta con 3 tablas Quiero que por favor me expliquen esto: Poseo 3 tablas en Firebird y Delphi 2007

Alumnos Salones Calificaciones

cod_alumno * cod_curso * cod_curso *

cod_curso materia1 cod_alumno *

nombre ihs1 año *

Page 38: Full Delphi

apellidos docente1 materia1

año docente1

nota1p_mat1

logro1p_mat1

ausencia1_mat1

Deseo una consulta, en un DBGrid que muestre esto:

curso año cod_alumno nombres apellidos materia1 docente1 nota1 logro1 Logro2 Logro3 ausencia

En una base de datos (bien hecha) las tablas están unidas gracias a sus llaves primarias y foráneas. Se navega desde una tabla A, tabla B y luego a la tabla C: SELECT A.cod_alumno,S.cod_curso,A.nombre, (y todo lo demás) FROM Alumnos A,Salones S, Calificaciones C WHERE A.cod_alumno=C.cod_alumno AND C.cod_curso=S.cod_curso

Grabar imágenes en campo Blob de Firebird El código que publico, almacena los tipos de gráficos en un campo blob procedure TF_Cliente.BitBtn1Click(Sender: TObject); var BitmapOriginal,BitmapNew: TBitmap; FileExt: string; Graphic: TGraphic; stream: TMemoryStream; begin inherited; // Verifica que la tabla este en modo de edición o de inserción según sea el caso if datos.cdsFoto_cte.IsEmpty then datos.cdsFoto_cte.Append else datos.cdsFoto_cte.Edit; // Inicio del código que almacena la imagen en memoria (en la variable stream) BitmapNew:= TBitmap.Create; BitmapOriginal := TBitmap.Create; stream:= TMemoryStream.Create; try OpenPictureDialog1.Execute; FileExt := LowerCase(ExtractFileExt(OpenPictureDialog1.FileName)); if (FileExt = '.bmp') then Graphic:= TBitmap.Create; if (FileExt = '.ico') then Graphic:= TIcon.Create; if (FileExt = '.emf') or (FileExt = '.wmf') then Graphic:= TMetafile.Create; if (FileExt = '.jpg') or (FileExt = '.jpeg') or (FileExt = '.jpe') then Graphic:= TJPEGImage.Create;

Page 39: Full Delphi

if (FileExt = '.png') then Graphic:= TPngImage.Create; if (FileExt = '.gif') then Graphic:= TGIFImage.Create; Graphic.LoadFromFile(OpenPictureDialog1.FileName); BitmapOriginal.Assign(Graphic); try BitmapNew.Width:= 192; BitmapNew.Height:= 182; BitmapNew.PixelFormat:= pf24bit; //cambia el mapa de bits (la foto) original para el nuevo tamaño 192x182 BitmapNew.Canvas.StretchDraw(BitmapNew.Canvas.ClipRect,BitmapOriginal); {Si deseas mostrar en un timage image1.picture.graphic:= BitmapNew; O si deseas grabar en un archivo bitmapNew.Savetofile('c:\mi_bmp.bmp') } BitmapNew.SaveToStream(stream); finally FreeAndNil(BitmapNew); end; finally FreeAndNil(BitmapOriginal); end; // Almacena la foto en el campo blob datos.cdsFoto_cteFOTO_CTE.LoadFromStream(stream); datos.cdsFoto_cte.Post; FreeAndNil(stream); end;

No olvidar de colocar en la cláusula USES: pngimage, jpeg, GIFImg; El Form debe tener 1 OpenPictureDialog1, y para que quede más claro, esta instrucción: datos.cdsFoto_cteFOTO_CTE.LoadFromStream(stream); datos = data module cdsFoto_cte = Clientdataset FOTO_CTE = nombre del campo blob; Imágenes en Firebird Para cargar la Imagen (BMP, JPG, ICO) con el diálogo directamente a la base de datos: procedure TForm1.ButtonCargarImagenClick(Sender: TObject); var Jpg: TJpegImage; Stream: TMemoryStream; FileExt: string; GraphType: TGraphType;

Page 40: Full Delphi

begin if OpenPictureDialog.Execute then begin Jpg := nil; Stream := nil; try Stream := TMemoryStream.Create; FileExt := LowerCase(ExtractFileExt(OpenPictureDialog.FileName)); if (FileExt = '.bmp') or (FileExt = '.dib') then begin GraphType := gtBitmap; Stream.Write(GraphType, 1); with ImageFoto.Picture.Bitmap do begin LoadFromFile(OpenPictureDialog.FileName); ImageFoto.Picture.Bitmap.SaveToStream(Stream); end; end else if (FileExt = '.ico') then begin GraphType := gtIcon; Stream.Write(GraphType, 1); with ImageFoto.Picture.Icon do begin LoadFromFile(OpenPictureDialog.FileName); ImageFoto.Picture.Bitmap.SaveToStream(Stream); end; end else if (FileExt = '.emf') or (FileExt = '.wmf') then begin GraphType := gtMetafile; Stream.Write(GraphType, 1); with ImageFoto.Picture.Metafile do begin LoadFromFile(OpenPictureDialog.FileName); ImageFoto.Picture.Bitmap.SaveToStream(Stream); end; end else if (FileExt = '.jpg') or (FileExt = '.jpeg') or (FileExt = '.jpe') then begin Jpg := TJpegImage.Create; Jpg.LoadFromFile(OpenPictureDialog.FileName); ImageFoto.Picture.Assign(Jpg); GraphType := gtJpeg; Stream.Write(GraphType, 1); Jpg.SaveToStream(Stream); end; DataModule1.IBTPersonas.Edit; Stream.Position := 0; DataModule1.IBTPersonasFoto.LoadFromStream(Stream); except

Page 41: Full Delphi

jpg.Free; Stream.Free; raise; end; jpg.Free; Stream.Free; end; end;

Para Mostrar la Foto almacenada en la base de datos en el TImage: procedure TForm1.MostrarImagenClick(Sender: TObject); var Stream: TMemoryStream; Jpg: TJpegImage; GraphType: TGraphType; begin Jpg := nil; Stream := nil; try Stream := TMemoryStream.Create; DataModule1.IBTPersonasFoto.SaveToStream(Stream); if Stream.Size > 0 then begin Stream.Position := 0; Stream.Read(GraphType, 1); case GraphType of gtBitmap: Form1.ImageFoto.Picture.Bitmap.LoadFromStream(Stream); gtIcon: Form1.ImageFoto.Picture.Icon.LoadFromStream(Stream); gtMetafile: Form1.ImageFoto.Picture.Metafile.LoadFromStream(Stream); gtJpeg: begin Jpg := TJpegImage.Create; Jpg.LoadFromStream(Stream); Form1.ImageFoto.Picture.Assign(Jpg); end else Form1.ImageFoto.Picture.Assign(nil); // Limpiar la imagen end; end else Form1.ImageFoto.Picture.Assign(nil); except Form1.ImageFoto.Picture.Assign(nil); end; jpg.Free; Stream.Free; end;

Page 42: Full Delphi

Para Borrar la imagen de la base de datos:

procedure TForm1.BorrarImagenClick(Sender: TObject); begin ImageFoto.Picture.Assign(nil); DataModule1.IBTPersonas.Edit; DataModule1.IBTPersonasFoto.Assign(nil); // Limpiar el campo end;

Actualizar desde 2 tablas

Quiero actualizar tres campos de una tabla con el contenido de otros tres campos de otra tabla, mediante un update ¿Cómo lo hago?

Tabla 1 - Tabla 2 Campo1 - Campo 1 Campo2 - Campo 2 Campo3 - Campo

Es decir, el valor de los campos de la tabla 2 pasarlos a los campos de la tabla 1 los campos son del mismo tipo.

UPDATE Tabla1 SET = (SELECT campo1 FROM tabla2 WHERE campo1 = condicion) WHERE campo = condición

Actualizar con una condición

Deseo actualizar el campo de una tabla1, esta se encuentra relacionada con tabla2 y requiero validar un campo de la tabla2 antes de actualizar, si el campo de la tabla2 es AH, entonces actualiza la tabla1 colocando la palabra "Herramienta"

UPDATE inve_clib01 SET camplib2 = 'Herramienta' WHERE cve_prod IN (SELECT cve_art FROM inve01 WHERE lin_prod = 'AH')

Page 43: Full Delphi

Extraer fecha y desglosar de un campo

Necesito saber si se puede y como, el sacar la fecha de nacimiento de una cadena que tiene el siguiente formato: ESP19630225, es un código UCI (de los ciclistas). Lo que necesito es primero extraer las tres letras de la izquierda, y lo siguiente es poder convertir 19630225 en un campo fecha con formato 25/02/1963, todo desde una SQL que me actualice el campo fecha nacimiento de mi tabla. UPDATE ctr0003 SET

nacio = (SUBSTRING(codiuci FROM 1 FOR 3)),

data_naix = CAST( (SUBSTRING(codiuci FROM 4 FOR

4)||'/'||SUBSTRING(codiuci FROM 8 FOR 2)||'/'||SUBSTRING(codiuci FROM 10

FOR 2)) AS DATE);

Como obtener el valor de un campo

Estoy haciendo una consulta con un IBQuery que va así: SELECT login, clave, id_perfil FROM usuarios WHERE clave=: cla AND

login=:log

Extraer el valor de campo id_perfil para el registro obtenido y guardarlo en una variable (perf = string), pero no sé qué instrucción debo colocar para guardar el valor del campo id_perfil en la variable perf. var

perf: String;

begin

with IBQUsuarios do

begin

ParamByName('usu').AsString:= txtUsuario.Text;

ParamByName('cla').AsString:= txtClave.Text;

Active := true;

perf:=FieldByName('id_perfil').AsString;

end;

Otra forma posible sería var

perf: String;

begin

with IBQUsuarios do

begin

ParamByName('USU').AsString:= txtUsuario.Text;

ParamByName('CLA').AsString:= txtClave.Text;

Active := true;

perf:=Fields[2].Value;// Considerando que login=0,clave=1,id_perfil=2; end;

Page 44: Full Delphi

Asignar valor a un campo en una base de datos

Como puedo asignarle un valor a un campo en tiempo de ejecución sin utilizar ningún componente. Tienes que poner el DataSet en modo Edición. AdoTable.Insert;

AdoTable.FieldByName('Nombre').AsString := 'Luis';

AdoTable.FieldByName('Folio').AsInteger := 1234;

AdoTable.FieldByName('Fecha').AsDateTime := Now;

AdoTable.Post;

Campo clave y campo valor en un ComboBox Necesito traer desde una Tabla (Firebird 2.1) dos campos: cod_cliente, nombre_cliente. Una lista con un SELECT. Quiero poner nombre_cliente en un TComboBox para que se le despliegue al usuario pero, al momento de guardar en la BD, uso solamente cod_cliente. La cosa es así, en un ComboBox no puedo traer ambos valores, mostrar uno y guardarme el otro para usarlo cuando quiera. En un TDBComboBox si es posible (KeyValue, KeyField, KeyValue) Ahora bien; si NO quisiera usar TDBComboBox, ¿qué otra opción tengo? ¿Hay algún componente que me permita guardar la estructura (clave, valor) y poder hacer lo que comento (exceptuando el TDBComboBox claro)?. No es complicado hacer lo que quieres usando un TComboBox: procedure TForm1.FormCreate(Sender: TObject);

begin

while not IBQuery.Eof do

begin

ComboBox1.AddItem(IBQuery.FieldByName('NOMBRE_CLIENTE').AsString,

TObject(IBQuery.FieldByName('COD_CLIENTE').AsInteger));

IBQuery.Next;

end;

end;

procedure TForm1.ComboBox1Change(Sender: TObject);

begin

with ComboBox1 do

ShowMessage(Format('%s %d',[Items[ItemIndex], // NOMBRE_CLIENTE

Integer(Items.Objects[ItemIndex])])); // COD_CLIENTE

end;

Query con 2 o más tablas

Debo hacer un Query en una base de datos Firebird, obviamente, que tome valores de 2 o 3 tablas. ¿Esto es posible? Ejemplo: tablas caja, clientes, cobradores. Debo mostrar en un DBGrid, que tomará los datos de la consulta, los registros de caja, pero en vez de los códigos

Page 45: Full Delphi

de cliente y cobrador debe mostrar sus nombres, para eso deberé tomar el código de caja y localizar en las otras 2 tablas sus nombres. SELECT

a.idcaja, b.cliente, c.colaborador

FROM cajas AS a

INNER JOIN clientes AS b

ON b.idcliente = a.clienteid

INNER JOIN colaboradores AS c

ON c.idcolaborador = a.colaboradorid

Query relaciona 3 tablas Utilizo Firebird 2.5, tengo 3 tablas Facturas, rendicion_detalle y rendición. Están relacionadas facturas.id_factura = rendicion_detalle.id_factura y rendicion.nren = rendicion_detalle.nren. Necesito un Query que me entregue todas las facturas tal que no existe en otro detalle de rendición (o que exista pero el estado de la rendición sea NULL), esto con el afán de no repetir facturar en distintas rendiciones. SELECT f.* FROM facturas f

WHERE f.id_factura NOT IN (SELECT rendicion_detalle.id_factura

FROM rendicion_detalle)

OR f.id_factura IN(SELECT rendicion_detalle.id_factura FROM

rendicion_detalle,rendicion WHERE endicion.nren=rendicion_detalle.nren

AND rendicion.estado IS NULL)

UPDATE con tablas relacionadas Tengo 2 tablas en una base Firebird, la tabla Artículos y la tabla Ítems. La tabla Artículos utiliza el campo Articulos.FK_Items para relacionarse con la tabla Ítems a través de Items.ID, La relación entre Artículos e Ítems es 1 a 1. Necesito actualizar un campo de la tabla Artículos colocando un valor fijo para el caso en que el campo código de la tabla Ítems tenga un determinado valor.

UPDATE articulos

SET codigo_segundo = 'X'

WHERE (SELECT codigo FROM items

WHERE articulos.fk_items = items.id) IN ('AL494J', 'F494P')

UPDATE sobre fechas pero solo las vacías

Tengo una Base Firebird que contiene una tabla de tareas asignadas. Los campos de esta tabla son: Id, IdInt, FechaAlta, FechaBaja, TareaAsignada, MotivoBaja, ResposableBaja. Lo que trato de lograr es que cuando un interno (IdInt) sea dado de baja por algún motivo me coloque esta fecha solo en las tareas que no han sido dadas de baja. Por ejemplo

Page 46: Full Delphi

Como se puede observar en caso de hacer algún movimiento (Egresa) con el interno 2 (IdInt) necesitaría que en el ID 4 el campo FechaBaja registre la novedad pero que deje intactas la demás fechas. Creo que buscas algo como:

UPDATE Tareas SET FechaBaja = :Baja

WHERE idInt = :Indice AND FechaBaja IS NULL

UPDATE de un campo dependiendo del valor de un campo de otra tabla Tengo dos tablas Tabla1 y Tabla2 y necesito poner, mediante un UPDATE, el Campo1 de la Tabla1 = True si Campo2 de Tabla2 > 10 y False en caso contrario, es decir: Si Campo2 (Tabla2) > 10 -> Campo1 (Tabla1) = True Else Campo1 (Tabla1) = False. Yo con Firebird uso algo así: UPDATE Tabla1 T1 SET campo1=TRUE

WHERE EXISTS (SELECT * FROM Tabla2 T2

WHERE T2.campo2>10 AND T2.codigo=T1.codigo)

Suponiendo que todas son FALSE antes de UPDATE. Ó UPDATE Tabla1 T1 SET

campo1= MI_COMPARACION(T1.campo1, (SELECT T2.campo2 FROM Tabla2 T2

WHERE T1.codigo=T2.codigo),10)

En ambas asumo que el campo código es el que relaciona ambas tablas. En la segunda propuesta habría que hacer la función MI_COMPARACION porque probaré a poner " campo1 = (10 <> SELECT T2.campo2 FROM Tabla2 T2 WHERE T1.codigo=T2.codigo) " y da error, lo que no sé es si existe ya alguna función tal efecto (y que devuelva el tipo de dato que te interesa) Campo clave y campo valor en un ComboBox

Necesito traer desde una Tabla (Firebird 2.1) dos campos: cod_cliente, nombre_cliente. Una lista con un Select. Quiero poner nombre_cliente en un ComboBox para que se le despliegue al usuario pero, al momento de guardar en la BD, uso solamente cod_cliente. La cosa es así, en un TComboBox no puedo traer ambos valores, mostrar uno y guardarme el otro para usarlo cuando quiera. En un TDBComboBox si es posible (keyValue, KeyField, KeyValue) Ahora bien; si NO quisiera usar TDBComboBox, ¿qué otra opción tengo? ¿Hay algún componente que me permita guardar la estructura (clave, valor) y poder

Id Idint FechaBaja

1 1 01/08/2013

2 1

3 2 30/07/2013

4 2

5 2 25/05/2013

Page 47: Full Delphi

hacer lo que comento (exceptuando el TDBComboBox claro)?. No es complicado hacer lo que quieres usando un TComboBox: procedure TForm1.FormCreate(Sender: TObject);

begin

while not IBQuery.Eof do

begin

ComboBox1.AddItem(IBQuery.FieldByName('NOMBRE_CLIENTE').AsString,

TObject(IBQuery.FieldByName('COD_CLIENTE').AsInteger));

IBQuery.Next;

end;

end;

procedure TForm1.ComboBox1Change(Sender: TObject);

begin

with ComboBox1 do

ShowMessage(Format('%s %d',[Items[ItemIndex],// NOMBRE_CLIENTE

Integer(Items.Objects[ItemIndex])])); // COD_CLIENTE

end;

Consulta necesaria

Yo tengo una tabla cargada con varios datos, supongamos movimientos de un expediente, dentro de los datos importantes en cada registro está el No. de expediente (o código único) y el orden en que se realizó el paso.

Lo que necesito es hacer una consulta que tome todos los expedientes cargados, pero solo el último movimiento de cada uno! el cual está determinado por el orden y así conseguir un Query con esos datos. Expediente y Último Movimiento. Lo que buscas es esto:

SELECT n_exp,asunto,fecha,folios, MAX(ord) AS ord FROM temp T1

WHERE ord = (SELECT MAX(ord) FROM temp T2

WHERE T2.n_exp = T1.n_exp)GROUP BY n_exp, asunto, fecha, folios

Actualizar un campo vacío con el valor de otro El archivo TXT en el que me mandan los corredores ciclistas desde la federación, está separado por comas y su formato es dorsal, nombre, apellido1, apellido2, etc., esto hasta aquí es correcto, luego yo importo estos datos a la tabla Firebird correspondiente y funciona de perlas pero he detectado que los corredores extranjeros que tienen un solo apellido, este no figura en apellido1 sino en apellido 2, con lo cual si hago una búsqueda a estos no los encuentro jamás ya que el valor es vacío, como ejemplo:

Lo que yo necesitaría sería que una vez importados los datos a la tabla, pudiera recorrer la tabla y cambiar el valor de los registros 2 y 3

No. Orden

1001 1

1001 2

1001 3

1002 1

1002 2

1005 1

1005 2

1005 3

1005 4

1 Josep, Fernández, Alberti, etc.

2 Lio, Chin, etc.

3 Johnny, Walker, etc.

4 Antonio, Gómez, Pérez, etc.

Page 48: Full Delphi

(que son los que están vacíos en apellido1) y que la tabla quedara así: He probado con UPDATE si campo apellido 2 = vacío que apellido 1=apellido2 y luego apellido2 = vacío, pero claro me los cambia todos.

Si lo has hecho así te quedaría que todos los que tengan el apellido2 vacío también tengan vacío el apellido1 y por si acaso no estaba suficientemente vacío el apellido2 lo vuelves a vaciar. Creo que sería algo como UPDATE corredores SET apellido1=apellido2,apellido2=''

WHERE apellido1 IS NULL

Supongo que con algo así funcionaría dando por hecho que realizará la primera actualización antes que la segunda. También podría hacer la comprobación a la hora de volcar los datos a la tabla Firebird, no sé cómo haces el traspaso de un lado a otro pero doy por sentado que en algún momento podrías meter la comprobación. Por último podrías hacer que al buscar por apellido no hagas dos campos de búsqueda, uno para el apellido1 y otro para el apellido2, yo pondría un solo campo que sería apellido y luego buscaría en la tabla coincidencias en los dos campos. SELECT * FROM corredores

WHERE apellido1 LIKE '%ernandez%' OR apellido2 LIKE '%ernandez%'

Como guardar desde un DateTimePicker a una base de datos

Quiero pasar la fecha que tengo en DateTimePicker1 a una base de datos Firebird desde mi botón guardar ff (BAcceso.Connected)then

begin

QAcceso.Database:=BAcceso;

QAcceso.Transaction:=TAcceso;

QAcceso.SQL.Text:='insert into UNO(FECHA)

values('+QuotedStr(FormatDateTime('mm/dd/yyyy',DateTimePicker1.Date))+')';

QAcceso.ExecSQL;

ShowMessage('Informacion grabada satisfactoriamente');

end;

Como pasarle un valor a un ComboBox desde un campo

Estoy programando con los componentes estándar para recuperar los datos de unos varios campos de una Base de datos, no sé por qué con un ComboBox no le puedo pasar un valor extraído de un campo y en dado caso a veces me sale el desplegado de ítem que tiene ese ComboBox otras no. Supongo que tu ComboBox se llama txtEQ_SO, trata con:

1 Josep, Fernández, Alberti, etc.

2 Lio, Chin, etc.

3 Johnny, Walker, etc.

4 Antonio, Gómez, Pérez, etc.

Page 49: Full Delphi

txtEQ_SO.Items.Add(' ');

Con esto debería incrementar la lista de lo que hay en el ComboBox, dentro de los paréntesis de este pones lo que vas a adherir al combo. Otra idea: Que te parece, borras lo que tienes en el ComboBox y realizas la consulta por medio de un Query y lo agregas al combo así: ComboBox.Items.Clear;

With IBQuery do

begin

Close;

Sql.Clear;

Sql.Add('SELECT campo FROM tabla');

Open; First;

If Not IsEmpty Then

begin

While Not EOF do

begin

ComboBox.Items.Add(FieldByName('campo').AsString);

Next;

end;

end;

end;

Asignar a campo un SELECT MAX El problema radica en que son incompatibles los tipos de datos dado que item_prodespera un dato entero y asignarle ese SELECT no es correcto. Como debo hacer para que item_prod tome el valor Integer que devuelve el SELECT? Tienes que poner tu código en un IBQuery 'SELECT MAX (item_prod) AS mayor FROM prod '

Luego ábrela, y por ultimo procedure TForm6.Button1Click(Sender: TObject);

begin

IBQuery.Close;

IBQuery.Open;

band := DBLookupComboBox1.KeyValue;

IBDataSet1.Append;

DBLookupComboBox1.KeyValue := band;

IBDataSet1.FieldByName('item_prod').AsInteger :=

IBQuery.Fieldbyname('mayor'). asInteger;

end;

Consulta en Firebird

Tengo una tabla personas y otra personas-operaciones Firebird personas (id-nombre) personas-operaciones (idpersona-tipooperacion-lugar-descripcion).

Page 50: Full Delphi

Como se puede realizar un SELECT, que muestre todas las personas que coincidan independientemente de cuantas líneas como parámetro quiera introducir. SELECT DISTINCT...

FROM INNER JOIN...

WHERE

AND personas-operacion.lugar =: lugar

AND personas-operacion.descripcion =: descripción

Ahí solo me traería las que tengan una determinada operación y si quisiera ampliar y detallas más operaciones, y me traiga las que cumplen con ambas o todas las que agregue. Puedes usar: personas-operacion.tipooperacion

IN (:tipo1, :tipo2, :tipo3, :tipo4, :tipo5)

Así podrás seleccionar personas que colaboran en varias operaciones (puedes poner a NULL los parámetros que no necesites en un momento dado). Consulta para contar registros

Necesito saber cuántos registros hay en una tabla filtrada por un campo de la misma, es decir: ID CODIGO AÑO

1 2 2009

2 2 2010

3 3 2008

4 3 2009

5 3 2010

6 4 2010

El resultado que quiero obtener es: CODIGO VECES

2 2

3 3

4 1

SELECT codigo, COUNT(codigo) AS veces FROM mi_table GROUP BY codigo

Ese sería la cláusula SQL. Lo importante aquí es el GROUP BY, que se utiliza para agrupar registros y con la combinación de la función COUNT, obtienes lo que deseas.

Page 51: Full Delphi

Convertir la primera letra mayúscula y las demás minúsculas

Tal como te dice Casimiro tienes que usar las funciones UPPER Y LOWER. UPDATE empleados

SET nombre = LEFT(UPPER(nombre),1) ||

RIGHT(LOWER(nombre),CHAR_LENGTH(nombre)-1) WHERE empleados_id = 1

Actualizar un campo que contiene información extra

Ejemplo: realizar un UPDATE y dejar solo la palabra Madero Nombre Dirección

C. Carlos Cuaron Colonia Madero #222

UPDATE colonias SET direccion='Madero' WHERE direccion IN

(SELECT direccion FROM colonias WHERE direccion LIKE '%Madero%')

Aunque personalmente creo que es mucho más simple y elegante esta otra: UPDATE colonias SET direccion = 'Madero'

WHERE direccion CONTAINING 'Madero'

Formato en centenas, decimales y unidades Tengo un campo Char con estos datos 85.12 o también con 115.12 como valores y necesito que pasarlo a este 008512 o en el caso 011512 no se si tendría que hacerlo en un If o si hay una función para hacerlo. Simplemente multiplica el número por 100. SELECT lpad((CAST(lpad((numero*100), 6, '0') AS Integer)),6,'0')

FROM A_tabla

Firebird sentencia: buscar coincidencias en una columna Quisiera hacer una consulta de una tabla para extraer los registros que más coincidan en una columna con la frase que busco. Imagino que es algo como lo que suelen hacer los buscadores tipo Google. Es decir, si por ejemplo busco en una tabla de entidades la entidad: 'palabra1 palabra2 palabra3' Quisiera que la consulta me mostrara los resultados que encuentre en la tabla ordenado de mayor coincidencia a menor coincidencia, por ejemplo: palabra2 palabra3 palabra1 palabraX palabra3 palabra2 palabra1 palabra3 palabra2 palabraY palabra1 palabraZ palabraQ

Page 52: Full Delphi

Observar que el orden del valor del registro puede ser distinto al criterio que busco, pero debe mostrarme primero los registros que mayor coincidencia tenga. No, no existe nada similar para Firebird, pero te puedes construir una consulta, parecida a la que proponías inicialmente, en la que además calculas el número de coincidencias sobre las palabras buscadas, y ordenas de mayor a menor en función de esas coincidencias. Por ejemplo., para buscar por 3 palabras: SELECT dir,

(CASE WHEN dir CONTAINING :txt1 THEN 1 ELSE 0 END +

CASE WHEN dir CONTAINING :txt2 THEN 1 ELSE 0 END +

CASE WHEN dir CONTAINING :txt2 THEN 1 ELSE 0 END) AS coincidencias

FROM clientes

WHERE dir CONTAINING :txt1 OR

dir CONTAINING :txt2 OR

dir CONTAINING :txt3

ORDER BY coincidencias DESCENDING

Naturalmente puedes ampliar la consulta hasta 10, 15, 20 o 50 palabras, de manera que la misma consulta te sirva para cualquier búsqueda que quiera hacer el usuario (en un momento dado solo tendrás que asignar valor a tantos parámetros como palabras está buscando el usuario). Problemas con campos Numeric Estoy trabajando con Delphi 2010, con Firebird 2.1 e IbExpert personal edition, y lo que me ocurre es lo siguiente, al crear la base de datos con la siguiente estructura LOTE VarChar 20

FECHA date

TIPO_DOCUMENTO VarChar 40

NUMERO_DOCUMENTO VarChar 15

CODIGO_PRODUCTO VarChar 20

CANTIDAD Integer

UD_LITROS Numeric 10,3

Al meter datos en IbExpert en el campo Numeric me sale el mensaje, Cannot post cahges!

There is at least one record with same fields values!

Y al hacerlo desde el programa, no dice nada pero tampoco me registra el valor introducido. Primero creas un "generator", ejemplo: CREATE SEQUENCE GEN_lotes_salida_ID;

ALTER SEQUENCE GEN_lotes_salida_ID RESTART WITH 0;

/* Old syntax is:

CREATE GENERATOR GEN_lotes_salida_ID;

SET GENERATOR GEN_lotes_salida_ID TO 0;

*/

Page 53: Full Delphi

Luego creas el trigger: CREATE OR ALTER trigger trg_lotes_salida_bi0 for lotes_salida

active before insert position 0

AS

BEGIN

NEW.id = GEN_ID(GEN_lotes_salida_ID,1);

END

Filtro por fecha Uso Firebird, Campos (id, fecha, total). Tengo un formulario y necesito filtrar por fecha ejemplo (15/10/08), tengo un componente DateTimePicker en el evento OnChange y cuando trato de filtrar la fecha no la filtra sino que pone el DBGrid en vacío. Cuando haces consultas por fechas en Firebird debes pasarle en formato mm/dd/yyyy. Primero, como dices que existe una factura con la fecha 16/05/2008 (dd/mm/aa), entonces prueba tu Query así: SelectSQL.Add('where Fecha = cast(''' + '05/16/08' + ''' as date)');

Si es que ahora ya te filtró correctamente, entonces prueba el siguiente código: SelectSQL.Add('where Fecha = cast(''' + FormatDateTime('mm/dd/yy',

f_actual.Date) + ''' as date)');

Fecha y Hora al insertar registros Uso InterBase 7, y tengo la necesidad de saber fecha y hora en que se agregó un registro. En Firebird empleo una solución, en todas mis tablas tengo este par de campos y los lleno con un disparador Before Insert-Update: USUARIOMODIFICACION VARCHAR(31) NOT NULL

FECHAMODIFICACION TIMESTAMP NOT NULL

CREATE TRIGGER tgbiucontratousuariom FOR contrato ACTIVE BEFORE INSERT OR UPDATE POSITION 0 As Begin New.UsuarioModificacion = Current_User; New.FechaModificacion = Current_TimeStamp; End

Actualizar Campo Fecha Automáticamente Estoy diseñando una base de datos en Firebird 2.0 y en una tabla necesito crear un campo tipo date el cual se actualice automáticamente todos los días con la fecha del día.

Page 54: Full Delphi

Si solamente es para capturarla más tarde, siempre puedes utilizar la variable de contexto llamada current_date de Firebird. SELECT current_date FROM rdb$database

Consulta filtrada

Tengo problemas al querer filtrar una consulta en Firebird Datos en tabla: Salida que busco COD1 COD2 REG_ID COD1 REG_ID

01 001 1 01 1

01 002 2 02 3

02 001 3 03 4

03 001 4

01 003 5

SELECT DISTINCT C1.COD1,

(SELECT FIRST 1 C2.ID FROM TBL C2 Where C1.COD1=C2.COD1)FROM TBL C1

Insertar datos de una Tabla a otra usando Where... Tengo una tabla ciudad con los siguientes campos: ID_Ciudad (auto_increment), Ciudad, Código_Postal, ID_Provincia, esta tiene unas 18000 localidades. Por otro lado tengo otra tabla Ciudad2 con los mismos campos con 23000 localidades, mi intención es insertar las localidades de esta tabla a la primera tabla de los registros que no estén. INSERT INTO ciudad (Ciudad,Codigo_Postal,ID_Provincia)

SELECT Ciudad,Codigo_Postal,ID_Provincia FROM ciudad2

WHERE Ciudad NOT IN (SELECT c2.Ciudad

FROM ciudad2 c2 INNER JOIN ciudad c1 ON

(c2.Ciudad=c1.Ciudad AND c2.Codigo_Postal=c1.Codigo_Postal))

Insertar datos en tabla recorriendo un DBGrid Estoy desarrollando el módulo de crear usuarios para un sistema de control de inventario y me han solicitado que un usuario tenga varios perfiles el cual comprende asociar el departamento más el área = perfil, ya tengo eso mi problema es que no sé cómo ingresar esa relación que la hago en un DBGrid a la tabla, ósea tengo que recorrer todas las líneas del DBGrid e irlas insertando en la tabla pero no sé cómo hacerlo. begin

dmConecta.qAreaporRol.Close;

dmConecta.qAreaporRol.SQL.Clear;

dmConecta.qAreaporRol.SQL.Add('INSERT INTO AREAPORROL (IDAREAROL,

ID_PERFILES, ID_ROLES, ID_USUARIO, ID_DEPTO)');

Page 55: Full Delphi

dmConecta.qAreaporRol.SQL.Add('VALUES (:IDAREAROL, :ID_PERFILES,

:ID_ROLES, :ID_USUARIO, :ID_DEPTO)');

dmConecta.qAreaporRol.Prepare;

with DBGrid1.DataSource.DataSet do

begin

DisableControls;

try

First;

while not Eof do

begin

dmConecta.qAreaporRol.ParamByName(':IDAREAROL').Value :=

FieldByName('IDAREAROL').Value;

dmConecta.qAreaporRol.ParamByName(':ID_PERFILES').Value:=

FieldByName('ID_PERFILES').Value;

dmConecta.qAreaporRol.ParamByName(':ID_ROLES').Value :=

FieldByName('ID_ROLES').Value;

dmConecta.qAreaporRol.ParamByName(':ID_USUARIO').Value :=

FieldByName('ID_USUARIO').Value;

dmConecta.qAreaporRol.ParamByName(':ID_DEPTO').Value :=

FieldByName('ID_DEPTO').Value;

dmConecta.qAreaporRol.ExecSQL;

Next;

end;

finally

EnableControls;

end;

end;

end;

Pasar de Edit a DBGrid

Tengo varios Edit a los que agrego información que tengo en una base de datos lo que quiero lograr es esa información pasarla a un DBGrid en forma de lista cada dato que vaya necesitando como si fuera una venta with DBGrid1.DataSource.DataSet do

begin

if not (State in [dsEdit,dsInsert]) then

Edit; // Insert o Append de acuerdo a lo que quieras

FieldByName('Campo1').AsString:= Edit1.Text;

FieldByName('Campo2').AsString:= Edit2.Text;

Post; // si deseas guardarlo aquí

end;

Si quieres poner los valores uno debajo de otro, tenéis que incrementar el índice de las filas y dejar fijo el de las columnas, por ejemplo: with StringGrid1 do

begin

Cells[Col, FixedRows ]:= Edit1.Text;

Cells[Col, FixedRows+1]:= Edit2.Text;

Cells[Col, FixedRows+2]:= Edit3.Text;

end;

Page 56: Full Delphi

Y si deseas situarlos uno al lado del otro de izquierda a derecha incrementar el índice de las columnas y dejar fijo el de las filas: with StringGrid1 do

begin

Cells[FixedCols , Row]:= Edit1.Text;

Cells[FixedCols+1, Row]:= Edit2.Text;

Cells[FixedCols+2, Row]:= Edit3.Text;

end;

Desglosar efectivo en billetes y monedas

Sirve para facilitarle el trabajo al cajero cuando va a buscar el dinero de las nóminas al banco, que sepa rápidamente la cantidad de billetes y monedas por denominación que tiene que pedir, también le sirve para cuando vaya a entregar el salario a cada trabajador.

procedure TForm1.Desglosar(Importe :Single; var Billetes:array of Single;

var Monedas:array of Single);

var

Dinero,

Desglose :Single;

begin

//****************************** Billetes ******************************

Dinero:=Int(Importe);

//Billetes de 100

if cb100.Checked then

begin

Desglose:=Int(Dinero / 100);

Dinero:=Dinero - Desglose * 100;

Billetes[0]:=Billetes[0] + Desglose;

end;

//Billetes de 50

if cb50.Checked then

begin

Desglose:=Int(Dinero / 50);

Dinero:=Dinero - Desglose * 50;

Billetes[1]:=Billetes[1] + Desglose;

end;

Page 57: Full Delphi

//Billetes de 20

if cb20.Checked then

begin

Desglose:=Int(Dinero / 20);

Dinero:=Dinero - Desglose * 20;

Billetes[2]:=Billetes[2] + Desglose;

end;

//Billetes de 10

if cb10.Checked then

begin

Desglose:=Int(Dinero / 10);

Dinero:=Dinero - Desglose * 10;

Billetes[3]:=Billetes[3] + Desglose;

end;

//Billetes de 5

if cb05.Checked then

begin

Desglose:=Int(Dinero / 5);

Dinero:=Dinero - Desglose * 5;

Billetes[4]:=Billetes[4] + Desglose;

end;

//Billetes de 3

if cb03.Checked then

begin

Desglose:=Int(Dinero / 3);

Dinero:=Dinero - Desglose * 3;

Billetes[5]:=Billetes[5] + Desglose;

end;

//Billetes de 1

Desglose:=Int(Dinero / 1);

Dinero:=Dinero - Desglose * 1;

Billetes[6]:=Billetes[6] + Desglose;

//****************************** Monedas ******************************

Dinero:=(Round((Frac(Importe)*100)));

//Monedas de 0.20

if cb020.Checked then

begin

Desglose:=Int(Dinero / 20);

Dinero:=Dinero - Desglose * 20;

Monedas[0]:=Monedas[0] + Desglose;

end;

//Monedas de 0.05

if cb005.Checked then

begin

Desglose:=Int(Dinero / 5);

Dinero:=Dinero - Desglose * 5;

Monedas[1]:=Monedas[1] + Desglose;

end;

//Monedas de 0.02

Page 58: Full Delphi

if cb002.Checked then

begin

Desglose:=Int(Dinero / 2);

Dinero:=Dinero - Desglose * 2;

Monedas[2]:=Monedas[2] + Desglose;

end;

//Monedas de 0.01

Desglose:=Int(Dinero / 1);

Dinero:=Dinero - Desglose * 1;

Monedas[3]:=Monedas[3] + Desglose;

end;

Una forma de llamarlo: Desglosar(StrToFloat(Valor.Text), Bill, Mon);

Seleccionar valor en un rango de datos Necesito filtrar la siguiente información, tengo una tabla que tiene los siguientes campos: SERIE FOLIO_INICIAL FOLIO_FINAL NODECERTIFICADO X 1 100 123456789

A 1 500 965432178

X 1 400 111118888

Y 1 200 598444444

Necesito Extraer de esta tabla el NODECERTIFICADO conociendo la SERIE y el folio dentro de un rango, es decir, si tengo SERIE X, FOLIO 255 que el resultado sea 111118888 SELECT * FROM control_de_folios WHERE SERIE = 'X' AND (FOLIO_inicial <=

255 AND folio_final !< 255)

Seleccionar un dato del DBLookupComboBox y guardar muchos en base de datos

Tengo una base de datos en Access llamada "Datos" conectada a un ADOQuery, Esta base contiene una tabla llamada Provincias con los campo id y provincia ya cargada, y una tabla Ciudades con los campos id y ciudades, con todas las ciudades del país ya cargadas. Lo que quiero lograr es que desde un DBLookupComboBox que están cargadas todas las provincias, seleccione una, y en una tabla Persona ya creada, con sus campos, genere registros con todas las ciudades en el campo ciudad (de la provincia elegida).

Page 59: Full Delphi

Ejemplo: elijo en el ComboBox una provincia "Córdoba" y al presionar Guardar, se carguen todas las ciudades de la provincia "córdoba" en el campo ciudad de la tabla persona. Si en la tabla CIUDADES, tienes creado un campo PROVINCIA_ID que haga referencia al campo ID de la provincia a la que pertenece (como creo que sería lógico). Y en el DBLookupComboBox de provincias, tienes configurada la propiedad KeyValue para que te devuelva el valor del campo ID de la tabla PROVINCIAS, podes hacer algo similar a: procedure TTuForm.btnGuardarClick(Sender: TObject);

begin

with qyNueva do

begin

Close;

SQL.Clear;

SQL.Add('INSERT INTO TABLA_NUEVA(ID, NOMBRE_CIUDAD, PROVINCIA_ID)');

SQL.Add('SELECT T2.ID, T2.NOMBRE_CIUDAD, T2.PROVINCIA_ID');

SQL.Add('FROM TABLA_CIUDADES T2');

SQL.Add('WHERE T2.PROVINCIA_ID = ' +

QuotedStr(QuotedStr(DBLookupProvincias.KeyValue)));

ExecSQL;

end;

end;

Si los registros de la tabla CIUDADES no tienen un campo que identifique a qué provincia pertenece, no veo la forma de seleccionar aquellas ciudades que corresponden a determinada provincia. Lo único que tendrías que agregar es un campo más a la tabla CIUDADES para que almacene el ID de la provincia a que pertenece, por ejemplo: Tabla CIUDADES: ID NOMBRE_CIUDAD PROVINCIA_ID

45 Villa Carlos Paz 5

47 Federación 12

51 Coronel Vidal 3

60 González Chávez 3

Tabla PROVINCIAS: ID NOMBRE_PROVINCIA

3 Buenos Aires

12 Entre Ríos

5 Córdoba

Entonces tomando en cuenta el campo de referencia PROVINCIA_ID, ahora si podemos decir que la relación está establecida ya que: Villa Carlos Paz Córdoba 5

Federación Entre Ríos 12

Coronel Vidal Buenos Aires 3

González Chávez Buenos Aires 3

Page 60: Full Delphi

Y por lo tanto solo necesitamos seleccionar de la tabla CIUDADES aquellas cuyo campo PROVINCIA_ID sea igual al ID de provincia deseado. De forma tal al código que te puse en el mensaje anterior. Abrir Form acorde a contraseña

Tengo 2 Formularios (Form1, Form2), en el Formulario1 tengo un Edit y un Botón, y en formulario 2 no tengo nada, pero bueno la cosa es así, yo le puse una Contraseña al botón para que al Escribir esa contraseña dentro del Edit1 me salga un MessageBox que diga, "Contraseña Correcta" y me abra el Form2. Y si la Contraseña no es Correcta que me salga un MessageBox que diga, "Contraseña Incorrecta" y que regrese al Form1 hasta que no atine la Contraseña Correcta. procedure TForm1.Button1Click(Sender: TObject);

begin

if Edit1.Text <> 'Esta es la Contraseña' then

messagebox(0,

PChar('Contraseña Incorrecta'),

PChar('Aviso'),

MB_OK)

else

begin

messagebox(0,

PChar('Contraseña Correcta'),

PChar('Bienvenido'),

MB_OK);

Hide;

Form2.Show;

end;

end;

Asignarle el Valor de un DBEdit a un DBGrid

Saben cómo puedo hacer que una columna del DBGrid me copie el Valor que Tiene un DBEdit. Table1.FieldByName('Valor').AsString := Edit1.Text;

IBDataSet.FieldByName('Valor').AsString:=DBEdit.Field.AsString

Ayuda con consulta Tengo dos tablas en Firebird 2.5 así: Prestadores Solicitudes Id_Prestador Integer Id_Solicitud Integer

Prestador VarChar Id_Prestador Integer*

Terminada VarChar

Ahora bien, el campo "Terminada" de la tabla solicitudes puede albergar los siguientes valores ('SI', 'NO', 'NO APLICA').

Page 61: Full Delphi

Lo que necesito es una consulta que me cuente el total de solicitudes de cada prestador, además de los diferentes valores del campo "TERMINADA" y me los agrupe por PRESTADORES, más o menos así:

Prestador Total_Solicitudes_Prestador Terminada_Si Terminada_N Terminada_No_Aplica

Prestador 1 10 5 4 1

Prestador 2 20 10 8 2

Prestador n 5 3 1 1

SELECT Id_Prestador,

SUM(Terminada) AS TotalTerminada,

SUM(NoTerminada) AS TotalNoTerminada,

SUM(NoAplica) AS TotalNoAplica

FROM (SELECT ID_Prestador,

IIF(Terminada = 'SI', 1, 0) AS Terminada,

IIF(Terminada = 'NO', 1, 0) AS NoTerminada,

IIF(Terminada = 'NO APLICA', 1, 0) AS NoAplica

FROM Solictudes) GROUP BY Id_Prestador

Imágenes en Firebird Estoy diseñando una aplicación relacionada con el control de personal, el tema es que el cliente ha solicitado que entre toda la información esté contenida la foto de cada trabajador. En este caso no se utiliza otro campo para el formato. Para probar en un Formulario (Form1) pones:

Un TOpenPictureDialog y lo nombras TOpenPictureDialog,

Un TButton y Lo Nombras ButtonCargarImagen,

Un TButton y lo Nombras MostrarImagen,

Un TButton y lo Nombras BorrarImagen,

Un TImage y lo Nombras ImageFoto, Además en DataModule1 existe una tabla de InterBase IBTPersonas con un campo tipo Blob llamado Foto (Enlazada a la correspondiente base de datos). También puedes poner un DBGrid enlazado a la Tabla mediante el DataSource correspondiente para seleccionar el registro con que quieras experimentar. Adicionar en el Uses JPEG Para cargar la Imagen (BMP, JPG, ICO) con el diálogo directamente a la base de datos: procedure TForm1.ButtonCargarImagenClick(Sender: TObject); var Jpg: TJpegImage; Stream: TMemoryStream; FileExt: string; GraphType: TGraphType; begin

Page 62: Full Delphi

if OpenPictureDialog.Execute then begin Jpg := nil; Stream := nil; try Stream := TMemoryStream.Create; FileExt := LowerCase(ExtractFileExt(OpenPictureDialog.FileName)); if (FileExt = '.bmp') or (FileExt = '.dib') then begin GraphType := gtBitmap; Stream.Write(GraphType, 1); with ImageFoto.Picture.Bitmap do begin LoadFromFile(OpenPictureDialog.FileName); ImageFoto.Picture.Bitmap.SaveToStream(Stream); end; end else if (FileExt = '.ico') then begin GraphType := gtIcon; Stream.Write(GraphType, 1); with ImageFoto.Picture.Icon do begin LoadFromFile(OpenPictureDialog.FileName); ImageFoto.Picture.Bitmap.SaveToStream(Stream); end; end else if (FileExt = '.emf') or (FileExt = '.wmf') then begin GraphType := gtMetafile; Stream.Write(GraphType, 1); with ImageFoto.Picture.Metafile do begin LoadFromFile(OpenPictureDialog.FileName); ImageFoto.Picture.Bitmap.SaveToStream(Stream); end; end else if (FileExt = '.jpg') or (FileExt = '.jpeg') or (FileExt = '.jpe') then begin Jpg := TJpegImage.Create; Jpg.LoadFromFile(OpenPictureDialog.FileName); ImageFoto.Picture.Assign(Jpg); GraphType := gtJpeg; Stream.Write(GraphType, 1); Jpg.SaveToStream(Stream); end; DataModule1.IBTPersonas.Edit; Stream.Position := 0; DataModule1.IBTPersonasFoto.LoadFromStream(Stream); except jpg.Free; Stream.Free; raise; end; jpg.Free; Stream.Free;

Page 63: Full Delphi

end; end;

Para Mostrar la Foto almacenada en la base de datos en el TImage: procedure TForm1.MostrarImagenClick(Sender: TObject); var Stream: TMemoryStream; Jpg: TJpegImage; GraphType: TGraphType; begin Jpg := nil; Stream := nil; try Stream := TMemoryStream.Create; DataModule1.IBTPersonasFoto.SaveToStream(Stream); if Stream.Size > 0 then begin Stream.Position := 0; Stream.Read(GraphType, 1); case GraphType of gtBitmap: Form1.ImageFoto.Picture.Bitmap.LoadFromStream(Stream); gtIcon: Form1.ImageFoto.Picture.Icon.LoadFromStream(Stream); gtMetafile: Form1.ImageFoto.Picture.Metafile.LoadFromStream(Stream); gtJpeg: begin Jpg := TJpegImage.Create; Jpg.LoadFromStream(Stream); Form1.ImageFoto.Picture.Assign(Jpg); end else Form1.ImageFoto.Picture.Assign(nil); // Limpiar la imagen end; end else Form1.ImageFoto.Picture.Assign(nil); except Form1.ImageFoto.Picture.Assign(nil); end; jpg.Free; Stream.Free; end;

Para Borrar la imagen de la base de datos: procedure TForm1.BorrarImagenClick(Sender: TObject);

begin

ImageFoto.Picture.Assign(nil);

DataModule1.IBTPersonas.Edit;

DataModule1.IBTPersonasFoto.Assign(nil); // Limpiar el campo

end;

Controlar DBLookupComboBox Cargo un DBLookupComboBox desde la BD sin problemas, en la lista tenemos varios ítems, cuando el usuario selecciona un elemento de la lista, el sistema se detiene y le pregunta si está seguro de cambiar de ítem, esto se hace porque si el

Page 64: Full Delphi

tipo responde que "si" algunas cosas del formulario cambian; y si responde que "no" el formulario no debería cambiar y el elemento visible en el combo tampoco debería cambiar al que seleccionó. Resulta que si respondo que "si", no hay problema, pero cuando respondo que no, los cambios en el formulario no se hacen pero el elemento visible cambia, y yo no quiero que cambie. Lo que necesito es que cuando responda que "no" el combo ponga visible la opción que estaba antes de hacer clic en él. var

OldKeyValue: string;

procedure TForm1.DBLookupComboBox1Enter(Sender: TObject);

begin

OldKeyValue:= VarToStr(DBLookupComboBox1.KeyValue);

end;

procedure TForm1.DBLookupComboBox1Click(Sender: TObject);

begin

if MessageBox(Handle,'¿ Desea cambiar de ítem?',

'',MB_ICONQUESTION+MB_YESNO) = IDNO then

DBLookupComboBox1.KeyValue:= OldKeyValue

else

OldKeyValue:= VarToStr(DBLookupComboBox1.KeyValue);

end;

Cargar ComboBox con datos de tabla

Tengo una tabla y necesito cargar un ComboBox con un campo de la tabla, he leído por ahí del DBLookupComboBox pero este necesita que la tabla tenga una primary key definida no?, es decir tengo un campo categoría, y necesitaría agregar de la tabla las categorías sin que se repitan. With dbgrid1.datasource.dataset do begin

try

DisableControls; //Deshabilitamos los controles asociados a ese

DataSet

First;

While not eof do begin

if Ccat.Items.IndexOf(FieldByName('Categoria').AsString)=-1 then

Ccat.Items.Add(FieldByName('Categoria').AsString);

Next;

end;

finally

EnableControls; //habilitamos nuevamente los controles

end;

Page 65: Full Delphi

Agregar Filas a TDBGrid según Filtro Búsqueda

Estoy realizando un formulario de "Préstamo de Libros" y dentro de ello, tengo un control TEdit llamado "txtfiltro" que realiza una búsqueda exacta de un campo determinado en mi IBQuery (qConsultar).

Select * From libros Where libros.isbn_lib Like '%' || :xisbn || '%'

Esta consulta me trae varios datos cómo: "Nombre Autor", "Título Libro", "Código ISBN", "Temática", "Ubicación del Libro". Ahora lo que se requiere es que si la consulta arroja resultados (es decir, encuentra un Libro), esto debe mostrarse en la Grilla que tiene por nombre "grillaPrestamo" (componente TDBGrid). ¿Cómo puedo hacer para que en la grilla me muestre los datos del libro encontrado? y además de ello, poder registrar OTRO libro, y otro más. Es muy utilizada en búsquedas incrementales (no muy eficientes) la cuál podes implementar de este modo: 1) Un IBQuery asociado a un DataSource y un TDBGrid asociado al anterior.

TIBDataBase <- TIBTransaction <- TIBQuery <- TDataSource <- TTDBGrid

Agregar un TEdit con este código en su evento OnChange:

procedure TForm1.Edit1Change(Sender: TObject); begin with IBQuery1 do begin Close; SQL.Text:= 'Select * From libros Where isbn_lib like :xisbn'; ParamByName('xisbn').AsString:= '%' + Edit1.Text + '%'; Open; end; end;

Así a medida que vas ingresando caracteres en el Edit se va filtrando el resultado y se ve reflejado en el TDBGrid. Buscar valores más cercanos Tengo la necesidad de buscar en una tabla (Firebird) por un campo que es numérico y tengo que buscar en un momento determinado los valores más 'próximos'. Por próximos quiero decir los valores que se acercan más a un valor, tanto por delante como por detrás.

Page 66: Full Delphi

Ejemplo: Si tengo una tabla con el campo1 tipo Integer y con estos datos. Campo1 = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 Como podría buscar u obtener la tabla ordenada por el criterio de proximidad a un valor, por ejemplo del 5: Campo1= 4, 6, 7, 3, 8, 2, 9, 1, 10

Select campo1, Case When (campo1 - :valor) > 0 Then campo1 – :valor Else -1 * (campo1 - :valor) From tabla Order By 2

Agregar Nombre a las columnas de Un TDBGrid en Tiempo de Ejecución No encuentro la manera de agregar nombre a las columnas de un TDBGrid en tiempo de ejecución.

procedure TForm1.Button1Click(Sender: TObject); begin TDBGrid1.Columns[1].Title.Caption:='Clientes'; end;

Agrupar datos

Tengo una tabla de devoluciones al Almacén y esta es su detalle, en la consulta que necesito, quiero agrupar los artículos que tengan la misma característica en cuanto a Nombre, Largo y Ancho.

Folio Nombre Cantidad Largo Ancho Fecha

1.1 Cartulina doble 5 1200 0.140 02/06/03

2.1 Cartulina doble 7 1200 0.140 03/06/03

2.2 Jac Cromo 5 1000 0.110 03/06/03

3.1 Laminado 2 1000 0.120 09/06/03

4.1 Couche 7 1500 0.150 01/07/03

4.2 Laminado 2 1000 0.120 01/07/03

4.3 Jac Cromo 9 1000 0.110 01/07/03

Select nombre, largo, ancho, Sum(cantidad), Min(fecha), Max(fecha) From tutabla Group By nombre, largo, ancho

Page 67: Full Delphi

TQuery con parámetro

Existen 2 tipos de acceso a Parámetros: en diseño y con código. En diseño se recurre a la propiedad Params del Query. Se abre su editor y aparece su ventana.

Debemos asignar Type: String; Nombre del Parámetro, y su valor Unknown, luego en código podemos hacer referencia a él a través de QueryX.Params[0] asignándole el valor actual. Previo a esto debemos:

Query.Close; Cerrar

Query.Clear; Limpiar

Params[0].Value:=XXX; Asignar el parámetro

Query.SQL.Add('Select campos From table Where campo = :XXX');

Estamento SQL

Query.Open; Abrir

No debemos olvidar si el valor del Query pasa a un ClientDataSet de cerrar y abrir este también para que se renueven los datos que este último envía al DataSource que a su ve los pasa al TDBGrid. Si es por código debemos usar un valor más exacto al parámetro, para ello nos apoyamos en un campo explícito. Para esto usamos la localización del parámetro.

Query1.ParamByName('ParamName').AsMoldeador:='ValorActuall';

Usando TIBQuery:

begin with IBQuery1 do begin Close;

Page 68: Full Delphi

SQL.Text:= 'Select * From wb Where Item Starting With :cInicial'; ParamByName('cInicial').AsString := cIni; Open; end; end;

Usando TIBDataSet:

begin with IBDataSet1 do begin Close; SelectSQL.Text:= 'Select * From wb Where Item Starting With:cInicial'; ParamByName('cInicial').AsString := cIni; Open; end; end;

La ventaja del TIBDataSet es que dando valor a la propiedad SelectSQL en diseño, te permite usar la herramienta DataSetEditor, con la que podrás generar con muy poca intervención las sentencias para insertar, modificar y borrar datos. Esto no es así para el TIBQuery donde tendrás que definir las sentencias manualmente. Los parámetros se definen en la consulta y siempre se escriben precedidos por dos puntos ':'. La consulta se puede asignar en tiempo de diseño o en tiempo de ejecución. Si en tiempo de diseño, desde el Object Inspector, asignamos a la propiedad SQL el valor:

Select * From tabla Where name = :pname

Se habrá creado un parámetro llamado "pname", cosa que podes comprobar desde el mismo Object Inspector haciendo clic sobre los '...' de la propiedad Params. Habiendo sido creado la consulta y su parámetro, se puede llamar bien por su propiedad vectorial Params:

with IBQuery1 do begin Close; Params[0].AsString := Edit1.Text; Open; end;

O bien mediante el método ParamByName:

Page 69: Full Delphi

with IBQuery1 do begin Close; ParamByName('pname').AsString := Edit1.Text; Open; end;

De otro modo, si consulta y parámetro son creados en tiempo de ejecución, se deben especificar ambos, mediante la propiedad vectorial Params:

with IBQuery1 do begin Close; SQL.Text := 'Select * From tabla Where name = :pname'; Params[0].AsString := Edit1.Text; Open; end;

Mediante el método ParamByName:

with IBQuery1 do begin Close; SQL.Text := 'Select * From tabla Where name = :pname'; ParamByName('pname').AsString := Edit1.Text; Open; end;

Y es mediante la propiedad ParamValue:

with IBQuery1 do begin Close; SQL.Text := 'Select * From tabla Where name = :pname'; Params.ParamValues['pname'] := Edit1.Text; Open; end;

Por último cabe acotar que si existe una definición de consulta/parámetros en tiempo de diseño, al asignar una nueva definición de consulta/parámetros en tiempo de ejecución, se sobrescribirá lo realizado en tiempo de diseño.

Page 70: Full Delphi

Consulta con varias tablas

Tengo que generar una consulta que une 3 tablas: Horarios, Citas y Pacientes. En Horarios se encuentra una lista de "horas" para un día de la semana X: 9:00, 9:30, 10:00...19:30 en fin las horas de inicio de las citas (cada 30Min) y cada una tiene un IDHorario único. En Citas tengo los campos: IdCita, fecha, IdHorario y ID Paciente. En Pacientes tengo IdPaciente, Nombre. Lo que Quiero Obtener es una consulta (simplificando las cosas) que tenga para una fecha dada:

idHorarios.Hora IdPaciente.Nombre

9:00 <null>

9:30 Pedro Perez

10:00 <null>

.... ....

19:30 <null>

Select h.hora, p.nombre, p.apellido From horarios h Left Join citas c On h.idhorario = c.idhorario Left Join pacientes p On c.idpaciente = p.idpaciente Where diasem = 1 And idarea = 1

Query con 3 tablas

Tengo un sistema para llevar remisiones (facturas), productos, clientes, etc.; el problema está en que estoy haciendo una pantalla donde tengo un TDBGrid,, cuando remisiono un producto o más, guardo la clave de cliente que remisiona, guardo la clave de producto, y la cantidad de producto, esto se guarda en detalle remisión, ahora lo que quiero hacer es jalar en la pantalla, el nombre de cliente, su saldo, y la cantidad acumulada que ha sumado el cliente de todas sus remisiones, solo me tiene que mostrar la cantidad de ciertos productos (específicamente del 1 y 2), Les diré que tablas son con las que interactuó en esa pantalla. Solo pondré los campos que necesitamos. Clientes (cvecli, razso(es el nombre), saldo) Remisiones (cverem, cvecli) Detalle_remision(cverem, cvepro(clave del producto), cantidad)

Select cverem, Sum(canti), c.cvecli, c.razso, c.saldo From remisiones r, detalle_remision d, clientes c Where r.cverem = d.cverem And r.cvecli= c.cvecli Group By cverem

Select clientes.cvecli, clientes.razso, Sum(detalle_remision.cantidad) As cantidadtotal, clientes.saldo From clientes

Page 71: Full Delphi

Inner Join remisiones On clientes.cvecli=remisiones.cvecli Inner Join detalle_remision On remisiones.cverem=detalle_remision.cveremv Group By clientes.cvecli, clientes.razso, clientes.saldo

Query con 2 o más tablas Debo mostrar en un TDBGrid, los datos de la consulta de un Query, los registros de caja, pero en vez de los códigos de cliente y cobrador debe mostrar sus nombres, para eso deberé tomar el código de caja y localizar en las otras 2 tablas sus nombres.

Select a.idcaja, b.cliente, c.colaborador From cajas as a Inner Join clientes As b On b.idcliente = a.clienteid Inner Join colaboradores As c On c.idcolaborador = a.colaboradorid

Ocultar columnas en TTDBGrid

Tengo un TDBGrid donde mostraré los datos de una serie de sentencias SQL, que dado el valor de un TComboBox, se debe o no mostrar una columna de la rejilla, es decir, si el valor del TComboBox es "Mostrar", se mostrará la columna, si es "Esconder" o ningún valor, la columna no debe aparecer en el TDBGrid.

TDBGrid1.Columns[0].Visible := False;

Realizar búsqueda en Firebird

Tengo una tabla en Firebird 2.5, y quiero realizar dos tipos de búsqueda: El primero por el código (campo clave) y el segundo es por nombre de producto. Un ejemplo con TIBDataSet:

procedure TForm1.Edit1Change(Sender: TObject); begin IBDataSet1.Close; IBDataSet1.SelectSQL.Text:= 'Select * From productos Where nombre Like :buscado'; IBDataSet1.ParamByName('buscado').AsString:= Edit1.Text+'%'; IBDataSet1.Open; end;

Toma en cuenta que en este caso la cadena SQL que originalmente le asignaste a la propiedad SelectSQL es reemplazada por cada nueva asignación.

Page 72: Full Delphi

TDBGrid con campo de numeración

Hacer clic derecho en el TDBGrid y elija Columns Editor....

En Columns Editor.... mostrado, hacer clic con el botón derecho y elija la opción Add All Fields, o pulsa el botón rodeado en rojo mostrado en la imagen.

Se agregarán las columnas persistentes al TDBGrid según los campos detectados de su DataSet, agregue otra columna a TDBGrid1, y muévalo hacia arriba.

Dé un título esta nueva columna. Use la propiedad Title.Caption de la columna para hacer esto.

Page 73: Full Delphi

Ahora localize en el TDBGrid el evento OnDrawColumnCell en el Object Inspector, y haga doble clic y pege lo siguiente.

procedure TFormMain.TDBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); var vTDBGrid: TTDBGrid absolute Sender; begin if DataCol=0 then vTDBGrid.Canvas.TextOut(Rect.Left + 2, Rect.Top + 2, IntToStr(vTDBGrid.DataSource.DataSet.RecNo)); end;

Consulta con dos tablas Tengo dos tablas una se llama "Correo_Contactos" y la otra "Correo_Entrada"

Correo_Contactos Correo_Entrada

nombre correo

correo mensaje

cod

Como hago para que me muestre todos los correo recibidos sin importar si los tengo agregados.

Page 74: Full Delphi

Select correo_contactos.nombre, correo_contactos.correo, correo_entrada.mensaje From correo_entrada Left Join correo_contactos On correo_contactos.correo = correo_entrada.correo

Store Procedure en Consulta Es posible utilizar un Store Procedure dentro de una sentencia SELECT, osaldoafcxc(a.clv_clie,:fecha) es un procedimiento que me devuelve el saldo a fecha de un cliente.

Select a.clv_clie, a.no_fact, (select * From osaldoafcxc(a.clv_clie,:fecha)) From cuent1 a , conc1 b Where b.tipo = 'c' And a.tipo_mov = b.num_cpto And b.con_refer = 'n'

Pintar TDBGrid dependiendo del valor de un registro Tengo un Cd con un campo que tiene un valor y dependiendo de ese valor pongo el color de la fila. Crea una nueva aplicación, agrega un TClientDataSet, un TDataSource, un TTimer un TTDBGrid, luego haz doble clic sobre el TClientDataSet, Clic botón derecho -> Clic sobre "New Field..." Name: OR_TIPO, Type: Integer, Clic sobre botón Ok. Asocia el TDBGrid al DataSource y este al ClientDataSet para poder visualizar el resultado, y luego prueba este ejemplo:

implementation const MAX = 200; procedure TForm1.FormCreate(Sender: TObject); var i: Integer; begin Timer1.Enabled := False; Randomize; with ClientDataSet1 do begin CreateDataSet; Open; for i:= 1 to MAX do begin Append; FieldByName('OR_TIPO').AsInteger := Random(5)+1; Post;

Page 75: Full Delphi

end; First; end; Timer1.Interval := 3000; Timer1.Enabled := True; end;

procedure TForm1.Timer1Timer(Sender: TObject); var i: Integer; begin Timer1.Enabled := False; with ClientDataSet1 do begin DisableControls; try First; for i:= 1 to MAX do begin Edit; FieldByName('OR_TIPO').AsInteger := Random(5)+1; Next; end; First; finally EnableControls; end; end; Timer1.Enabled := True; end;

procedure TForm1.TDBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); var C : TColor; begin with Sender as TTDBGrid do begin case ClientDataSet1.FieldByName('OR_TIPO').AsInteger of 1: C:= clLime; 2: C:= clYellow; 3: C:= clMoneyGreen; 4: C:= clRed; 5: C:= clAqua; end; Canvas.Brush.Color := C;

Page 76: Full Delphi

DefaultDrawColumnCell(Rect, DataCol, Column, State); end; end;

Mostrar una tabla en un TDBGrid por código Como muestro la siguiente tabla en un TDBGrid, pero que sea por código.

id_materia

nombre

ihs

area

procedure TForm1.Button1Click(Sender: TObject); begin DataSource1.DataSet:= IBQuery1; TDBGrid1.DataSource:= DataSource1; with IBQuery1 do begin Database:= IBDatabase1; Transaction:= IBTransaction1; Close; SQL.Text:= 'Select id_materia, nombre, ihs, area From tu_tabla'; Open; end; end;

Llenar TDBGrid en tiempo de ejecución Necesito que me muestre solo una columna.

with TDBGrid1 do begin DataSource:= meta.DataSource; Columns.Clear; Columns.Add; // <- Agregar nueva columna Columns[0].FieldName:= 'TABLE_NAME'; Columns[0].Width:= 150; Columns[0].Title.Caption:= 'Nombre de la tabla'; Columns[0].Title.Color:= clLime; Columns[0].Color:= clMoneyGreen; end;

Page 77: Full Delphi

Ejecutar script SQL en firebird

Tengo un script nombre.sql, donde tengo varias órdenes de cambios en base de datos (Alter Table, Create Procedure, Insert Into, etc.), como se puede ejecutar un script SQL por código.

IBScript1.Script.LoadFromFile('archivo.sql'); IBScript1.ExecuteScript;

Ejecutar Script con IBSQL

Se puede ejecutar Script con el componente IBSQL, he intentado crear un Store Procedure y me falla la primera línea (SET TERM^), sin embargo cuando creo una Base de Datos todo es correcto, el mismo Script con IbExpert lo crea perfectamente. Si, sólo es necesario que pongas la propiedad ParamCheck a False antes de ejecutarlo.

with IBSQL1 do begin Close; ParamCheck:= False; SQL.Add('Create Procedure sp_pi Returns(Result Double Precision)'); SQL.Add('As'); SQL.Add('begin'); SQL.Add('result = ''3.141592654'';'); SQL.Add('end'); ExecQuery; end;

Luego:

IBStoredProc1.StoredProcName:= 'SP_PI'; IBStoredProc1.ExecProc; ShowMessage(FloatToStr(IBStoredProc1.Params[0].Value));

Ocultar columna en TDBGrid Como se oculta una columna en tiempo de ejecución en el TDBGrid En el TDBGrid existe una propiedad llamada Columns que es un array que contiene todas las columnas que existen en el TDBGrid. Si pones la columna que quieres (piensa que el array tiene base 0) su propiedad Visible a false, esta desaparecerá.

TDBGrid1.Columns[x].Visible:=False;

Page 78: Full Delphi

Seleccionar un Ítems en ComboBox y añadir muchos registros en tabla

Tengo una BD en Access conectada con un ADOQuery, esta contiene una tabla provincias con los campos provincia, id_prov otra tabla llamada ciudades con los campos ciudad, id_ciudad, id_prov. Quiero seleccionar una provincia desde un ComboBox y que en una tabla nueva ya creada con un campo ciudades y otros campos, me copie todas las ciudades de la provincia elegida en el campo ciudades.

Insert Into nueva_tabla (campo1, campo2) Select campo1, campo2 From ciudades Where id_prov = :id_prov

Agregar datos al TDBComboBox en ejecución Tengo un TDBComboBox que se llama año, por medio de la propiedad Ítems, están agregados los años desde 1900 hasta 2013, un botón modificar y que pueda agregarle más años al TDBComboBox, pero ejecutándose programa. Para insertar al inicio el ítem usa:

DBComboBox1.Items.Insert(0, '2014');

Para que los ítems agregados se guarden usa esto:

DBComboBox1.Items.SaveToFile('c:\dbcomboboxitems.txt');

Y para cargar los ítems que guardaste usa esto:

if FileExists('c:\dbcomboboxitems.txt') then DBComboBox1.Items.LoadFromFile('c:\dbcomboboxitems.txt');

TDBGrid: Mostrar un campo u otro dependiendo de una condición

Tengo una tabla con dos campos nombre: "nombre" y "nombre_nuevo" y un TDBGrid donde una de las columnas tiene el FieldName=nombre. Lo que pretendo es que si el campo nombre está vacío me muestre el campo nombre_nuevo.

procedure TPadronBuscaHistoria.GridHistoriaDrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); begin if (DataCol = 5) and (Trim(QueryHa.FieldByName('nombre').AsString) = '') then begin GridH.Canvas.TextRect(Rect,Rect.Left + 8, Rect.Top+5, QueryH.FieldbyName('nombre_nuevo').AsString); end; end;

Page 79: Full Delphi

Columnas de DBGrid en tiempo de ejecución

En tiempo de ejecución creo en un DBGrid de 2 columnas a las cuales les asigno un campo de una tabla, el problema es que quiero cambiar el título de las columnas.

dbgListado.Columns[0].Title.Caption:='Codigo'; dbgListado.Columns[1].Title.Caption:='Nombre';

Consulta de dos tablas Tengo dos tablas, Camiones con los campos ID_CAMION, MARCA, MODELO y la tabla Códigos con los campos ID_CODIGO, ID_CAMION, CODIGO. Que registros de la tabla camiones no figuran ninguna vez en la tabla códigos, es decir el que ID_CAMION de la tabla Camiones no tenga correspondencia con ningún valor de la tabla códigos. Ejemplo

Tabla Camiones Tabla Códigos

ID_Camion Marca Modelo ID_Codigo ID_Camion Código

1 Mercedes Atego 1528 1 1 23

2 Pegaso 1180

3 Iveco Trakker

4 Mecedes Atego 1528 2 3 40

En la consulta deberían aparecer los registros 2 y 4 de la tabla camiones.

Select * From bom0001 Where id_camion Not In (Select id_camion From bom0001a)

Consulta de varios registros y como resultado varias columnas Tengo la siguiente tabla:

Código Lectura Fecha

001 3400 01/01/2008

001 3600 01/02/2008

001 3350 31/12/2007

002 1500 01/01/2008

002 1600 01/02/2008

002 1250 31/12/2007

003 1000 31/12/2007

003 0950 01/11/2007

004 1000 01/11/2007

004 1250 31/12/2007

Se necesita hacer una consulta que genere la salida, suministrando como parámetro fecha1 y fecha2: Parámetros: fecha1: 01/01/2008 - fecha2: 01/02/2008

Page 80: Full Delphi

Código Fecha1(01/01/2008) Fecha2(01/02/2008) Consumo

001 3400 3600 200

002 1500 1600 10

Explicación: En el caso del primer código (001): Reg. No. 1: 001-3400-3600-200 La primera columna: es el código que se encuentra en la tabla. (001) La segunda columna: corresponde a la lectura que coincide con la fecha1. (3400) La tercera columna: corresponde a la lectura que coincide con la fecha2. (3600) La cuarta columna: se debe generar la resta de la tercera columna con la segunda columna (3600-3400)=200 y así continúa con el código (002) y fíjense que las lecturas con fecha que no están indicadas, no se muestran en la salida (como lo es el caso de las lecturas con fecha: 31/12/2007.

Select d.ruta As ruta,d.codigo_do As codigo_do,sus.nombre_fiscal As nombre, d.descripcion As direccion, t1.lectura, t2.lectura, (t1.lectura-t2.lectura) As consumo, t1.fecha, t2.fecha From direccion_operacional d Left Outer Join suscriptores sus On sus.id = d.id_suscriptor Left Outer Join lecturas t1 On t1.codigo_do=d.codigo_do Left Outer Join lecturas t2 On t2.codigo_do=d.codigo_do Where (t1.fecha= :fecha1 And t2.fecha= :fecha2) And (d.tipo_tarifa=:tarifa) And (d.ruta>=:ruta1 And d.ruta<=:ruta2)

Consulta de artículos vendidos en un día

Necesito hacer es una consulta la cual me permita obtener los artículos vendidos en un día. Lo que hago es lo siguiente: seleccionó un rango de fecha, desde/hasta y me devuelve todos los registros vendidos desde que se implementó el sistema, y no es lo que necesito. Realizo la consulta sobre las tablas facturas que contiene los siguientes campos, nrofactura, fecha, total, tipo_fac y la tabla detalles, que contiene los siguientes campos, id_det, descripcion, subtotal, cantidad, nrofactura.

Select b.descripcion, Sum(b.cantidad) From tfacturas a Inner Join tdetalles b On a.nrofactura=b.nrofactura Where a.fecha Between :vfec1 And :vfec2 Group By b.descripcion

Consulta para conocer la cantidad de ventas

Tengo una tabla MySQL donde se refleja por cada ítems de compra un número de ventas, lo que sucede es que este número de ventas se repite para cada registro, por ejemplo si un cliente compra 4 productos en una venta (facturas) los 4 registros obtienen el mismo número de la venta, pero la venta sería una sola, como puedo hacer con una consulta para conocer la cantidad de ventas de un cliente (ventas

Page 81: Full Delphi

físicas en el ejemplo sería 1 y 4), porque lo que estoy obteniendo es la cantidad de ítems de la venta.

Select cliente, Count(Distinct numeroventa) From ventas Group By cliente

Consulta la cantidad de ventas

Se trata de un informe en el cual tengo que mostrar mediante un Group By todos los artículos de la base de datos con sus cantidades vendidas respectivamente. Por ejemplo tengo las siguientes tablas (simplificadas), también me gustaría poder filtrar por fecha o mes (realizando la misma consulta).

LineaVta Artículos

CodArticulo CodArticulo

Cantidad Nombre

Select nombre, codigo, Sum(cantidad) From LineaVta, Articulos Where LineaVta.CodArticulo = Articulos.CodArticulo Group By nombre, codigo

Consulta por Múltiples campos Tengo un panel con varios campos y un DBGrid, lo que necesito es realizar una consulta no importa cual campo este lleno, puede ser uno como todos, algunos o nada (en la condición de nada debería traer todos los registros): numero, nombre, apellido, documento.

with tu_Query do begin Close; SQL.Clear; SQL.Add('Select * From tu_tabla'); SQL.Add('Where numero campo1 :p1 And nombre Like :p2'); SQL.Add('and apellido Like :p3 And documento Like :p4'); ParamByName('p1').AsString := Edit1.Text + '%'; ParamByName('p2').AsString := Edit2.Text + '%'; ParamByName('p3').AsString := Edit3.Text + '%'; ParamByName('p4').AsString := Edit4.Text + '%'; Open end;

Page 82: Full Delphi

Buscar un registro por diferentes campos

Necesito buscar un registro dentro de una tabla pero por diferentes campos, os explico tengo un Form con un DBGrid en el que se van colocando los registros seleccionados, este Form tiene un Edit en el que tecleo el nombre, la licencia, el DNI o el código UCI y mediante una consulta filtro los registros que cumplan la condición para poder elegir el que corresponda, por ejemplo si tecleo Gómez, me manda en un For auxiliar todos los registros que empiezan por Gómez, si tecleo 12345678 me busca primero en el nombre, como no lo encuentra tendría que buscar en el DNI pero me devuelve la consulta en blanco.

procedure TF_Inscripcions.Edit1KeyPress(Sender: TObject; var Key: Char); begin If (Key=#13) then begin Bsr:=TBuscar.Create(Application); Bsr.Close; Bsr.SQL.Clear; Bsr.SQL.Add('Select dorsal, nom_llarg, dni, licencia, codiuci, nacio, club, edat,'); Bsr.SQL.Add('abr_club, publicitat, categoria From ctr0003'); Bsr.SQL.Add('Where nom_llarg Starting :nom Or dni Starting :nom'); Bsr.SQL.Add('Or llicencia Starting :nom Or codiuci Starting :nom'); Bsr.SQL.Add('Order By nom_llarg'); Bsr.ParamByName('nom').AsString:=Edit1.Text; Bsr.Open; Bsr.Show; end; end;

Cálculo de horas laborales

Función que cuenta las horas laborales entre dos fechas, descontando los días del fin de semana y los días festivos. Para ello, hay que indicarle la fecha y hora de inicio y de fin, las horas de comienzo y fin del horario, y hay que tener en una tabla los festivos (festivos es el nombre de la tabla), para que pueda descontar esos días. Es útil para por ejemplo medir las horas de cualquier servicio.

SET TERM ^; CREATE OR ALTER PROCEDURE tiempoentrefechas ( fi TimeStamp, ff TimeStamp, hih Time, hfh Time) RETURNS (tiempo Float) AS Declare Variable nfi, nff, wi, wf TimeStamp; Declare Variable syd, fes, syd Integer; Declare variable tw, horas, tiempodia1, tiempodia2 Float; Declare variable taf float, tff Float;

Page 83: Full Delphi

begin nfi= fi; nff= ff; /* Adecuamos la fecha y hora de inicio respecto al fin del horario */ if (Cast(nfi As Time) > hfh) then nfi= Cast(nfi+1 As Date) + hih; /* Adecuamos la fecha y hora de inicio respecto al inicio del horario */ if (Cast(nfi As Time) < hih) then nfi= Cast(nfi As Date) + hih; /* Adecuamos la fecha y hora de inicio respecto a los fines de semana */ if (Extract(WeekDay From nfi) = 6) then /* Sabados*/ nfi= Cast(nfi+2 As Date)+ hih; if (Extract(WeekDay From nfi) = 0) then /* Domingos*/ nfi= Cast(nfi+1 As Date)+ hih; /* Adecuamos la fecha y hora de fin respecto al fin del horario */ if (Cast(nff As Time)> hfh) then nff= Cast(nff As Date)+hfh; /* Adecuamos la fecha y hora de fin respecto al inicio del horario */ if ( Cast(nff As Time) < hih) then nff= Cast(nff-1 As Date)+hfh; /* Adecuamos la fecha y hora de fin respecto a los fines de semana */ if (Extract(WeekDay From nff) = 6) then /* Sabados */ nff= Cast(nff-1 As Date)+ hfh; if (Extract(WeekDay From nff) = 0) then /* Domingos*/ nff= Cast(nff-2 As Date)+ hfh; /* Calculamos los días de fin de semana */ syd =((DatedIff(Day, nfi, nff)+Extract(WeekDay From nfi) )/7) *2; /* Calculamos todos los días sin fines de semana. Hay que quitarle un día... */ tw = DatedIff( Day, nfi, nff) -1 - syd; if (tw < 0) then tw=0; tff = tw; -- Días transcurrido * horasDia + horas de primer día + horas del ultimo día taf = tw * DatedIff( Minute ,hih, hfh) /60.00 + DatedIff(Minute, Cast(nfi As Time), hfh)/60.00 + DatedIff(Minute, hih, Cast(nff As Time))/60.00 ; /* Quitamos los fes sin incluir los días de inicio y fin, que tratamos luego */

Page 84: Full Delphi

Select Count(1) From fes Where dia Between Cast(:nfi As Date)+1 And Cast(:nff As Date)-1 And Extract(WeekDay From dia) Not In (0,6) Into :fes; tw= tw - fes; /* Calculamos el tiempo transcurrido en horas */ if ( DatedIff(Day, nfi, nff) = 0) then -- si es el mismo día tiempo= DatedIff( Minute, Cast(nfi As Time), Cast(nff As Time)) / 60.00; else // Dias transcurridos * horasDia + horas de primer día + horas del ultimo día tiempo= tw * DatedIff(Minute ,hih, hfh) /60.00 + DatedIff(Minute, Cast(nfi As Time), hfh)/60.00 + DatedIff(Minute, hih, Cast(nff As Time))/60.00 ; -- si el primer día es festivo y no es sábado ni domingo, restamos las horas fes = 0; Select Count(1) From fes Where dia=Cast(:nfi As Date) And Extract(WeekDay From dia) Not In (0,6) Into :fes; if (fes =1) then tiempo=tiempo - DatedIff(Minute, Cast(nfi As Time), hfh)/60.00; -- si el ultimo día es festivo y no es sábado ni domingo, restamos las horas fes = 0; Select Count(1) From fes Where dia=Cast(:nff As Date) And Extract(WeekDay From dia) NOT IN (0,6) INTO :fes; if (fes =1) then tiempo=tiempo - DatedIff( Minute, hih, Cast(nff As Time))/60.00; /* Para trazar cuando estoy desarrollando */ horas = (DatedIff(Minute ,hih, hfh))/60.00; tiempodia1=DatedIff(Minute, Cast(nfi As Time), hfh)/60.00; tiempodia2=DatedIff(Minute, hih, Cast(nff As Time))/60.00; wf = nff; wi= nfi; syd= syd; tiempo= tiempo; if (tiempo < 0 or (tiempo IS NULL)) then tiempo=0; suspend; end^ SET TERM ;^ Grant Select On fes TO PROCEDURE tiempoentrefechas; Grant EXECUTE ON PROCEDURE tiempoentrefechas TO SYSDBA;

Page 85: Full Delphi

Consulta de 2 tablas y dar resultado en un DBGrid

Estoy utilizando dos tablas: vehículos y bitacoravehiculos, quiero que al realizar la consulta me muestre algunos campos de ambas tablas en un DBGrid, de esta manera: para relacionar las dos tablas, utilizo el campo (nave) que existe en ambas tablas, de la tabla Vehículos, solo quiero nave (que es la llave primaria) y de la tabla bitacoravehiculos me muestre los campos: fserv, cserv, crep, nfac, dcom, litros, importe, imptot, para que al ejecutar el formulario de trabajo, al seleccionar un vehiculo me muestre todo su historial de reparaciones y servicios en un DBGrid, por ejemplo: Vehículos

nave Placas Marca

01 GY01514 Chevrolet

02 GA02133 Nissan

BitacoraVehiculos*

nave FServ CServ Importe ImporteTotal

01 26/07/2006 Cambio de llantas $700.00 $700.00

01 28/07/2006 Cambio de balatas $800.00 $1500.00

02 20/08/2006 Cambio de aceite $100.00 $100.00

Resultado después de la consulta, si selecciono solo el vehículo 01:

nave FServ CServ Importe ImporteTotal

01 26/07/2006 Cambio de llantas $700.00 $700.00

01 28/07/2006 Cambio de balatas $800.00 $1500.00

Resultado después de la consulta, si selecciono solo el vehículo 02:

nave FServ CServ Importe ImporteTotal

02 20/08/2006 Cambio de aceite $100.00 $100.00

Select v.nave, b.fser, b.cserv, b.crep, b.nfac, b.dcom, b.litros, b.importe, b.imptot From vehículos v, bitacoraVehiculos b Where v.nave = b.nave Order By b.fserv

Además le cargas todos los campos al Query (doble clic sobre el componente TQuery, clic derecho sobre la ventana que se abre, y clic en AddAllFields) y si quieres personalizar el DBGrid1 (Doble clic sobre el DBGrid, creas columnas, y a éstas le seleccionas el nombre del campo en la propiedad DataField).

Page 86: Full Delphi

Agrupar datos de una tabla

La tabla, en la que tengo un ID del recibo y los detalles de los mismos. CREATE TABLE RE0010DG( "ID_REBUT" INTEGER NOT NULL, "ID_ARBIT1" INTEGER, "ID_ARBIT2" INTEGER, "ID_ARBIT3" INTEGER, "ID_ARBIT4" INTEGER, "ID_ARBIT5" INTEGER, "ID_ARBIT6" INTEGER, "ID_ARBIT7" INTEGER, "ID_ARBIT8" INTEGER, "KM1" INTEGER, "KM2" INTEGER, "KM3" INTEGER, "KM4" INTEGER, "KM5" INTEGER, "KM6" INTEGER, "KM7" INTEGER, "KM8" INTEGER, "SOBRES_1" NUMERIC(9, 2), "SOBRES_2" NUMERIC(9, 2), "SOBRES_3" NUMERIC(9, 2), "SOBRES_4" NUMERIC(9, 2), "SOBRES_5" NUMERIC(9, 2), "SOBRES_6" NUMERIC(9, 2), "SOBRES_7" NUMERIC(9, 2), "SOBRES_8" NUMERIC(9, 2), "IMPORT_1" NUMERIC(9, 2), "IMPORT_2" NUMERIC(9, 2), "IMPORT_3" NUMERIC(9, 2), "IMPORT_4" NUMERIC(9, 2), "IMPORT_5" NUMERIC(9, 2), "IMPORT_6" NUMERIC(9, 2), "IMPORT_7" NUMERIC(9, 2), "IMPORT_8" NUMERIC(9, 2), "IMPORT_KM_1" NUMERIC(9, 2), "IMPORT_KM_2" NUMERIC(9, 2), "IMPORT_KM_3" NUMERIC(9, 2), "IMPORT_KM_4" NUMERIC(9, 2), "IMPORT_KM_5" NUMERIC(9, 2), "IMPORT_KM_6" NUMERIC(9, 2), "IMPORT_KM_7" NUMERIC(9, 2), "IMPORT_KM_8" NUMERIC(9, 2), "CAMPIONAT1" NUMERIC(9, 2),

Page 87: Full Delphi

"CAMPIONAT2" NUMERIC(9, 2), "CAMPIONAT3" NUMERIC(9, 2), "CAMPIONAT4" NUMERIC(9, 2), "CAMPIONAT5" NUMERIC(9, 2), "CAMPIONAT6" NUMERIC(9, 2), "CAMPIONAT7" NUMERIC(9, 2), "CAMPIONAT8" NUMERIC(9, 2), "FEINER1" NUMERIC(9, 2), "FEINER2" NUMERIC(9, 2), "FEINER3" NUMERIC(9, 2), "FEINER4" NUMERIC(9, 2), "FEINER5" NUMERIC(9, 2), "FEINER6" NUMERIC(9, 2), "FEINER7" NUMERIC(9, 2), "FEINER8" NUMERIC(9, 2), "DOS_SECTORS1" NUMERIC(9, 2), "DOS_SECTORS2" NUMERIC(9, 2), "DOS_SECTORS3" NUMERIC(9, 2), "DOS_SECTORS4" NUMERIC(9, 2), "DOS_SECTORS5" NUMERIC(9, 2), "DOS_SECTORS6" NUMERIC(9, 2), "DOS_SECTORS7" NUMERIC(9, 2), "DOS_SECTORS8" NUMERIC(9, 2), "TOTAL_A1" NUMERIC(9, 2), "TOTAL_A2" NUMERIC(9, 2), "TOTAL_A3" NUMERIC(9, 2), "TOTAL_A4" NUMERIC(9, 2), "TOTAL_A5" NUMERIC(9, 2), "TOTAL_A6" NUMERIC(9, 2), "TOTAL_A7" NUMERIC(9, 2), "TOTAL_A8" NUMERIC(9, 2), "A1" VARCHAR(1) CHARACTER SET ISO8859_1 COLLATE ES_ES, "A2" VARCHAR(1) CHARACTER SET ISO8859_1 COLLATE ES_ES, "A3" VARCHAR(1) CHARACTER SET ISO8859_1 COLLATE ES_ES, "A4" VARCHAR(1) CHARACTER SET ISO8859_1 COLLATE ES_ES, "A5" VARCHAR(1) CHARACTER SET ISO8859_1 COLLATE ES_ES, "A6" VARCHAR(1) CHARACTER SET ISO8859_1 COLLATE ES_ES, "A7" VARCHAR(1) CHARACTER SET ISO8859_1 COLLATE ES_ES, "A8" VARCHAR(1) CHARACTER SET ISO8859_1 COLLATE ES_ES, "F1" VARCHAR(1) CHARACTER SET ISO8859_1 COLLATE ES_ES, "F2" VARCHAR(1) CHARACTER SET ISO8859_1 COLLATE ES_ES, "F3" VARCHAR(1) CHARACTER SET ISO8859_1 COLLATE ES_ES, "F4" VARCHAR(1) CHARACTER SET ISO8859_1 COLLATE ES_ES, "F5" VARCHAR(1) CHARACTER SET ISO8859_1 COLLATE ES_ES, "F6" VARCHAR(1) CHARACTER SET ISO8859_1 COLLATE ES_ES, "F7" VARCHAR(1) CHARACTER SET ISO8859_1 COLLATE ES_ES, "F8" VARCHAR(1) CHARACTER SET ISO8859_1 COLLATE ES_ES);

Page 88: Full Delphi

Necesitaría poder sacar los datos agrupados por id_arbitre pero el problema es que el valor de este ID, puede estar en cualquiera de las 8 columnas posibles. Vamos que lo que necesitaría es poder sacar todos los registros donde aparezca por ejemplo el valor del árbitro 1, algo así: y sucesivamente, para sacar una hoja por cada árbitro.

Arbitro 1 Arbitro 2

Recibo 1 Recibo 1

Recibo 3 Recibo 2

Recibo 5 Recibo 3

El problema que tengo y que no sé cómo solventar es que el valor del id_arbitre = 1 puede estar tanto en id_arbitre_1, id_arbitre_2, id_arbitre_3, id_arbitre_4, ID_arbitre_5, id_arbitre_6, id_arbitre_7, id_arbitre_8, pero solo una vez en cada recibo. Luego todos los campos adicionales son los que tienen el mismo numero id_arbitre_1 -> km_1 -> total_1, etc.

Select id_arbit1, id_rebut, import_1, sobres_1, import_km_1, campionat1, feiner1, dos_sectors1, total_a1 From re0010dg Where id_arbit1 = 1 UNION Select id_arbit2, id_rebut, import_2, sobres_2, import_km_2, campionat2, feiner2, dos_sectors2, total_a2 From re0010dg Where id_arbit2 = 1 UNION Select id_arbit3, id_rebut, import_3, sobres_3, import_km_3, campionat3, feiner3, dos_sectors3, total_a3 From re0010dg Where id_arbit3 = 1 UNION Select id_arbit4, id_rebut, import_4, sobres_4, import_km_4, campionat4, feiner4, dos_sectors4, total_a4 From re0010dg Where id_arbit4 = 1 UNION Select id_arbit5, id_rebut, import_5, sobres_5, import_km_5, campionat5, feiner5, dos_sectors5, total_a5 From re0010dg Where id_arbit5 = 1 UNION Select id_arbit6, id_rebut, import_6, sobres_6, import_km_6, campionat6, feiner6, dos_sectors6, total_a6 From re0010dg Where id_arbit6 = 1 UNION Select id_arbit7, id_rebut, import_7, sobres_7, import_km_7, campionat7, feiner7, dos_sectors7, total_a7 From re0010dg Where id_arbit7 = 1 UNION

Page 89: Full Delphi

Select id_arbit8, id_rebut, import_8, sobres_8, import_km_8, campionat8, feiner8, dos_sectors8, total_a8 From re0010dg Where id_arbit8 = 1

Asignando sentencias SQL para modificar en IBDataSet

var filtro: String; begin Case AnsiIndexStr(equipo ,['rojo', 'verde']) of 0: filtro := 'juego_zona_uno=:juego_zona_uno,'; 1: filtro := 'juego_zona_dos=:juego_zona_dos,'; else begin ShowMessage('Equipo no inscrito'); exit; end; end; ibdtst.ModifySQL.Clear; ibdtst.ModifySQL.Add('Update torneo SET,'); ibdtst.ModifySQL.Add('clave=:clave,'); ibdtst.ModifySQL.Add(filtro); ibdtst.ModifySQL.Add('WHERE clave=clave,'); end;

Actualizar un campo vacío con el valor de otro

El archivo TXT en el que me mandan los corredores ciclistas desde la federación, está separado por comas y su formato es dorsal, nombre, apellido1, apellido2, etc., esto hasta aquí es correcto, luego yo importo estos datos a la tabla Firebird correspondiente y funciona, pero los corredores extranjeros que tienen un solo apellido, no figura en apellido1 sino en apellido 2, si hago una búsqueda a estos no los encuentro jamás ya que el valor es vacío, como ejemplo:

1 Josep Fernández Albert etc.

2 Lio Chin etc.

3 Johnny Walker etc.

4 Antonio Gómez Pérez etc.

Lo que yo necesitaría sería que una vez importados los datos a la tabla, pudiera recorrer la tabla y cambiar el valor de los registros 2 y 3 (que son los que están vacíos en apellido1) y que la tabla quedara así:

1 Josep Fernández Albert etc.

2 Lio Chin etc.

3 Johnny Walker etc.

4 Antonio Gómez Pérez etc.

Page 90: Full Delphi

Actualización:

Update corredores Set apellido1=apellido2, apellido2='' Where apellido1 Is Null

Búsqueda:

Select * From corredores Where apellido1 Like '%ernandez%' Or apellido2 Like '%ernandez%'

Editar Información de DBEdit y también en DBGrid Tengo una pequeña tabla de práctica, creada de la siguiente manera. CREATE TABLE USUARIO ( CODIGO CHAR(12) NOT NULL, NOMBRE CHAR(30), APELLIDO CHAR(30), CIUDAD CHAR(20), TELEFONO CHAR(12) ); Luego hicimos las conexiones a una forma, usando IBX, como se necesita, usando un TIBDataSet y unos DBEdit, conectamos la base de datos y un DBGrid usando un DataSource. Usando un IBQuery, hacemos una búsqueda en la tabla para buscar la información que ha sido digitada en el DBEdit. Cuando la información se encuentra en la tabla esta se debe poder Editar, y adicionalmente debo poder ver la información en el DBGrid. Como la información me la entrega un IBQuery, esta solo se puede mirar, pero no se puede entrar a editar en los otros DBEdit, debido a que los DBEdit no están mirando la tabla, sino la información del IBQuery, y mucho menos apuntando en el DBGrid. Creo que te va a resultar más simple utilizar el evento OnSetText del TField en cuestión:

type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); private procedure CampoSetText(Sender: TField; const Text: String); public end; implementation procedure TForm1.FormCreate(Sender: TObject);

Page 91: Full Delphi

begin IBDataSet1.FieldByName('CAMPO_BUSQUEDA').OnSetText:= CampoSetText; end; procedure TForm1.CampoSetText(Sender: TField; const Text: String); begin if not IBDataSet1.Locate('CAMPO_BUSQUEDA', Text, []) then Abort; end;

En el ejemplo asigno el evento en tiempo de ejecución; pero si tienes creados los campos persistentes lo podes hacer en diseño desde el Object Inspector. Consulta para insertar campo en una tabla si no existe

Buscando la manera de insertar un campo en una tabla pero verificando que éste no existiera previamente a través de un SP:

CREATE OR ALTER PROCEDURE InsertarCampo AS begin if (Not Exists(select 1 From RDB$Relation_Fields Where RDB$Relation_Name = 'tabla' And RDB$Field_Name = 'CAMPO')) then Execute Statement 'Alter Table tabla Add campo Integer'; end;

Problemas con Update

Tengo dos tablas, clientes y repartidores, y necesito hacer un Update en un campo de la tabla clientes cuando se cumpla la condición clientes.cod = repartidores.cod. El problema viene cuando quiero darle el valor a pelo, no el de un campo de la tabla, sino haría un Select sobre el campo y le daría el valor.

CREATE TABLE "CLIENTES" ( COD VARCHAR(20) NOT NULL, TRC CHAR(1) NOT NULL );

CREATE TABLE "REPARTIDORES" ( COD VARCHAR(20) NOT NULL );

Update clientes c Set c.trc = 's' Where c.cod In (Select "cod" From repartidores)

Page 92: Full Delphi

Relaciones uno a muchos en Firebird

Dispondremos del programa SQL manager lite for InterBase and Firebird. Una vez dentro del programa, tendremos por lo menos dos tablas, seleccionaremos la tabla que tendrá la relación muchos.

En la zona derecha del programa seleccionamos la ficha "Constraints" y dentro de esta ficha seleccionamos la ficha "Foreign Keys".

Seleccionaremos el campo que vamos a relacionar con la tabla foránea, "CONCEPTO", en el campo "Foreign Table" seleccionamos la tabla "CONCEPTO", dentro de ésta tabla seleccionamos el campo clave primaria "ID".

Finalizaos pulsando sobre el botón "Ok" y después sobre el botón "Compile".