Vários parametros em um só método de busca

Boa Tarde!! Pessoal,

tenho um formulário de histórico de vendas por período, com os campos DataInicio e DataFinal. A busca das vendas por período está funcionando perfeitamente, porem, eu tentei incrementar algo a mais, por exemplo, além de buscar apenas por período específico, eu gostaia de buscar por período e tambem por codigo do cliente, ou por periodo e pelo nome do cliente, ou por periodo + o código do cliente + vendas a prazo.
Tentei fazer isso no método buscar vendas por período mas nao está dando certo. Consegui apenas usando o periodo e o código do cliente. Quando tento fazer apenas com o periodo e o nome do cleinte dá erro.
aqui estao o método e sua implementação:

 public List<Vendas> listarVendasPorClintenoPeriodo(int CodCliente, LocalDate DataInicio, LocalDate DataFim){
         try {
            // 1º passo - criar a Lista
             List<Vendas> lista = new ArrayList<>();
             // 2º passo - instrução SQL, organiza-la e executar
             String sql = "select v.id, date_format(v.data_venda,'%d/%m/%Y') as data_formatada, c.nome, v.total_venda, v.observacoes from tb_vendas as v "
             +"inner join tb_clientes as c on(v.cliente_id = c.id) where v.cliente_id = ? and v.data_venda BETWEEN ? and ?";
             
             PreparedStatement stmt = con.prepareStatement(sql);
             
             //colocando os parametros
             
                stmt.setInt(1, CodCliente);
             
                stmt.setString(2, DataInicio.toString());
                stmt.setString(3, DataFim.toString());
             
             
             ResultSet rs = stmt.executeQuery();
             
             while(rs.next()){
                Vendas obj = new Vendas();
                Clientes c = new Clientes();
                obj.setId(rs.getInt("v.id"));
                obj.setData_venda(rs.getString("data_formatada")); 
                c.setNome(rs.getString("c.nome"));
                obj.setTotal_venda(rs.getDouble("v.total_venda")); 
                obj.setObservacao(rs.getString("v.observacoes")); 
              
                obj.setCliente(c);
              
           lista.add(obj);
             
             
             }
             return lista;
         } catch (SQLException erro) {
             
             JOptionPane.showMessageDialog(null, "Ops!!! !!" + erro);
             return null;
         }
         
        
     }
     
      public List<Vendas> listarVendasPorClintePorNome(String nomeCliente, LocalDate DataInicio, LocalDate DataFim){
         try {
            // 1º passo - criar a Lista
             List<Vendas> lista = new ArrayList<>();
             // 2º passo - instrução SQL, organiza-la e executar
             String sql = "select v.id, date_format(v.data_venda,'%d/%m/%Y') as data_formatada, c.nome, v.total_venda, v.observacoes from tb_vendas as v "
             +"inner join tb_clientes as c on(v.cliente_id = c.id) where c.nome like ? and v.data_venda BETWEEN ? and ?";
             
             PreparedStatement stmt = con.prepareStatement(sql);
             
             //colocando os parametros
             
                stmt.setString(1, nomeCliente);
             
                stmt.setString(2, DataInicio.toString());
                stmt.setString(3, DataFim.toString());
             
             
             ResultSet rs = stmt.executeQuery();
             
             while(rs.next()){
                Vendas obj = new Vendas();
                Clientes c = new Clientes();
                obj.setId(rs.getInt("v.id"));
                obj.setData_venda(rs.getString("data_formatada")); 
                c.setNome(rs.getString("c.nome"));
                obj.setTotal_venda(rs.getDouble("v.total_venda")); 
                obj.setObservacao(rs.getString("v.observacoes")); 
              
                obj.setCliente(c);
              
           lista.add(obj);
             
             
             }
             return lista;
         } catch (SQLException erro) {
             
             JOptionPane.showMessageDialog(null, "Ops!!! !!" + erro);
             return null;
         }
         
        
     }

