Ordenação ClientDataSet...

Delphi

26/07/2004

Colegas..

preciso fazer uma ordenação num determinado número de registros de uma tabela, mas esta ordenação não pode ser passada via SQL, isto é, a ordenação é um campo inexistante na tabela..

assim :

Tenho um sequencial 00000001, 00000002, 0000003. (no banco)
No meio destes números pra ser mais preciso antes da segunda casa, na hora da impressão do sequencial eu adiciono três caracteres aleatórios :
007250000001, 001980000002, 009760000003.
Se eu ordenar por sequencial irá aparecer assim :

007250000001
001980000002
009760000003

mas preciso que apareça no rel assim :

001980000002
007250000001
009760000003

ordenada pelo sequencial adicionado os três caracteres..

lembrando não armazeno no banco de dados os três caracteres..

agradeço a atenção de todos

Cabelo


Cabelo

Cabelo

Curtidas 0

Respostas

Rafs

Rafs

26/07/2004

Caro colega,

Entendi que vc faz a inclusão destes três caracteres aleatórios imediatamente antes da impressão, sendo assim, sería necessário ter conhecimento de como vc efetua a impressão.
Porém se vc puder incluir estes três caracteres a ponto de serem visíveis pelo ClientDataSet, vc só precisará criar um índice na coluna que deseja ordenar e no ClientDataSet apontar o IndexFieldNames (ou IndexName) para o índice criado. Desta forma vc terá os seus dados ordenados como deseja.

Para qualquer dúvida, a disposição.


GOSTEI 0
Cabelo

Cabelo

26/07/2004

Colega..

Não entendi o que quis dizer, vc está me dizendo que preciso incluir estes três caracteres no banco de dados?? Ou seria uma outra tabela que contivesse os valores aplicados??

Cabelo


GOSTEI 0
Rafs

Rafs

26/07/2004

Colega,

Não quis me referir a você alterar no banco de dados, mas sim alterar localmente.
Ao utilizar o ClientDataSet é criado um cache dos dados que foram solicitados ao banco de dados, correto. Neste caso você podería incluir estes três caracteres localmente para depois efetuar a ordenação e a impressão conforme você deseja.
Acredito que sería nestes moldes:
-Resgataría os dados do banco de dados através do ClientDataSet
-Alteraría os registros, incluindo os três caracteres no campo desejado, no ClientDataSet
-Criaría o índice para o referido campo (IndexDefs)
-Ordenaría o ClientDataSet pelo índice criado (IndexFieldNames ou IndexName)
-Emitiría o relatório.

Apesar de ser um pouco trabalhoso, acredito que resolverá o seu problema.
Se vc puder me detalhar como vc emite o relatório (se linca direto com o ClientDataSet ou conecta a outro componente), talvez possamos descobrir uma forma mais fácil e prática de inserir estes caracteres e ordená-los corretamente.


GOSTEI 0
Cabelo

Cabelo

26/07/2004

Colega..

Como faria para inserir no cache do client, os caracteres, acho que é só isso que falta..

eu tinha imaginado exatamente isso, só não sei como executar..

agradeço sua atenção..

Cabelo


GOSTEI 0
Rafs

Rafs

26/07/2004

Para incluir estes caracteres, trabalhe com o ClientDataSet como se ele fosse uma TTable. Mas em hipótese alguma execute o ApplyUpdates, senão ele atualizará seu BD.
Um exemplo de código sería o seguinte:
var
  lRegistro: String;
begin
...
...
  ClientDataSet.First;
  while not ClientDataSet.Eof do begin
    lRegistro := ClientDataSet.FieldByName(´NomeCampo´).AsString;
    ClientDataSet.Edit;
    ClientDataSet.FieldByName(´NomeCampo´).AsString := 
      Copy(lRegistro,1,2)+CaracteresGerados+Copy(lRegistro,3,6);
    ClientDataSet.Post;
    ClientDataSet.Next;
  end;
...
...
end;

Declare a variável [i:383f866247]lRegistro[/i:383f866247] para poder alterar o conteúdo do ClientDataSet.
[i:383f866247]CaracteresGerados[/i:383f866247] será os caracteres que vc deverá gerar para incluir no campo desejado
Com o comando [b:383f866247]Copy[/b:383f866247] você inserirá os caracteres na posição que deseja (após a segunda casa, conforme no seu exemplo)
Pela sua primeira mensagem, entendi que o campo seja string.
Depois de atualizar o ClientDataSet, você precisará criar o índice e indexar o ClientDataSet pelo índice criado.
ClientDataSet.IndexDefs.Add(´NomeIndice´,´NomeCampo´,[]);
ClientDataSet.IndexFieldNames := ´NomeCampo´;

Desta forma você terá a ordenação que deseja.

:)


GOSTEI 0
Cabelo

Cabelo

26/07/2004

Colega Rafs..

O método Post no clientdataset não irá alterar o banco de dados? Pq com a TQuery do BDE no Delphi 5, quando vc utiliza o método Post, ele altera os dados na base..


