J'ai une requête SQL que j'ai du mal à créer à l'aide de NHibernate Criteria :
SELECT ID, COLA, COLB, COLC
FROM table
WHERE COLC='something' AND ID IN (SELECT ID FROM (SELECT MAX(ID) as ID, COLA FROM table WHERE COLB='something' GROUP BY COLA) subquery)
ORDER BY ID DESC
À l'origine, j'avais une question un peu plus simple :
SELECT ID, COLA, COLB, COLC
FROM table
WHERE COLC='something' AND ID IN (SELECT MAX(ID) FROM table WHERE COLB='something' GROUP BY COLA)
ORDER BY ID DESC
Cependant, avec NHibernate, si j'utilise un "GROUP BY", il ajoute automatiquement le champ à l'instruction SELECT, et je n'ai aucun moyen de l'arrêter (pour autant que je sache).
En gros, j'ai besoin de trouver le dernier enregistrement groupé par une colonne arbitraire (dans cet exemple, "COLA"). Je sélectionne l'ID maximum pour essayer d'obtenir le dernier enregistrement (mais cela pourrait être autre chose, comme "MAX(UPDATED)"). Après avoir obtenu l'ensemble des derniers enregistrements, je les filtre à nouveau ("WHERE COLC='quelque chose'"), et je sélectionne les colonnes dont j'ai besoin dans le résultat.
S'il existe un meilleur moyen d'obtenir les mêmes résultats, je serais heureux de l'entendre. Mes compétences en SQL sont médiocres, au mieux.
Dans NHibernate, j'ai pu obtenir les deux requêtes correctement, mais la partie du milieu - "SELECT ID FROM" - ne fonctionnait pas.
La requête principale :
DetachedCriteria.For<table>()
.Add<table>(x => x.COLC == "something")
.Add(LambdaSubquery.Property<table>(x => x.ID).In(subquery));
Et la sous-requête :
DetachedCriteria.For<table>()
.Add<table>(x => x.COLB == "something")
.SetProjection(Projections.ProjectionList()
.Add(LambdaProjection.Max<table>(x => x.ID))
.Add(LambdaProjection.GroupProperty<table>(x => x.COLA)));
Le critère de la sous-requête place "COLA" dans la liste de sélection (à cause de la GroupProperty), il est donc inutilisable seul, et c'est pourquoi je dois trouver comment faire le "SELECT ID FROM (SELECT ..." dans les critères. Une fois combinées, elles produisent le SQL invalide suivant (parce que la sous-requête renvoie plus d'une colonne) :
SELECT ID, COLA, COLB, COLC
FROM table
WHERE COLC='something' AND ID IN (SELECT MAX(ID), COLA FROM table WHERE COLB='something' GROUP BY COLA)
ORDER BY ID DESC
Edit : Cela pourrait également permettre de voir le type de données et de résultats que je souhaite obtenir :
ID COLA COLB COLC
1 1 someone someother
2 1 something someone (Matches subquery, but not the max. ID)
3 1 something something (Matches subquery and main query)
4 2 someone something
5 2 something someother (Only matches subquery)
6 3 someone someother
Le résultat que je veux ici est l'ID maximum pour un ensemble donné de "COLA", où "COLB" correspond à "quelque chose", donc je voudrais que la sous-requête renvoie {3, 5}. Au final, la requête ne renvoie que l'enregistrement correspondant à l'ID 3 (la clause WHERE externe élimine le 5 car COLC est erroné). Les données réelles dans COLB et COLC ne sont pas pertinentes - je les utilise simplement pour filtrer davantage les résultats.
Je pense qu'au fond, je veux le dernier enregistrement (ID maximum) pour chaque série de COLA.
SELECT ID, COLA, COLB
FROM table
WHERE ID IN (SELECT MAX(ID) FROM table GROUP BY COLA)
ORDER BY ID DESC