Fórum Obter ID dos itens selecionados em um CheckListBox #623649

06/02/2025

0

Pessoal, estou populando um CheckListBox com este codigo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var
  Qry : TIBQuery;
begin
  Qry := TIBQuery.Create(nil);
  try
    Qry.Database := FrmDm.dbBoletos;
    Qry.SQL.Clear;
    Qry.SQL.Add('SELECT CODIGO, NOME_PROJETO FROM TBNOMEPROJETO');
    Qry.SQL.Add('ORDER BY NOME_PROJETO');
    Qry.Open;
 
    while not Qry.eof do
    begin
      clbCentroCusto.Items.AddObject(Qry.FieldByName('NOME_PROJETO').AsString, TObject(Integer(Qry.FieldByName('CODIGO').AsInteger)));
      Qry.Next;
    end;
  finally
    FreeAndNil(Qry);
  end;
end;



Em seguida, preciso obter a ID dos itens marcados, para então fazer um select in

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var
 i: Integer;
 lista : tstringlist;
begin
  try
   lista.create;
  for i := 0 to clbCentroCusto.Count - 1 do
    if clbCentroCusto.Checked[i] then
    begin
     lista.add(IntToStr(Integer(cbCentroCusto.Items.Objects[cbCentroCusto.ItemIndex])));
    end;
 
  finally
   lista.free;
  end;


Cheguei até este ponto, gostaria de pedir umas dicas, se estou no caminho certo.

obrigado.
Renan

Renan

Responder

Post mais votado

08/02/2025

Perfeito. É uma solução "elegante".

Para que o plano de acesso fique razoavelmente eficiente, a tabela TBDUPLICATAS precisa ser indexada por (COD_PROJETO, VENCIMENTO).

Arthur Heinrich

Arthur Heinrich
Responder

Gostei + 1

Mais Posts

06/02/2025

Arthur Heinrich

O componente "lista : tstringlist;" do segundo bloco aparentemente irá conter os IDs dos itens selecionados.

A partir dele você precisa montar sua query.

Uma coisa que muita gente faz é montar a query dinamicamente, concatenando os IDs: select ... where ID in (valor1, valor2, ..., valorn) ...

Embora isto seja de fácil implementação, causa uma série de problemas.

1 - SQL Injection: Embora nesta caso, por se tratar de IDs numéricos, não vai quebrar o código e, por vir de uma seleção controlada, o usuário não terá condições de estipular IDs não presentes na lista, nas é sempre bom tomar cuidado com concatenações em queries, com base em valores digitados pelos clientes.

2 - Limite dos bancos: Dependendo da situação, é possível que o usuário selecione um número muito grande de itens. No Oracle, por exemplo, um filtro do tipo "coluna in (lista)" é limitado a listas com, no máximo, 1000 itens. Se este limite é ultrapassado, a query aborta.

Outro problema é relacionado ao plano de acesso. Geralmente, o plano vai utilizar o código informado na lista e executar um processo chamado "in list iterator", onde o plano de acesso é executado para cada um dos códigos e o resultado é concatenado. Uma lista com 100 valores, literalmente executa o plano de acesso 100 vezes.

3 - Hard Parse: Ao concatenar valores à query, sem o uso de bind variables, ou utilizar listas contendo número de valores distintos, o banco interpreta a query como uma query nova e precisa realizar o hard parse, que é muito mais lento que o soft parse, que consiste em identificar a query no cache e reexecutar o plano de acesso gerado previamente. Isto acarreta problemas de performance.

Uma alternativa, para tornar a query única, seria utilizar uma tabela temporária para armazenar os itens desejados e, executar a query utilizando um join com a tabela temporária. Desta forma, a query é sempre a mesma, mudando apenas o conteúdo da tabela temporária, que precisa ser populada previamente. Isto evita problemas de hard parse, melhora o cache e elimina o limite de 1000 itens. Entretanto, caso o número de itens escolhido retorne uns 10% a 15% do total de registros, é possível que utilize um plano de acesso ineficiente.
Responder

Gostei + 0

07/02/2025

Renan

Olá, Arthur.

Obrigado pelas explicações, muito interessante os pontos que você citou.

No meu caso, o usuário não vai digitar os códigos que estarão presentes no SQL IN.
Os dados serão obtidos a partir dos itens que o usuário marcar no CheckListBox.

Como você mencionou, a variável Lista vai armazenar as IDS marcadas.

Montei a SQL desta forma, mas estou com erro: Incompatible types: 'string' and 'TStringList'

1
2
3
4
5
6
7
8
9
10
11
12
Query1.Close;
Query1.SQL.Clear;
Query1.SQL.Add('SELECT D.NF, D.DATA_DOC, D.NUM_DOC, D.TOTAL, D.VENCIMENTO, D.DT_PAGAMENTO, D.OBS, C.CEDENTE');
Query1.SQL.Add('FROM TBDUPLICATAS AS D');
Query1.SQL.Add('INNER JOIN TBCEDENTES AS C ON C.CODIGO = D.COD_CEDENTE');
Query1.SQL.Add('WHERE D.VENCIMENTO >= :INI and D.VENCIMENTO <= :FIM');
Query1.SQL.Add('AND D.COD_PROJETO IN ('+Lista+')');  //erro nesta linha
Query1.SQL.Add('ORDER BY D.VENCIMENTO');
Query1.ParamByName('INI').AsDate := dtpInicio.Date;
Query1.ParamByName('FIM').AsDate := dtpFim.Date;
Query1.Prepare;
Query1.Open;


Responder

Gostei + 0

07/02/2025

Renan

Acho que achei a solução.

Após criar a Lista eu delimito ela, com uma virgula

1
2
Lista.Delimiter := ',';
Lista.StrictDelimiter := True;


e na SQL

1
Query1.SQL.Add('AND D.COD_PROJETO IN ('+Lista.DelimitedText+')');


Rodando normal, pelos testes que fiz até o momento.
Responder

Gostei + 0

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar