DISTINCT não funciona JPA/JPQL

31 respostas
jpqljpa
B

Como faço para usar o distinct ??’

Método

31 Respostas

A

Não manjo de JPQL, mas para este caso acredito que se aplica o que é válido para SQL… para que te retornem somente registros distintos, você precisa especificar quais campos quer obter no resultado. Porque do jeito que a query está escrita, retornarão todos os campos da tabela. Supondo que ela tenha 10 campos, e em dois registros por exemplo os 9 primeiros tenham valores repetidos, somente no décimo haja valores diferentes… precisaria escrever a query somente com os 9 primeiros campos.

B

Preciso especificar os campos?

A

Se eu estivesse com o mesmo problema que você, conhecendo o que eu conheço de SQL, deduziria isto. Mas veja que eu disse no começo… não conheço JPQL. Ainda faço fogo usando pedras de jdbc bruto.

L
SELECT DISTINCT(u.atributo_para_realizar_distinct) FROM Usuario u

Você tem que especificar qual atributo você quer que seja único. Não faz sentido utilizar a primary key, pois já é única. Pode utilizar algo como nome ou email (no caso de usuário).

B

OK vou testar amigo.

B

value="#{lancamento.idlancamentoCtLancamento.idlancamento}": The class ‘java.lang.Integer’ does not have the property ‘idlancamentoCtLancamento’.

B

Está dando esse erro, estou ver o q é.

L

Pode postar a query inteira? Você tá tentando aparencentente acessar a propriedade idlancamentoCtLancamento em um número inteiro lancamento. Você tem que colocar no distinct a propriedade do objeto raiz da query que quer que seja distinta.

Por exemplo, se você tem uma entidade Lançamento com os campos id, nome e data, você pode fazer o seguinte:

SELECT DISTINCT(lanc.data) FROM Lançamento lanc

Essa query te devolve os lançamentos com datas diferentes. Se há mais de 1 lançamento com a mesma data, nesse caso, apenas 1 será retornado.

B

public List lista() {

TypedQuery query;
query = em.createQuery("SELECT DISTINCT(c.idlancamentoCtLancamento.idlancamento) FROM CtLancamentoconta c ", CtLancamentoconta.class);

List<CtLancamentoconta> results = query.getResultList();
    
     System.out.print(results);
      
    if (results.isEmpty()) {
        return null;
    }
    return results;
 }
L

A classe CtLancamentoConta tem um atributo idLancamentoCtLancamento, certo? Qual o tipo desse atributo? Tenta fazer algo como

SELECT DISTINCT(c.<atributo para distinguir>) FROM CtLancamentoconta c
B

ilustre, o idLancamentoCtLancamento faz referência a classe Lançamento que tem relação com a classe LançamentoConta, eu quero restringir em função do dlancamentoCtLancamento.idlancamento nota que a partir do objecto dlancamentoCtLancamento eu pego o seu id idlancamento

Vou tentar fazer isso.

L

Então você tem a classe LancamentoConta, que tem um @OneToMany para Lancamento e quer fazer o distinct em um atributo do Lancamento? Desculpe, não consegui entender a relação entre as classes.

B

javax.el.PropertyNotFoundException: The class ‘edu.ucan.sighp.entity.ct.CtLancamento’ does not have the property ‘idlancamentoCtLancamento’.

SELECT DISTINCT(c.idlancamentoCtLancamento) FROM CtLancamentoconta c

B

Sim, é isso ilustre.

B

B

Este elemento está repetido… quero trazer apenas um deles.

L

Eu juro que to tentando entender kkkkk Eu ainda não compreendi a estrutura de classes o que exatamente você quer buscar no banco.

Parece que existe uma classe que possui uma coleção de lançamentos. Cada lançamento, dentro dessa coleção, possui um “alvo”, o diário daquele lançamento, isso?

Por exemplo:

Lancamentos tem uma List dentro dela, contendo:

id    diario
1        1
2        1

Você quer que apareça o lançamento no diário 1 apenas uma vez, para essa entidade Lancamentos?

L

Você pode fazer o seguinte também:

SELECT DISTINCT(lancamento.diario) lancamento FROM Lancamentos lancamentos 
INNER JOIN Lancamento lancamento;

Essa query vai retornar uma List<Lancamento> com diários distintos, para todos os conjuntos de lançamentos.

Por exemplo, se você tem o conjunto de Lançamentos A com 2 lançamentos dentro, apontando pros diários 1, 1 e 2, e um outro conjunto de Lançamentos B, apontando pros diários 1 e 3, essa query irá retornar os Lancamentos pros diários 1, 2 e 3 (sem duplicar o 1).

Se você quer os lancamentos distintos de um conjunto de lançamentos específico, você pode fazer:

SELECT DISTINCT(lancamento.diario) lancamento FROM Lancamentos lancamentos 
INNER JOIN Lancamento lancamento WHERE lancamentos.id = :id;

e informar parâmetro o id pra query. Seguindo o mesmo exemplo anterior, se o ID for o do Lançamentos A, só vai vir 2 elementos na List<Lancamento>, os que contem os diários 1 e 2 (o 1 aparece só uma vez).

B

Calma, vou tentar te fazer entender…

B

Calma, vou te fazer compreender melhor o cenário…

B

Bom dia amigo, é o seguinte, eu tenho uma tabela lancamento que tem relação com uma tabela lancamentoconta conforme mostra a figura abaixo

Agora, aqui nessa outra imagem eu tenho uma lista dos lançamentos essa lista vem da minha ManagedBean Lançamento.

Resultado

