Obter ID dos itens selecionados em um CheckListBox
Pessoal, estou populando um CheckListBox com este codigo.
Em seguida, preciso obter a ID dos itens marcados, para então fazer um select in
Cheguei até este ponto, gostaria de pedir umas dicas, se estou no caminho certo.
obrigado.
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
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
Curtidas 0
Melhor post

Arthur Heinrich
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).
Para que o plano de acesso fique razoavelmente eficiente, a tabela TBDUPLICATAS precisa ser indexada por (COD_PROJETO, VENCIMENTO).
GOSTEI 1
Mais Respostas

Arthur Heinrich
06/02/2025
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.
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.
GOSTEI 0

Renan
06/02/2025
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'
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'
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;
GOSTEI 0

Renan
06/02/2025
Acho que achei a solução.
Após criar a Lista eu delimito ela, com uma virgula
e na SQL
Rodando normal, pelos testes que fiz até o momento.
Após criar a Lista eu delimito ela, com uma virgula
Lista.Delimiter := ','; Lista.StrictDelimiter := True;
e na SQL
Query1.SQL.Add('AND D.COD_PROJETO IN ('+Lista.DelimitedText+')');
Rodando normal, pelos testes que fiz até o momento.
GOSTEI 0