e aqui está a implementação:

 private void btnPesquisarActionPerformed(java.awt.event.ActionEvent evt) {                                             
        // Metodo Buscar vendas por período
        // É necessário fazer a conversão de datas
        // Primeiro passo: Receber a data
            
        
            DateTimeFormatter formato = DateTimeFormatter.ofPattern("dd/MM/yyyy");
            String nome = "%"+TxtNome.getText()+"%";
            
            int CodCliente  = Integer.parseInt(TxtCodCliente.getText());
            LocalDate DataInicio = LocalDate.parse(TxtDataInicial.getText(), formato);
           
            LocalDate DataFim = LocalDate.parse(TxtDataFinal.getText(), formato);
            VendasDAO dao = new VendasDAO();
            
            if(TxtCodCliente.getText() != ""){
            
            List<Vendas>lista = dao.listarVendasPorClintenoPeriodo(CodCliente, DataInicio, DataFim);
            DefaultTableModel dados = (DefaultTableModel)TabelaHistorico.getModel();
            dados.setNumRows(0);
            
            for (Vendas v:lista){
                dados.addRow(new Object[]{
                    
                    v.getId(),
                    v.getData_venda(),
                    v.getCliente().getNome(),
                    v.getTotal_venda(),
                    v.getObservacao()
                });
                
            }
            
            } else{
                
            List<Vendas>lista = dao.listarVendasPorClintePorNome(nome, DataInicio, DataFim);
            DefaultTableModel dados = (DefaultTableModel)TabelaHistorico.getModel();
            dados.setNumRows(0);
            
            for (Vendas v:lista){
                dados.addRow(new Object[]{
                    
                    v.getId(),
                    v.getData_venda(),
                    v.getCliente().getNome(),
                    v.getTotal_venda(),
                    v.getObservacao()
                });
                
            }
                
                
            }
            
            
            
           
            

Essa é a mesangem que recebo:
Exception in thread “AWT-EventQueue-0” java.lang.NumberFormatException: For input string: “”
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:675)
at java.base/java.lang.Integer.parseInt(Integer.java:781)
at br.com.projeto.view.frmVendasPorCliente.btnPesquisarActionPerformed(frmVendasPorCliente.java:254)
at br.com.projeto.view.frmVendasPorCliente.access$300(frmVendasPorCliente.java:35)
at br.com.projeto.view.frmVendasPorCliente$4.actionPerformed(frmVendasPorCliente.java:145)
Alguem consegue identificar o que está acontecendo ?

O método TxtCodCliente.getText() eestá retornando vazio "", então não dá pra fazer Integer.parseInt.

6 linhas abaixo você tem essa verificação, if(TxtCodCliente.getText() != ""), que também está errada.
String devem ser comparadas com o método equals pois o == ou != compara o endereço de memória e não o conteúdo

private void btnPesquisarActionPerformed(java.awt.event.ActionEvent evt) {                                             
	DateTimeFormatter formato = DateTimeFormatter.ofPattern("dd/MM/yyyy");
	String nome = "%"+TxtNome.getText()+"%";
	
	String codigo = TxtCodCliente.getText();
	if (!"".equals(codigo) ) {

		int CodCliente  = Integer.parseInt(codigo);
		LocalDate DataInicio = LocalDate.parse(TxtDataInicial.getText(), formato);

		LocalDate DataFim = LocalDate.parse(TxtDataFinal.getText(), formato);
		VendasDAO dao = new VendasDAO();


		List<Vendas>lista = dao.listarVendasPorClintenoPeriodo(CodCliente, DataInicio, DataFim);
		DefaultTableModel dados = (DefaultTableModel)TabelaHistorico.getModel();
		dados.setNumRows(0);

		for (Vendas v : lista) {
			dados.addRow(new Object[]{
				v.getId(),
				v.getData_venda(),
				v.getCliente().getNome(),
				v.getTotal_venda(),
				v.getObservacao()
			});
		}
	} else {
		List<Vendas>lista = dao.listarVendasPorClintePorNome(nome, DataInicio, DataFim);
		DefaultTableModel dados = (DefaultTableModel) TabelaHistorico.getModel();
		dados.setNumRows(0);
		for (Vendas v:lista){
			dados.addRow(new Object[]{

			v.getId(),
			v.getData_venda(),
			v.getCliente().getNome(),
			v.getTotal_venda(),
			v.getObservacao()
			});
		}
	}
}

Quando estou buscando as vendas pelo código do cliente e pelas datas inicio e final está retornando sem erro. O erro só ocorre quando insiro o nome do cliente. Minha intenção é fazer uma busca onde eu possa inserir todos os dados possíveis no formulario (codigo e nome), tendo o período por obrigatorio, ou preencher apenas com o codigo ou o nome.
Pelo código já consegui

