Filtrar consulta SQL com campos FK

Essa é a minha primeira postagem aqui no GUJ, pois já frequento aqui há alguns meses, e já observei que tem um pessoal que entente bem do assunto.

Depois de pesquisar na internet e em alguns livros não encontrei uma solução até o momento.
Estou fazendo um projeto para meu curso. Ele é para testar conhecimentos em codigo java e banco de dados Mysql. Tenho que fazer CRUD em cada tabela criada, no caso são tres.

As tabelas são Operadora, ContatoPessoaFisica e ContatoPessoaJuridica. É um tipo de agenda simples.
As FKs estão nas tabelas Contato que recebem a ID da operadora.

O problema está quando dou um SELECT. Os dados saem duplicados assim que eu cadastro uma nova operadora. Quando tem apenas uma operadora tudo funciona normal. É listado apenas um ID de Contato, mas com mais de uma operadora são listados o mesmo numero de Contatos existente das operadoras.
Quero que quando listar exiba apenas um contato relacionado a uma operadora

No codigo Java está ok. Fiz os testes em linha de comando no mysql, e realmente aparecem duplicados.

O comando Sql que estou usando: select * from contatoPessoaFisica as c, operadora as o where O.IdOperadora

Quero trazer as informaçoes tanto do Contato quanto da Operadora sem estarem duplicados.
Se alguem puder ajuda, agradeço.

Tem como colocar as estruturas de sua tabela?

Como ela foi implementada.

1 curtida

Obrigado por responder Jhonys
Aqui está a estrutura

--
-- Estrutura da tabela `contatopessoafisica`
--

