Complex QueryOver - nhibernate

Hi I have to translate folowing sql to QueryOver
Will it be possible ? my actual query may more complex. But I have stuck in this stage.
SELECT InnerQuery.USERID,
InnerQuery.TRAFFICZONEID,
InnerQuery.StatusCategory,
COUNT(*) AS LineCount
FROM (
SELECT MissionID,
UserId,
TRAFFICZONEID,
CASE
WHEN status BETWEEN 1
AND 5
THEN 1
WHEN status BETWEEN 6
AND 8
THEN 2
WHEN status BETWEEN 9
AND 17
THEN 3
ELSE 0
END AS [StatusCategory]
FROM mission
) AS InnerQuery
LEFT OUTER JOIN trafficzone t ON InnerQuery.TRAFFICZONEID = t.Trafficzoneid
GROUP BY InnerQuery.USERID,
InnerQuery.TRAFFICZONEID,
InnerQuery.StatusCategory
Is it possible to do that kind of uery in QueryOver ? Or else what is the best way to do it with NHibernate ?
Thank you,
DineshNS

I suggest you use HQL for this.
From all the query methods supported by NHibernate, it's the one that works best with free-form queries.
The only thing it does NOT support directly is an outer join to a subquery. You can fake that using an implicit join with the subquery (from A, (subquery) B where A.X = B.X) and a UNION for items that don't have matching elements in the subquery.

For a complex query, you could create a view in database and use that from NHibernate.

Related

Is there a way to handle a complex SQL query in a Java application using Spring and Hibernate, connecting to an Oracle database?

I have a Java application using Spring and Hibernate. I'm updating a legacy application that was using a stored procedure to get a count of rows from the below query and display the count on a home page. I've been trying to implement QueryDSL, as we need this to be type safe and cannot use inline strings, but can't seem to get the syntax correctly (if it is even possible to handle a query like this in QueryDSL)
SELECT count(*) from TABLE_A A
LEFT OUTER JOIN
(
SELECT ONE_ID, TWO_ID, STATUS, STATUS_CHANGE_DATE
FROM
(
SELECT B.ONE_ID, B.FLOW_STATUS_ID, C.DESCRIPTION, B.STATUS_CHANGE_DATE,
MAX (B.STATUS_CHANGE_DATE) OVER (PARTITION BY B.ONE_ID) RECENT_DATE
FROM TABLE_B B
INNER JOIN TABLE_C C ON B.TWO_ID = C.THREE_ID
)
WHERE STATUS_CHANGE_DATE = RECENT_DATE
) D
ON D.ONE_ID = A.THREE_ID WHERE D.TWO_ID = 3;
Can anyone please point me in the right direction or recommend another way to handle this query?
Thanks!
I tried using QueryDSL's HibernateQueryFactory to construct the query but I'm not sure how to construct it in a way that handles the outside left join with the two inner queries that also includes an inner join.

Is there a way to make the faster ordered SQL TOP 1 query as Entity Framework query?

Here is two ways to get the top 1 row from a table ordered
Slower:
select top 1 *
from movies m
where m.Distributor = 'any'
order by m.IMDB_Rating desc
Faster:
select top 1 m.*
from movies m
left join movies m2 on m.Distributor = m2.Distributor
and m2.IMDB_Rating > m.IMDB_Rating
where m.Distributor = 'any'
and m.IMDB_Rating is not null
and m2.id is null
The first one is simpler, but the second one is faster.
So, is there a way to make the second query using Entity Framework?
If there is no way to make this query in EF or EF Core, could you give me another query as fast as the second one if it is possible?
I'm sorry if it is duplicated, I can't find any answer to my question
Thanks a lot!
For this query:
select top (1) m.*
from movies m
where m.Distributor = 'any'
order by m.IMDB_Rating desc;
You want an index on movies(Distributor, IMDB_Rating desc).
I cannot speak to why the second version would be faster.

GroupBy and SelectMany analogues in SQL?