Quando deixo o campo código vazio tambem da erro. Ou seja, só está funcionando se eu colocar o periodo e o código. Se colocar periodo, código e nome da erro, se colocar apenas nome e periodo da erro, enfim
é isso que quero corrigir

Então posta o erro que você está tendo agora, pois o erro que você postou antes é devido a fazer o parseInt de uma String vazia:

Exception in thread “AWT-EventQueue-0” java.lang.NumberFormatException: For input string: “”
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:675)
at java.base/java.lang.Integer.parseInt(Integer.java:781)
at br.com.projeto.view.frmVendasPorCliente.btnPesquisarActionPerformed(frmVendasPorCliente.java:254)

Exatamente isso. Veje bem, tenho os campos Codigo, Nome, DataInicio e DataFinal. Se eu coloco o código e a data inicio e final, tudo bem, ele me retorna a consulta legal. Mas se deixo o campo Codigo vazio, dá erro. da mesma forma, se eu preencher apenas os campos datainicio e datafinal, dá erro.
Eu gostaria de fazer com IFs,
if (txtcodigo.getText() == “” and txtnome.getText == “”) usa o metodo busca por periodo. Se apenas um estiver vazio, identifica qual deles está vazio e faz a consulta por perioro e pelo campo preenchido. Eu tentei usar algo que já havia feito em Delphi ha muito tempo atras, mas nao deu certo.

Problema é que nao estou conseguindo, por isso estou pedindo ajuda

Então você ignorou o código que eu postei antes.

Lá é feito a comparação do código do jeito certo, antes de fazer o Integer.parseInt.

:person_shrugging:t2:

Nao, não. Eu realmente estava insistindo no erro. Agora testei e deu certo.
Obrigado
Mas tenho uma pergunta ainda, se nao for pedir demais.
veja bem,
Imaginemos que eu crie uma variável chamada filtro do tipo string, certo ?

String filtros := " ";

Então faria assim:

            if (filtros = '' ") {
                 filtros := filtros + 'where ';
           } else { filtros := filtros + 'and ';
}


Então,

   Se tiver algo digitado no campo CodCliente 

if (txtCodCliente.getText != ‘’ ") {
filtros := filtros + ’ txtCodCliente.getText()’ ;
}
// caso tenha digitado um numero de processo
if (txtNome != ‘’ ") {
filtros := filtros + ’ txtNome.getText()’ ;
}

e lá no método faria a consulta SQL assim:

String sql = "select v.id, date_format(v.data_venda,'%d/%m/%Y') as data_formatada, c.nome, v.total_venda, v.observacoes from tb_vendas as v "
             +"inner join tb_clientes as c on(v.cliente_id = c.id) where v.data_venda BETWEEN ? and ? + filtro";

O que estou tentando dizer e não sei se isso tem lógica, é que poderiamos ter apenas uma consulta, portando, um unico método, onde a instrução SQL receberia um WHERE ou AND no final, desde que os campos CodCliente e Nome estivessem preenchidos ou não.
Isso faz algum sentido ?

O que você quer fazer é possível e bem comum, você pode concatenar as instruções where/and ao sql e os parâmetros posteriormente.

A sua comparação de strings precisa ser com equals(), não com o sinal de igual (como o staroski já tinha demonstrado). Em vez de:

if (filtros = '' ") {
  filtros = filtros + 'where ';
} else { 
  filtros = filtros + 'and ';
}

Algo como

if (!"".equals(filtro) ) {
  filtros = filtros + 'where ';
} /// resto do código

Mas, se o seu sql inicial já tiver um where (por exemplo, da data), todas as instruções subsequentes podem ser apenas “and” (ou “or”), e você não precisa de else. Algo como:


// sql inicial já tem where
String sql = "select v.id, date_format(v.data_venda,'%d/%m/%Y') as data_formatada, c.nome, v.total_venda, v.observacoes from tb_vendas as v " +
"inner join tb_clientes as c on(v.cliente_id = c.id) where v.data_venda BETWEEN ? and ? "

String filtros = "";

