Average of difference between two dates using Hibernate JPA in SQL Server - sql-server

I'm having a table with columns: id, task_type, start_time, end_time. I need to get the Average Time taken by each task. In SQL query I could do:
SELECT task_type, AVG(DATEDIFF(MS, end_time, start_time)) AS average_time GROUP BY task_type
I'm unable to use the DATEDIFF in JPA as it's not supported. If I pass the nativeQury to the JPA "#Query" It shows the column names which are not included in SELECT statement as Invalid, suppose if I pass the aforementioned query as native query I get error the column name id is not valid.
It would be a great help if anyone is able to point out what I'm missing here.
Note: The project is a micro service architecture, database is stored in a Microsoft SQL Server and the API is being written in Spring Boot.

Regarding calling vendor-specific and user-defined functions, see this tutorial on ways you can do that from JPQL.
The function() syntax might not work for you due to the MS parameter (you could probably register a Hibernate user type for that, which is a nuissance). Registering a function in the dialect should work just fine, though. You'll probably want to implement SQLFunction yourself, rather than using the StandardSQLFunction implementation.
As for why the native query doesn't work for you, what is the result class you're trying to map your query onto? Try using an interface or a DTO with the same property names as the aliases used in the query, similar to how you would use projections. If that doesn't work, a result set mapping should.

The way I'd write that in JPQL:
SELECT ent.taskType, AVG( EXTRACT (EPOCH FROM (ent.endTime - ent.startTime)))
FROM Entity ent
GROUP BY ent.taskType
This is the result in seconds, you can manipulate de extract result to whatever you want to show in view.

I solved this by creating the Projection class and JPQL query.

Related

EF Core Views and SQL Parameters

I have created a view on SQL Server which produces a report for monthly totals. The view has been added to my DB Context and mapped successfully, therefore I am in a position where I can successfully get the results of my view as follows:
var list = db.MonthlyTotals.ToList();
However, I need to be able to restrict between dates and therefore needs to pass in some parameters for a start and end date.
Is this possible with either EF Core 6 or 7? Or do I need to use stored procedures instead?
I have created a view...I need to be able to restrict between dates and therefore needs to pass in some parameters for a start and end date...Is this possible with either EF Core 6 or 7?
Views don't use parameters, that's by design of the SQL Server Engine, and has nothing to do with whatever ORM you use, such as EF Core. If you really want to use parameters, then use stored procedures.
But the good news is, your use case is simple enough that you shouldn't need parameters anyway. Like Gert suggested in the comments, just use a Where clause against your view instead.
You can achieve this in C# with LINQ's method syntax like so:
var list = db.MonthlyTotals
.Where(mt => mt.YourDateColumn >= someDateVariable && my.YourDateColumn < someOtherDateVariable)
.ToList();
There's also query syntax with LINQ, which more closely resembles T-SQL code, but in my opinion is less intuitive in the context of C# as opposed to method syntax.

Hibernate Entity Manager: Result Set Mapping

I'm new to Hibernate and I am a fan of iBATIS, but my new work environments forces me to use Hibernate. In the current scenario at my workplace, there are many complex select queries that I feel hibernate doesn't handles very well.
So I thought of writing my own native SQL select queries, with lots and lots of joins and conditions. So far so good.
I'm using the EntityManager to fire the queries and return the result set. The sample code will look like this:
String sqlQuery="select COL_1, COL_2 from MY_TABLE_NAME";
Query q=em.createNativeQuery(sqlQuery,);
List resultList=q.getResultList();
Please keep in mind this is just a code sample. I would like to have a way so that the result set as in this example (COL_1 and COL_2) can be mapped to my JAVA Class that has two (or more) fields.
Also note that this JAVA Class can not be an Entity that is linked to a table, So I need a way to define any of my JAVA class as a resultClass, the way we do in iBATIS.
Is there any way to do it? SO that the I just define a mapping somewhere for any JAVA class and the result set from query gets mapped to my JAVA Class automatically
String sqlQuery="select COL_1, COL_2 from MY_TABLE_NAME";
Query q=em.createNativeQuery(sqlQuery,MY_TABLE_NAME.class);
List<MY_TABLE_NAME> resultList=q.getResultList();
look variable in IDE debug mode, you will get what you want.

How can I call a stored procedure without table names in HQL?