Neste outro cenário, eu tenho a mesma tabela a ser preenchida com uma lista de lençamentocontas como ela tem relação com a tabela lançamento a partir do idlancamento eu pego todos os atributo da tabela lançamento. Porém utilizando uma lista de lançamentoconta eu terei os registros duplicados porque a operação de lançamento envolve duas contas(débito e credito) logo idlancamento na tabela lancamentoconta é duplicado mas com a mesma informação. Vê a imagem abaixo

Resiltado usando uma lista do tipo lançamentoconta

OBS.: Eu pretendo ter uma lista do tipo lancamentoconta sem os itens repetidos.

Abraços!

L

Opa Bruno, bom dia!

Acho que agora compreendi melhor o problema, obrigado! Essa query aqui talvez funcione para você:

SELECT 
DISTINCT(ctLancamentoConta.<ATRIBUTO_PARA_DISTINGUIR>) ctLancamentoConta
FROM CtLancamento ctLancamento
JOIN p.ctLancamentoConta WHERE ctLancamento = :lancamento

Lendo meio de trás pra frente, essa query vai:

  1. Fazer um join de Ct_Lancamento com Ct_LancamentoConta, somente para o teu Ct_Lancamento específico (por causa do where com a comparação de CtLancamento). Eu acho que você tem o objeto CtLancamento específico ali no teu bean, certo? O mesmo para o qual você quer listar os lancamentos diários. Se tem, você pode fazer assim:

    TypedQuery<CtLancamentoConta> q = em.createQuery(stringComAQueryAliDeCima)
     .setParameter("lancamento", CtLancamentoQueTemNoBean);
     return q.getResultList();
    
  2. A respeito do distinct, cabe a você decidir qual é o parâmetro que você quer usar para distinguir duas entidades. O teu exemplo dos dois lancamentos “iguais” não é muito bom, porque todos os atributos deles são iguais. Você tem que dizer o que caracteriza um lancamento repetido. É o diário? O documento? O valor? A data?

Eu não tenho certeza, mas acho que você pode passar mais de um parâmetro no distinct.

Outra coisa, eu estava pesquisando aqui e descobri que talvez essa query não te retorne exatamente a lista de CtLancamentoConta, mas os atributos que você selecionar no DISTINCT. Eu to sem ter como testar aqui. Tenta e me diz o que aconteceu!

B

Ok, vou testar. Mas vale dizer que o caracteriza um lançamento repetido é o idLançamento que está na tabela lançamentoconta, como um lançamento em contabilidade envolve duas contas então o idlançamento na tabela lançamentoconta se repete duas vezes porque temos uma conta a debitar e outra a creditar. Mas Ivbarbosa vamos fazer o seguinte, vamos supor que eu quero uma query que me retorna todos os elementos da tabela lancamentoconta usando o distinct no idlancamento porque é o mesmo. Vê essa imagem dos dados da tabela idlancamentoconta.
Nota que nesta tabela o idlancemento está repatido pois eu quero uma query que me traz todos os itens dessa tabela lancamentoconta mas usando o distinct no idlancamento. OBS. Esquece a tabela lancamento.

Desde já eu agradeço o teu apoio

B

Deste uma olhada?

L

Tentou fazer assim?

SELECT DISTINCT(lc.idLancamento_ct_lancamento) lc 
FROM LancamentoConta lc

O problema é que eu não tenho certeza se as queries com DISTINCT retornam a entidade ou apenas uma lista com o atributo que você quer distinto. Você sabe o que acontece? Não tenho como testar por enquanto.

Se não funcionar, confesso que não sei o que fazer para conseguir obter o resultado que você quer, vou ter que dar uma estudada mais tarde porque to realmente curioso pra descobrir como é que se faz isso. Assim que eu descobrir eu respondo pra ti.

L

Bruno,

Depois de dar uma estudada, eu vi que o DISTINCT no JPA funciona exatamente como no SQL. Você aplica DISTINCT num certo campo (ou coluna), e aquela coluna apenas é retornada. Por exemplo

SELECT DISTINCT(pessoa.nome) FROM Pessoa p

Retorna apenas os nomes distintos. Sendo nome um campo que não é chave primária, não dá para eliminar duplicatas com ele. O que eu te falei antes para tentar fazer está completamente errado.

O que tem como fazer também, é o seguinte (que você já tentou)

SELECT DISTINCT(p) FROM Pessoa p

O que é utilizado aqui para fazer o DISTINCT é a chave primária de Pessoa.

No teu caso, você quer uma lista de lançamentos distinguidos pelo nome do negócio ali, o Documento, ou a Descrição, que acho que não são chaves primárias.

Até agora eu ainda não descobri como buscar dessa maneira que você quer. Algumas alternativas são:

  1. GROUP BY na coluna que você quer única, montando a lógica de agrupamento na query
  2. Filtrar na aplicação, e não no DB
B

Ok, mas ultrapassei essa situação de uma outra forma mas preciso mesmo dessa solução. vou ler mais, olha tem um outro cenário… vou te marcar no tópico.

Abraços

L

Acabei de pensar numa solução com o GROUP BY.

A ideia da query é a seguinte: você vai selecionar os IDs com nomes únicos de lançamento, assim:

SELECT MIN(l.id) FROM Lancamento l GROUP BY l.nome

Beleza? Essa query vai te retornar apenas 1 ID para cada nome de lancamento. Você vai utiliza-la como subquery na query principal, assim:

SELECT lanc FROM Lancamento lanc WHERE lanc.id IN (SELECT MIN(l.id) FROM Lancamento l GROUP BY l.nome)
B

Ok, vou implementar depois te dou um toque.

L

Tá com cara de gambiarra, não sei porque hahahahaha

Mas acredito que vá funcionar.

B

ya kkkk

Criado 31 de janeiro de 2017
Ultima resposta 9 de fev. de 2017
Respostas 31
Participantes 3