// "and" para o código do cliente
if (!txtCodCliente.getText().equals("") {
  filtros = filtros + " and v.cliente_id = ? ";
}

// "and" para o nome do cliente
if (!txtnome.getText().equals("") {
  filtros = filtros + " and c.nome like ? ";
}

sql = sql + filtros;

Nesse caso, você pode armazenar os parâmetros em uma lista e passá-los posteriormente para o preparedStatement.

Abraço.

Eu entendi. Porem, a instrução SQL está no método lá no VendasDAO e os IFs estão no form de busca. Não to sabendo como modificar a instrução a partir da implementação do método no outro formulário.

Altere seu método e passe os valores conforme precisar, e gere o sql comparando os parâmetros em vez do conteúdo dos textfields

public List<Vendas> listarVendasPorClintenoPeriodo(int codCliente, LocalDate DataInicio, LocalDate DataFim, String nomeCliente){

// sql inicial já tem where
String sql = "select v.id, date_format(v.data_venda,'%d/%m/%Y') as data_formatada, c.nome, v.total_venda, v.observacoes from tb_vendas as v " +
"inner join tb_clientes as c on(v.cliente_id = c.id) where v.data_venda BETWEEN ? and ? "

String filtros = "";

// "and" para o código do cliente
if (codCliente > 0) {
  filtros = filtros + " and v.cliente_id = ? ";
}

// "and" para o nome do cliente
// note que o parâmetro já vem com 2 %, então verificamos eles também
if (!nomeCliente.equals("") && !nomeCliente.equals("%%")) {
  filtros = filtros + " and c.nome like ? ";
}

// resto do código (lembrando que é preciso ajustar o preparedstatement também

E para chamar seria algo como:

String nomeCliente = "%"+TxtNome.getText()+"%";
String codigo = TxtCodCliente.getText();
int CodCliente = Integer.parseInt(codigo);

LocalDate DataInicio = LocalDate.parse(TxtDataInicial.getText(), formato);
LocalDate DataFim = LocalDate.parse(TxtDataFinal.getText(), formato);

VendasDAO dao = new VendasDAO();

List<Vendas>lista = dao.listarVendasPorClintenoPeriodo(CodCliente, DataInicio, DataFim, nomeCliente);

// resto do código

Abraço.

A consulta está funcionando. Não consegui usar essa questão dos filtros. Como eu disse nao sei como fazer para mudar a instrução SQL a partir do formulario de busca.
A unica questão agora é descobrir como fazer para que o usuário não deixe um dos campos vazio, codigo do cliente ou o nome. Se deixar vazio e apertar o botão não faz nada e avisa que tem que preencher

Recomendo que leia as respostas que os colegas te passam, pois o @TerraSkilll já recomendou uma solução pra isso.

Na implementação acho que está ok agora, mas me perdi aqui na instrução SQL. Devo colocar a variavel filtros assim:

String sql = "select v.id, date_format(v.data_venda,'%d/%m/%Y') as data_formatada, c.nome, v.total_venda, v.observacoes from tb_vendas as v " +
"inner join tb_clientes as c on(v.cliente_id = c.id) where v.data_venda BETWEEN ? and ? " + Filtros;

No final, após as aspas ou dentros das aspas?

Quando você concatena uma String, você concatena dentro das aspas ou fora?

Na verdade nunca fiz isso numa instrução SQL. Mas pela lógica deve ser fora das aspas. Eu acho.

Sim, a concatenação de string é fora das aspas. Veja o primeiro exemplo que postei, onde concateno a String sql com a String filtros. Se colocar dentro das aspas, não é uma concatenação, é somente a palavra filtros dentro da String.

Concatenação de strings funciona da mesma forma independente do conteúdo, o fato de ser uma instrução sql não muda nada. Veja um exemplo rodando em : KQdgwE - Online Java Compiler & Debugging Tool - Ideone.com .

Pequena dica/lição: recomendo testar as coisas e ver o resultado, em vez de esperar uma resposta pronta e perfeita. Aprender por conta própria faz parte e, a não ser que você esteja realmente travado, 5 minutos de testes pode ser muito melhor do que 1 h esperando alguém responder sua dúvida.

Abraço.

2 curtidas

Amigo, eu agradeço muito pelas contribuições. Mas não sou de esperar respostas prontas nao. Não mexo com Java, sou iniciante. Jamais fiz um curso. E para que tenhas uma ideia, já estou finalizando um sistema de controle de estoque com um carrinho de compras. Problema é que para um iniciante, que nunca mexeu com java, não é fácil mesmo. Tem detalhes que apenas com experiencia é que se resolve.