In C# I can group collection items, run subquery for each group and then return rows.
var rows = collection.GroupBy( item => item.Property).SelectMany( g => ...);
In SelectMany part query can run against the collection (due to the closure) or/and the grouped items. The results of subqueries are then combined.
My problem is that I do not know how to achieve the same with SQL query.
Subquery placed inside select can be parametrized but allows to return one row at most, and joins do not exclude items that do not belong to the group.
I have no sql-oriented mindset and apologize if it is really a dumb question.
Example of temporal DB:
id instance_id data from to
1 1 A 20140301 20140310
2 1 AA 20140311 20140321
3 2 B 20140301 20140305
4 2 BC 20140306 20140316
I need to run subqueries for each instance_id i.e. against historical data of the entity and select only part of the history for each entity.
You can do that using CROSS APPLY like this:
SELECT *
FROM mytable
CROSS APPLY (
SELECT *
FROM othertable
WHERE instance_id = mytable.instance_id)
I would recommend using a join if possible, but APPLY comes in handy if you don't have a simple join condition. This article explains it nicely.

TSQL Aggregate function to produce a yes or no flag

I will attempt to explain my problem using a similar but simpler problem. Let's say that I'm writing software for a library, which has a table of Patrons and Books. In addition, it has a CheckOuts table which associates Patrons to any Books (1 per row) that they have checked out.
I'm using MSSQL 2005 and need to build a view or stored procedure that contains two columns, PatronID and HasBook, which needs to be dynamically generated: 1 if the patron has one or more book checked out, and 0 otherwise.
Here is my first attempt at writing a query to do this:
SELECT PatronID, MIN((SELECT 1, COUNT(BookID) FROM CheckOuts WHERE CheckOuts.PatronID = Patrons.PatronID)) AS HasBook
FROM Patrons
The error I'm receiving is:
Cannot perform an aggregate function
on an expression containing an
aggregate or a subquery.
I'm a very new SQL user, so if that query makes you cringe, I would sincerely appreciate any advice you would like to give. I'm very interested in the "right" way to do this.
Well, if you just want to know if the PatronId has any checkout, you can do the following:
SELECT PatronID, CASE WHEN B.PatronId IS NOT NULL THEN 1 ELSE 0 END AS HasBook
FROM Patrons A
LEFT JOIN (SELECT PatronId FROM CheckOuts GROUP BY PatronId) B
ON A.PatronId = B.PatronId
Try this:
SELECT a.PatronID, CASE b.PatronID WHEN NULL THEN 0 ELSE 1 END
FROM Patrons a
LEFT OUTER JOIN Patrons b ON b.PatronID = a.PatronID AND EXISTS (SELECT * FROM CheckOuts c WHERE c.PatronID = b.PatronID)
EDIT: Lamak's solution, using the derived table, may be better than mine. His is probably faster.

Can this SQL with subquery in SELECT be converted to Hibernate 3.0.5 HQL?

Is it possible to convert the following into HQL 3.0.5 using any approach? Subqueries, outer joins with predicates, etc?
SELECT c.case_id,
(SELECT MAX(a.begin_date)
FROM assignment a
WHERE a.case_id = c.case_id)
FROM case c
The relationship between case and assignment is 1 to many. The intent of the query is to return all cases and their most recent assignment begin date, if one exists.
I'm having difficulty finding exactly what Hibernate 3.0.5 supports and what it doesn't but I've seen indications that it only supports subqueries in the WHERE.
EDIT: If no assignment exists for a given case, the case_id should still return and the assignment begin date returned should be null.
Firstly, your SQL query can be rewritten with JOIN and GROUP BY instead of subquery:
SELECT c.case_id, MAX(a.begin_date)
FROM case c LEFT JOIN assignment a ON a.case_id = c.case_id
GROUP BY c.case_id
In this form it can be easily converted to HQL, something like this (depends on mapping):
SELECT c.id, MAX(a.beginDate)
FROM Case c LEFT JOIN c.assignments a
GROUP BY c.id
HQL does supports subselects provided the underlaying DB has it[Eg. Oracle 10g].
As explained in this article.