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

18 respostas
java
J

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 ?

18 Respostas

staroski

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()
			});
		}
	}
}
J

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

J

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

staroski

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)
J

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.

J

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

staroski

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:

J

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 ?

TerraSkilll

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.

J

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.

TerraSkilll

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.

J

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

staroski

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

J

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?

staroski

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

J

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

TerraSkilll

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.

J

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.

Criado 3 de fevereiro de 2024
Ultima resposta 5 de fev. de 2024
Respostas 18
Participantes 3