J'ai une entité Hibernate qui ressemble à ceci (accesseurs omis par souci de concision):
@Entity
@Table(name="FeatureList_Version")
@SecondaryTable(name="FeatureList",
pkJoinColumns=@PrimaryKeyJoinColumn(name="FeatureList_Key"))
public class FeatureList implements Serializable {
@Id
@Column(name="FeatureList_Version_Key")
private String key;
@Column(name="Name",table="FeatureList")
private String name;
@Column(name="VERSION")
private Integer version;
}
Je souhaite créer une requête HQL qui récupère la version la plus récente d'une FeatureList. Le type de requête suivant fonctionne:
Select f.name, max(f.version) from FeatureList f group by f.name
Le problème est que cela ne remplira pas le champ clé, dont j'ai besoin pour contenir la clé de l'enregistrement avec le numéro de version le plus élevé pour la FeatureList donnée. Si j'ajoute f.key dans la sélection, cela ne fonctionnera pas parce qu'il n'est pas dans le groupe par ou un agrégat et si je le mets dans le groupe, le tout cesse de fonctionner et cela me donne simplement chaque version en tant qu'entité distincte.
Alors, quelqu'un peut-il aider?
La version simple de cette requête ressemble à ceci (en supposant que (name, version)
les paires sont uniques):
select f from FeatureList f
where f.version =
(select max(ff.version) from FeatureList ff where ff.name = f.name)
J'ai fait un scénario ici,
Tableau
key name version
----------- -------------------- -----------
1 adeel 1
2 adeel 2
3 adeel 3
4 ahmad 1
5 ahmad 2
6 ahmad 3
7 ahmad 4
8 ansari 1
9 ansari 2
10 ansari 3
Résultat en utilisant votre requête d'origine
>> select f.name, max(f.version) from FeatureList f group by f.name
name max(f.version)
-------------------- ------------
adeel 3
ahmad 4
ansari 3
Résultat en utilisant la requête souhaitée
>> select fl.* from FeatureList fl
where (fl.name, fl.version) in (select f.name, max(f.version)
from FeatureList f group by f.name);
key name max(fl.version)
----------- -------------------- -----------
3 adeel 3
7 ahmad 4
10 ansari 3
NB: J'ai essayé cette fois avec MySQL. Ça marche. Je suis à peu près sûr que MS SQL Server possède également l'opérateur IN (...)
. Vous avez juste besoin d'utiliser session.createNativeQuery()
dans Hibernate.
Modifié pour fonctionner sur réponse de axtavt
Comme nous l'avons découvert, cela peut être aussi simple que,
select f from FeatureList f
where f.version =
(select max(ff.version) from FeatureList ff where ff.name = f.name)
Essayez maintenant la même chose en utilisant Hibernate Criteria API ,
DetachedCriteria versions = DetachedCriteria.forClass(FeatureList.class, "f")
.setProjection( Property.forName("f.version").max())
.add(Property.forName("f.name").eqProperty("fl.name"));
session.createCriteria(FeatureList.class, "fl")
.add( Property.forName("fl.version").eq(versions) )
.list();
Vieille question, mais je pensais offrir mon expérience ici également aux futurs utilisateurs:
select f from FeatureList f where f.version =
(select max(ff.version) from FeatureList ff where ff.name = f.name);
Cela fonctionne très bien, mais si les conditions suivantes sont réunies:
ce qui suit semble être beaucoup plus rapide:
FROM FeatureList ORDER BY version DESC LIMIT 1;
Mes essais sur une requête similaire avec 700 000 enregistrements dans le tableau prennent environ 0,19 s pour l'ancienne version et 0,05 s pour la dernière.
Que dis-tu de ça,
from FeatureList fl where (fl.name, fl.version) in (
select f.name, max(f.version) from FeatureList f group by f.name)
Remarque: essayez avec la fonction createNativeQuery()
, c'est une requête Oracle valide, vous n'êtes sûr d'aucune autre base de données.
Une question, la paire, name
et version
, est-elle unique? Si oui, alors c'est bien, sinon si la paire n'est pas unique, que pensez-vous comment une clé sera sélectionnée? Supposons que l'un des enregistrements de la requête d'origine soit,
f.name max(f.version)
------ --------------
Django 1.2
et supposons qu'il y a 3 key
s ayant la même paire. Maintenant, répondez, quelle clé doit être affectée à cet enregistrement? J'espère que vous comprenez mon point.
Que diriez-vous d'utiliser distinct + order by au lieu de group by?
select f.id, distinct(f.name), f.version from FeatureList f order by f.version desc