Cabelo


GOSTEI 0
Rafs

Rafs

26/07/2004

Colega,

O método Post do ClientDataSet irá alterar somente os valores locais da máquina, mas não alterarão os dados do BD. Pois o ClientDataSet realiza um cache dos dados na máquina local. Para alterar os dados do BD, vc precisará chamar o método ApplyUpdates, por isso que coloquei para vc em [b:22869d16d2]hipótese alguma[/b:22869d16d2] chamar este método, senão o BD será alterado.
A TQuery do BDE não realiza cache dos dados, isto é, não armazena os dados na máquina local, assim, quando é chamado o método Post a TQuery se encarrega de atualizar o BD imediatamente.


GOSTEI 0
Cabelo

Cabelo

26/07/2004

Obrigado pela ajuda..

Vou tentar aqui..

Cabelo


GOSTEI 0
Cabelo

Cabelo

26/07/2004

Colega..

Fiz exatamente o quê vc sugeriu, mas não funcionou..

Ainda não resolvi o problema..

Cabelo


GOSTEI 0
Rafs

Rafs

26/07/2004

Colega,

Você podería detalhar o que aconteceu? Se não ordenou corretamente ou se houve algum erro.
Fiz um teste rápido aqui, porém funcionou..


GOSTEI 0
Uildenei

Uildenei

26/07/2004

se for somente em ordem ascendente assim eh mais facil e eh certo que funciona:


cds.IndexFieldNames:=´CAMPO´;


desde que esse campo nao seja calculado

Uildenei


GOSTEI 0
Cabelo

Cabelo

26/07/2004

Ocorreu o seguinte :

Ele simplesmente não fez a ordenação corretamente..

O problema é que o campo é string..

e pela ordenação a partir de uma string, a ordenação acaba saindo errada..

se fosse integer, ordenaria corretamente..

Cabelo


GOSTEI 0
Rafs

Rafs

26/07/2004

Eu refiz o teste agora e ordenou corretamente.
Primeiro vc deverá atualizar a tabela com os caracteres desejados para depois indexar
Se vc quiser eu lhe mando o teste que fiz.
Um detalhe que esqueci de mencionar, o tamanho do campo no BD deve permitir receber os três caracteres a mais que você irá inserir, pois o ClientDataSet respeita este aspecto. Isto é, o campo deve ter 11 caracteres de tamanho, senão quando vc inserir os três caracteres o sistema irá ´capar´ os três últimos.


GOSTEI 0
Cabelo

Cabelo

26/07/2004

Colega rafs

Exatamente o quê eu havia imaginado..

O problema é o seguinte..

Além de inserir os três caracteres, eu devo ainda inserir alguns caracteres em braco, para separar o código, para facilitar a digitação caso seja necessário..

Aí eu teria que ter uma campo com 25 caracteres, e meu sequancial seria de somente 15..

Além do mais.. não posso mudar o banco de dados, pois esta tabela é usada mais adiante no sistema, e é necessário que tenha somente 15 caracteres..

Eu tive uma idéia de criar um campo calculado, mas não deu certo, e como o colega uildinei mencionou não é possível realizar este evento em campos calculados..

Não sei o quê eu faço..

Como vou resolver este problema, sendo que além de tudo não posso usar uma tabela temporária..

Cabelo


GOSTEI 0
Rafs

Rafs

26/07/2004

Camarada, agora vc apertou sem abraçar... :(

Vou dar uma pensada em casa e vejo se consigo alguma idéia para ajudar com seu ´probleminha´.
Mas para me ajudar, detalhe como vc faz desde a seleção na tabela até a apresentação no relatório. Quem sabe possa surgir alguma idéia que supra as suas necessidades, diferente do que estamos trabalhando. :)


GOSTEI 0
Cabelo

Cabelo

26/07/2004

esta é a rotina para inserir os registros do sequencial :

v_sequencial := F_Max_Cod(´C_SEQUENCIAL´, ´VT0100´, 15, MD.QGERAL2, MD.cdsGeral2);
//esta função gera o sequencial de 15 dígitos
v_sql := ´insert into VT0100 (C_SEQUENCIAL, C_BAIXA, C_COD_SERVICO, C_IMPRESSO, ´+
´C_DATA_IMP, C_LOGIN_IMPRESSAO, C_COD_COLABORADOR, C_STATUS, ´+
´C_COD_EMPRESA, C_DATA_ENTREGA, C_LOGIN_ENTREGA) values ´+
´(´´´+v_sequencial+´´´, ´´N´´, ´´´+
cdsCA0400.fieldbyname(´C_COD_SERVICO´).asstring+´´´, ´´N´´, ´´´+
formatdatetime(´mm/dd/yyyy´, now)+´´´, ´´´+F_Le_Usuario+´´+
´´´, ´´´+s_cod_vendedor+´´´, ´´I´´, ´´´+v_empresa+´´´, ´´´+
formatdatetime(´mm/dd/yyyy´, now)+´´´, ´´´+F_Le_Usuario+´´´)´;
F_Grava(MD.sqlEngestrauss, MD.QGERAL, MD.cdsGeral, v_sql);
//esta função manda o SQL abrindo uma transaction, e dando um commit ou rollback