I am trying to fetch the current timestamp through a stored procedure in HQL. This means my code looks something like the following:
var currentTimestamp =
session.CreateQuery("SELECT CURRENT_TIMESTAMP()")
.UniqueResult<DateTime>();
This doesn't work. Specifically, it throws a System.NullReferenceException deep inside of the NHibernate HqlParser.cs file. I played around with this a bit, and got the following to work instead:
var currentTimestamp =
session.CreateQuery("SELECT CURRENT_TIMESTAMP() FROM Contact")
.SetMaxResults(1)
.UniqueResult<DateTime>();
Now I have the data I want, but an HQL query I don't. I want the query to represent the question I'm asking -- like my original format.
An obvious question here is "Why are you using HQL?" I know I can easily do with this session.CreateSQLQuery(...), hitting our MySQL 5.1 database directly. This is simply an example of my core problem, with the root being that I'm using custom parameter-less HQL functions throughout my code base, and I want to have integration tests that run these HQL parameter-less functions in as much isolation as possible.
My hack also has some serious assumptions baked in. It will not return a result, for example, if there are no records in the Contact table, or if the Contact table ceases to exist.
The method to retrieve CURRENT_TIMESTAMP() (or any other database function) outside of the context of a database table varies from database to database - some allow it, some do not. Oracle, for example, does not allow a select without a table, so they provide a system table with a single row which is called DUAL.
I suspect that NHibernate is implementing in HQL primarily features which are common across all database implementations, and thus does not implement a table-less select.
I can suggest three approaches:
Create a view that hides the table-less select such as 'create view dtm as select current_timestamp() as datetime'
Follow the Oracle approach and create a utility table with a single row in it that you can use as the table in a select
Create a simple stored procedure which only executes 'select current_timestamp()'

Creating SQL Server JSON Parsing/Query UDF

First of all before I get into the question, I'll preface this with the fact that I know that this is a "bad" idea. But for business reasons it is something that I have to come up with a solution to, and I'm hoping that someone, somewhere might have some ideas on how to go about this.
I have a SQL Server 2008 R2 table that has a "OtherProperties" column. This column contains various other, somewhat arbitrary additional pieces of information that relate to the records. There is a business need to create a UDF that we can use to query the results, for example.
SELECT *
FROM MyTable
WHERE MyUDFGetValue(myTable.OtherProperties, "LinkedOrder[0]") IS NOT NULL
This would find a record where there was an array of LinkedOrder entries that contained a value at index 0
SELECT *
FROM MyTable
WHERE MyUDFGetValue(myTable.OtherProperties, "SubOrder.OrderId") = 25
This would find a property "orderId" and use its value in a comparison.
Anyone seen an implementation of this? I've seen implementations of functions. Like this JSONParser that take the values into a table which just will not get us what we need query wise. Complexity wise, I don't want to write a full fledged JSON parser, but I can if I need to.
Not sure if this will suit your needs but I read about a CLR JSON serializer/deserializer. You can find it here, http://www.sqlservercentral.com/articles/CLR/74160/
It's been a long time since you asked your question but there is now a solution you can use - JSON Select which provides various functions for different datatypes, for example the JsonInt() function. From one of your examples (assuming OrderId is an int, if not you could use a different function):
SELECT *
FROM MyTable
WHERE dbo.JsonInt(myTable.OtherProperties, 'SubOrder.OrderId') = 25
DISCLOSURE:
I am the author of JSON Select, and as such have an interest in you using it :)
If you cannot use SQL Server 2016 with built-in JSON support, you would need to use CLR e.g. JSONselect, json4sql, or custom code such as http://www.codeproject.com/Articles/1000953/JSON-for-SQL-Server-Part, etc.

SSRS Multi value parameters - appropriate layer for implmentation of the filter

When using multivalue parameters in sql reporting services is it more appropriate to implement the list filter using a filter on the dataset itself, the data region control or change the actual query that drives the dataset?
SSRS will support any scenario, so then I ask, is there a reason beyond the obvious of why this should be done at one level over another?
It makes sense to me that modifying the query itself and asking the RDBMS to handle the filtering would be most efficient but maybe I am missing something with respect to how the SSRS Data Processing Extension may handle this scenario?
You are correct. The way to go is to pass the parameters through to the database engine.
Reporting Services should only be ideally used to render content. The less data that you need to pass back to the client web browser, the faster the report will render.
You may find my answer to a similar post regarding using mulit-value parameters to be of use.
Passing multiple values for a single parameter in Reporting Services
Hope this helps but please feel free to pose any further questions you may have.
Cheers,
John
Using table-valued UDF is a good approach, but there is still one issue - in case if this function is called in many places of query, and even inside inner select, there can be performance problem. You can resolve this issue using table variable (or temp table eather):
DECLARE #Param (Value INT)
INSERT INTO #Param (Value)
SELECT Param FROM dbo.fn_MVParam(#sParameterString,',')
...
where someColumn IN(SELECT Value FROM #Param)
so function will be called only once.
Othe thing, if you don't use stored procedure, but embedded SQL query instead, you can just put MVP into query:
...
where someColumn IN(#Param)
...
Use the RDBMS to do the main filtering
SSRS provides filtering for the purposes on data driven display and/or dynamic display. Especially useful for sub reports etc

Resources