CREATE TABLE IF NOT EXISTS `contatopessoafisica` (
  `idContato` int(11) NOT NULL AUTO_INCREMENT,
  `telefone` varchar(45) NOT NULL,
  `email` varchar(100) NOT NULL,
  `Operadora_idOperadora` int(11) DEFAULT NULL,
  `nome` varchar(45) NOT NULL,
  `apelido` varchar(45) NOT NULL,
  PRIMARY KEY (`idContato`),
  KEY `fk_contatoPessoaFisica_Operadora1_idx` (`Operadora_idOperadora`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Estrutura da tabela `contatopessoajuridica`
--

CREATE TABLE IF NOT EXISTS `contatopessoajuridica` (
  `idContatoPessoaJuridica` int(11) NOT NULL AUTO_INCREMENT,
  `fax` varchar(45) NOT NULL,
  `telefone` varchar(45) NOT NULL,
  `site` varchar(45) NOT NULL,
  `nome` varchar(45) NOT NULL,
  `Operadora_idOperadora` int(11) DEFAULT NULL,
  PRIMARY KEY (`idContatoPessoaJuridica`),
  KEY `fk_contatoPessoaFisica_Operadora1_idx` (`Operadora_idOperadora`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Estrutura da tabela `operadora`
--
CREATE TABLE IF NOT EXISTS `operadora` (
  `idOperadora` int(11) NOT NULL AUTO_INCREMENT,
  `NomeOperadora` varchar(45) NOT NULL,
  `Codigo` int(11) NOT NULL,
  `Tarifa` decimal(10,2) NOT NULL,
  PRIMARY KEY (`idOperadora`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Não estou usando o Operadora_idOperadora diretamente no codigo Java. Estou usando agregação, onde um Contato possui uma Operadora, relaçao de dependencia.

Então neste caso as tabelas Contatos recebem um objeto do Tipo operadora. Então passo esse objeto, e ele recebe não so o Operadora_idOperadora, mas todos os campos.

Tambem já fiz os teste, para que quando informar os dados dos Contatos receba tambem um Operadora_idOperadora e funciona. O problema maior mesmo está sendo na hora de exibir, de fazer a filtragem. Do jeito que está, parece que ao cadastrar uma nova operadora, os Contatos tambem recebem essa operadora. Queria que recebesse apenas aquela operadora que indiquei ao cadastrar

Já tentou usar o inner join:

 select * from operadora as o inner join contatoPessoaFisica as c on   O.IdOperadora= c.Operadora_idOperadora where O.IdOperadora=?

Já usei algo parecido, mas estava retornando empty. Acabei de dar esse comando:
select * from contatoPessoaFisica as C, Operadora as O;
Retornou todos os campos de contatoPessoaFisica e Operadora e o uncico que está null é o operadora_idoperadora.

Estou pensando que talvez seja no codigo Java. Mas interessante que quando eu cadastro somente uma operadora e depois cadastro um contato, esse contato recebe a operadora e o id, todos os campos de operadora normalmente, so que quando cadastro mais uma operadora esse contato recebe duas operadoras. Vou fazer um teste aqui. Vou colocar para que quando cadastrar um novo contato receba somente o operadora_idoperadora, pois do jeito que está, recebendo todo o objeto, o operadora_idoperadora nao é passado para o contato.

Você deve inverter então, aonde operadora esteja dentro de contatopessoafisica e contatopessoajuridica, sendo assim o relacionamento que você mesmo disse:

Observação: Tem também outros pequenos problemas de padrão, já uma vez lhe disse isso e você até me indagou sobre o assunto. a sua nomenclatura de campos no mysql, por padrão poderia ser tudo minusculo.

Vou propor um esquema referente ao que eu entendi na sua pergunta, sem ver o seu código e lógica empregada.


--
-- Estrutura da tabela `operadora`
--
delimiter $$

CREATE TABLE `operadora` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `nome` varchar(45) NOT NULL,
  `codigo` int(11) NOT NULL,
  `tarifa` decimal(10,2) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8$$

--
-- Estrutura da tabela `contatopessoafisica`
--
delimiter $$

CREATE TABLE `contatopessoafisica` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `telefone` varchar(45) NOT NULL,
  `email` varchar(100) NOT NULL,
  `nome` varchar(45) NOT NULL,
  `apelido` varchar(45) NOT NULL,
  `operadora_id` int(11) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `pkpfoperadora_idx` (`operadora_id`),
  CONSTRAINT `pkpfoperadora` FOREIGN KEY (`operadora_id`)
       REFERENCES `operadora` (`id`) 
       ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8$$

--
-- Estrutura da tabela `contatopessoajuridica`
--
delimiter $$

CREATE TABLE `contatopessoajuridica` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `fax` varchar(45) NOT NULL,
  `telefone` varchar(45) NOT NULL,
  `site` varchar(45) NOT NULL,
  `nome` varchar(45) NOT NULL,
  `operadora_id` int(11) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `pkpjoperadora_idx` (`operadora_id`),
  CONSTRAINT `pkpjoperadora` FOREIGN KEY (`operadora_id`) 
       REFERENCES `operadora` (`id`)
       ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8$$

Relacionamento

No momento da gravação faça um dropdown no seu projeto dentro do cadastro de contatopessoafisica e contatopessoajuridica sendo esse a operadora.

As sua SQL serão feitas com Join de contatopessoafisica e contatopessoajuridica com operadora retornando somente a linha pretendida.

Bom foi isso que eu entendi.

Observação: faltou colocar seu código Java.

Opa, valeu Dragonn pela resposta. Na verdade a operadora já está dentro das classes Contatos

public class ContatoPessoaFisica {
//
    private Operadora operadora;
        setOperadora
        getOperadora
}

No momento do cadastro faço o seguinte

ContatoPessoaFisica fisica = new ContatoPessoaFisica();
fisica.setters;


Operadora operadora = new Operadora();
operadora.setters;
fisica.setOperadora(operadora);

Aqui está o insert na classe DAO.

public boolean inserir (ContatoPessoaFisica contatoPessoaFisica){
        String sql="insert into ContatoPessoaFisica (nome,apelido,telefone,email) values (?,?,?,?)";

        try {
            PreparedStatement ps=conexao.prepareStatement(sql);
            ps.setString(1, contatoPessoaFisica.getNome());
            ps.setString(2, contatoPessoaFisica.getApelido());
            ps.setString(3, contatoPessoaFisica.getTelefone());
            ps.setString(4, contatoPessoaFisica.getEmail());

            return ps.executeUpdate() == 1;
        } catch (Exception e) {
            System.out.println("erro no insert de ContatoPessoaFisica"+e);
            return false;
        }
}

E aqui o insert na classe Controle:

public static void inserir() {
        
        ContatoPessoaFisica c = new ContatoPessoaFisica();
        
        c.setNome(JOptionPane.showInputDialog("Informe o nome"));
        c.setApelido(JOptionPane.showInputDialog("Informe o sobrenome"));
        c.setTelefone(JOptionPane.showInputDialog("Informe o Telefone"));
        c.setEmail(JOptionPane.showInputDialog("Informe o email"));
       
        
        ArrayList<Operadora> listaOperadora=  OperadoraDAO.listar();
        Operadora p = (Operadora)JOptionPane.showInputDialog(null, "Selecione a operadora",
                "Operadora ", JOptionPane.INFORMATION_MESSAGE,
                null, listaOperadora.toArray(), null);
 
        c.setOperadora(p);
        
        if (dao.inserir(c)) {
            JOptionPane.showMessageDialog(null,"Contato incluido com sucesso");

        } else {
            JOptionPane.showMessageDialog(null,"Erro ao inserir contato");
        }
    }

E aqui o listar da Operadora, onde é retornado um ArrayList com os dados da operadora. Que são passados para o objeto ContatoPessoaFisica na classe controle.

public static ArrayList<Operadora> listar() {
        ArrayList<Operadora> lista = new ArrayList<Operadora>();
        try {
            Statement st = conexao.createStatement();
            ResultSet rs = st.executeQuery("select * from Operadora");
            while (rs.next()) {
                Operadora op = new Operadora();
                op.setIdOperadora(rs.getInt("idOperadora"));
                op.setNomeOperadora(rs.getString("nomeOperadora"));
                op.setCodigo(rs.getInt("codigo"));
                op.setTarifa(rs.getDouble("tarifa"));    
                lista.add(op);
                
            }
        } catch (Exception e) {
            System.out.println("Erro: problemas ao listar Operadora. Verificar a OperadoraDAO" + e);
        }

        return lista;
}

Então sua DAO está errada! siga o exemplo que eu te passei, outra coisa na hora de inserir contatospessoafisica e/ou contatospessoajuridica tem que passar o código da operadora na SQL, faltou isso de inicio do que vi!

Será que devo especificar aqui o operadora_idoperadora pertencente ao ContatoPessoaFisica também?

c.setNome(JOptionPane.showInputDialog("Informe o nome"));
c.setApelido(JOptionPane.showInputDialog("Informe o sobrenome"));
c.setTelefone(JOptionPane.showInputDialog("Informe o Telefone"));
c.setEmail(JOptionPane.showInputDialog("Informe o email"));

No caso o tipo Operadora operadora, que está nas classes contatos não equivaleria ao operadora_idoperadora?

Ou devo criar um abributo do tipo int para receber a operadora, usando FK do banco?

Vou dar uma olhada nisso que você falou. Obrigado por responder. Volto mais tarde a noite.

1 curtida

Olha a minha proposta e reescreva um parte do seu código! A chave está sendo demostrada naquele layout de banco!

E como seria a filtragem no banco para exibir somente somente um Contato relacionado a uma operadora, sem os dados ficarem duplicados?

Cadastro uma operadora. É como se ela recebesse o Contato. Mas parece que como voce falou, devo inverter isso. Vou dar uma olhada, ate mais.

Se seguir o meu Layout, cada contapessoafisica terá uma operadora somente!

Exemplo de SQL:

SELECT 
    c.id, 
    c.telefone, 
    c.email, 
    c.nome, 
    c.apelido, 
    c.operadora_id, 
    a.nome as nomeoperadora,
    a.codigo,
    a.tarifa
FROM contatopessoafisica c 
JOIN operadora a 
             on a.id=c.operadora_id

Blz Dragon ajudou muito. Consegui resolver, o problema está justamente na filtragem mesmo, o codigo java tava perfeito. Obrigado por ajudar