no evento beforePrint do detail do report :

v_seguranca := F_strzero(v_i + 1, 3);
rlBarCode.Caption := copy(cdsVT0100.fieldbyname(´C_SEQUENCIAL´).asstring, 1, 1)+
´ ´+
copy(cdsVT0100.fieldbyname(´C_SEQUENCIAL´).asstring, 2, 3)+
´ ´+
copy(cdsVT0100.fieldbyname(´C_SEQUENCIAL´).asstring, 5, 2)+
´ ´+
copy(cdsVT0100.fieldbyname(´C_SEQUENCIAL´).asstring, 7, 3)+
´ ´+
copy(cdsVT0100.fieldbyname(´C_SEQUENCIAL´).asstring, 10, 2)+
´ ´+
copy(cdsVT0100.fieldbyname(´C_SEQUENCIAL´).asstring, 12, 2)+
copy(v_seguranca, 1, 2) +
´ ´+
copy(v_seguranca, 3, 1) +
copy(cdsVT0100.fieldbyname(´C_SEQUENCIAL´).asstring, 14, 2);

Agradeço sua atenção..

Cabelo


GOSTEI 0
Rafs

Rafs

26/07/2004

Colega,

Hoje estive super enrolado no trampo e não consegui olhar direito o que vc me passou. Vou dar uma olhada com calma em casa e assim que tiver alguma idéia lhe passo.


GOSTEI 0
Cabelo

Cabelo

26/07/2004

Cara muito obrigado pela atenção, se precisar de alguma coisa tô aqui..

Cabelo


GOSTEI 0
Rafs

Rafs

26/07/2004

Caro cabelo_uni,

Consegui fazer da seguinte forma, espero que lhe ajude...
Abaixo segue o código comentado.

Crie um campo tipo InternalCalc no FieldsEditor do CDS
Declare uma variável na seção private para verificar se os registros já foram adicionados ao campo tipo InternalCalc
PS.: A função GeraCaracter eu utilizo para gerar os caracteres aleatóriamente.
  private
    { Private declarations }
// Informará se já foram carregados os valores para o campo tipo InternalCal
    pvCarregou: Boolean;
    function GeraCaracter: String;


// função para criar os caracteres randomicamente
function TForm1.GeraCaracter: String;
var
   I: Integer;
begin
  Randomize;
  I := Random(999);
  Result :=  FormatFloat(´000´,I);
end;


Na criação do form eu abro o CDS e adiciono o índice que desejo utilizar para ordenar os registros
procedure TForm1.FormCreate(Sender: TObject);
begin
  cds.Open;
// Crio um índice no CDS para ordenar pelo campo tipo InternalCalc
  cds.IndexDefs.Add(´idxOrdem´,´Teste´,[]);
// Ao abrir o CDS, automaticamente é executado o evento OnCalcFields, por isso
// após a abertura do CDS eu mudo o status da variável pvCarregou para True,
// para que quando alterar o índice não reexecute o evento OnCalcFields
  pvCarregou := True;
end;


No evento OnCalcFields insira o código para que o campo tipo InternalCalc seja atualizado.
É aqui que virá a rotina para você incluir os caracteres que deseja
procedure TForm1.cdsCalcFields(DataSet: TDataSet);
var
  Primeiro, Segundo: String;
  lRegistro: String;
begin
// Verifica se a variável é false para poder carregar o campo tipo InternalCalc
// com os caracteres necessários
  if not pvCarregou then
  begin
    lRegistro := cds.FieldByName(´CPOSTRING´).AsString;
    Primeiro := Copy(lRegistro,1,2);
    Segundo := Copy(lRegistro,3,6);
    cds.FieldByName(´Teste´).AsString := Primeiro+GeraCaracter+Segundo;
  end;
end;


Caso deseje posso lhe enviar o programinha que fiz para testar.
Havendo alguma dúvida estarei à disposição. :D


GOSTEI 0
Cabelo

Cabelo

26/07/2004

Cara não consegui fazer isso aki..

vc poderia então me mandar o programa??

talvez eu consiga fazer..

Obrigado pela atanção..

cabelo.uni@uol.com.br

Valew

Cabelo


GOSTEI 0
Rafs

Rafs

26/07/2004

Acabei de enviar o arquivo para o email que vc me passou.

Este está lendo os dados de um arquivo xml, mas funciona perfeitamente igual ao acessar um BD.

Espero que lhe ajude.


GOSTEI 0
Cabelo

Cabelo

26/07/2004

Muito obrigado pela sua ajuda..

Assim que conseguir te dou um toque..

Valew mesmo..


Cabelo


GOSTEI 0
POSTAR