2016-12-20 13 views
6

aşağıdaki iki tablo düşünün:JPA Ölçüt API'sinde bir alt sorguda bir ORDER BY kullanılmasının alternatifleri nelerdir?

  1. Project (id, project_name)
  2. Status bir Project olmuştur ettiği bütün durumları içerir
  3. Status (id, id_project, status_name)

.

En son durumun "yeni" olduğu tüm projeleri sorgulamak istediğimizi bildirelim. Ben ile gelip SQL sorgusu: Ben Kriterler API kullanarak yukarıdaki sorgu çoğaltmak için çalışıyorum ve sınıf CriteriaQuery yöntemi orderBy var ama sınıf Subquery değil fark

SELECT q.id_project FROM status q 
WHERE q.status_name like 'new' 
AND q.id IN (
    SELECT TOP 1 sq.id from status sq 
    WHERE q.id_project = sq.id_project 
    ORDER BY sq.id DESC) 

.

Ben şimdiye kadar gelmelisin olan kriterler Sorgu: Subquery sq sonuçlarını sıralama ve sadece en son olanı döndürerek için herhangi bir yöntem olmadığı için burada saplanıp

CriteriaQuery<Project> q = criteriaBuilder.createQuery(Project.class); 
Root<Status> qFrom  = q.from(Status.class); 
Subquery<Integer> sq  = q.subquery(Integer.class); 
Root<Status> sqFrom  = sq.from(Status.class); 

sq.select(sqFrom.get(Status_.id)) 
    .where(criteriaBuilder.equal(sqFrom.get(Status_.project), qFrom.get(Status_.project)) 

.

Alt sorgusu sıralamak için, yukarıda açıklanan senaryoda istenen sonucu elde etmek için alternatifler nelerdir?

+0

Dize tabanlı JPQL izin vermez: bir ilintisiz forma toplama işlevleri alt sorgu, bu yüzden bir ilintisiz alt sorgunun yazma açıkça epeyce (örnek JPQL kullanır altında, Ölçüt API eşdeğer basit olmalı) iyi olduğunu düşünüyorum Bir alt sorguda SİPARİŞ BY, ve Kriterler bunu basitçe yansıtır. "subquery :: = simple_select_clause subquery_from_clause [nerede_clause] [groupby_clause] [sahip_clause]" –

+0

@NeilStockton Anladım ki, bu yüzden "sq.id" en yüksek değerini döndürmek için alternatif çözümler –

+0

soruyorum. alt sorgu (nerede yan tümce)? "SELECT MAX (sq.id) FROM durum sq WHERE q.id_project = sq.id_project" alt sorgusunu yapamaz mısın? –

cevap

2

tahmin ediyorum maksimum değer bulmak. Zaten yayınlandığı gibi, bir Kriterler Sorgusuna dönüştürülebilir.

Maalesef Kriterler Sorgular alt sorguda sıralamayı desteklemez - bu ilgili yanıtları görmek: Eğer gerçekten bir ORDER BY gerekiyorsa

https://stackoverflow.com/questions/19549616#28233425 https://stackoverflow.com/questions/5551459#5551571

Alternatif (örn) Aşağıdaki örnekte bir değer aralığını sağlamak için yerine CriteriaQuery bir yerli sorgu kullanmaktır: diğer yanıtlar yanı sıra

Query query = entityManager.createNativeQuery(
    "SELECT bar FROM foo WHERE bar IN (SELECT TOP 10 baz FROM quux ORDER BY quuux)"); 
2

Sizin alt sorgu, bunu belirttiğimiz gibi,

SELECT MAX(sq.id) FROM status sq WHERE q.id_project = sq.id_project 

ait JPQL denk olur ki tamamen JPA spec tarafından desteklenmesi gerektiğini. tüm kayıtları sipariş karşılaştırıldığında yavaş olarak

SELECT q.id_project FROM status q 
WHERE q.status_name like 'new' 
AND q.id = (
    SELECT MAX(sq.id) from status sq 
    WHERE q.id_project = sq.id_project) 

Bu aynı zamanda daha hızlı olacaktır: Kriterler API açısından, ben SELECT MAX yerine SELECT TOP 1 ... ORDER BY ... kullanarak alt sorgu yazılmış olabilir bu

Subquery<Integer> sq  = q.subquery(Integer.class); 
Root<Status> sqFrom  = sq.from(Status.class); 
Expression maxExpr = criteriaBuilder.max(sqFrom.get(Status_.id)); 
sq.select(maxExpr).where(criteriaBuilder.equal(sqFrom.get(Status_.project), qFrom.get(Status_.project)) 
1

, ben veritabanı iyileştirici örtük bir korelasyon yeniden yazmak mümkün olduğunu sanmıyorum

select q.project from Status q 
where q.name = 'new' 
    and q.id in (select max(sq.id) from Status sq group by sq.project.id) 
İlgili konular