Hey - I'm battling to figure out how to write the following using NHibernate ICriteria (Multi criteria?) for the following:
(It's a query to get a list of first names ordered by popularity in the table in the last day)
select firstname,count(firstname) as occurances from registrants
where timestamp between DateAdd(day,-1, GetDate()) and getdate()
group by firstname
order by count(firstname) desc
Also, given this is just a couple of columns from a table, excluding the ID, and NHibernate needs ID's for it's objects, what's the easiest way to "fake" an ID so I can just get the results?
You need to use projections and a transformer to do this. Here's some background info http://nhibernate.info/doc/nh/en/index.html#querycriteria-projection
var criteria = Session.CreateCriteria<Registrant>()
.Add(Restrictions.Between("Timestamp", DateTime.Now.AddDays(-1), DateTime.Now)
.AddOrder(Order.Desc(Projections.Count("FirstName")))
.SetProjection(Projections.ProjectionList()
.Add(Projections.GroupProperty("FirstName"), "FirstName")
.Add(Projections.Count("FirstName"), "Occurances")
.SetResultTransformer(Transformers.AliasToBean<FirstNameOccurance>());
criteria.List<FirstNameOccurance>();
You'll need to create a class called FirstNameOccurance that has 2 properties called FirstName and Occurances.
Related
Preface:
The following is a rails sql query that allows me to find the 5 most frequent book searches in the last week, grouped by a few things.
time_range = (Time.now - 7.day)..Time.now
frequent = BookSearch.select("count(book_id) as id_count, short_name, isbn, genre").limit(5).where(created_at: time_range).group(:short_name).group(:isbn).group(:genre).order("id_count DESC")
Detail:
ISBN is a 13 char. string, but I'd like to group by the first two characters.
Example: if there are two strings, ab1234568901 and ab98765432109, I'd like them to be grouped because they both start with ab
I've tried replacing .group(:isbn) with .group(:isbn[0,2]) but then it looks for a column named is (the first two char's of isbn) and fails out.
Note: I want to keep the whole isbn in the db because it's possible we want to later on group by the first 4, 6, etc. digits.
Question:
How do I transform this query to do everything it's currently doing, but only group by the first two characters of isbn?
I think this should work:
BookSearch.select(
"count(book_id) as id_count, short_name, genre",
"LEFT(book_searches.isbn,2) AS isbn_selector"
).limit(5)
.where(created_at: time_range)
.group(:short_name)
.group("isbn_selector")
.group(:genre)
.order("id_count DESC")
I'm working a DB design regarding how a user launched something.
My idea was to have timestamp (DateTime) column, and a method column (varchar).
This 'method' (varchar) could be anything:
BUTTON_OK
BUTTON_X
APP_Y
APP_Z
etc
How can I COUNT the uses but group some values. In this case I want to have my result:
BUTTONS: 20
APP_X: 10
APP_Z: 14
You need some way of defining which 'methods' fall into which 'method group'.
One way would be to have a lookup table:
tbl_methodgroup
method_id Method Method_group
1 Button_OK Buttons
2 Button_X Buttons
3 App_Y App_Y
4 App_Z App_Z
then you could use:
select
b.method_group,
count(1)
from
tbl_methodgroup a
inner join tbl_method b on a.Method=b.Method
group by b.method_group
This method would have the advantage of being scalable as more methods get added. Rather than hand coding queries, which would need to be modified each time.
If the name of the table is tblTest, then the query will look like following:
SELECT method, COUNT(*) FROM tblTEst Group BY method
Apologies if I missread question, last chance to make it right if you have consistency in the data and grouping scenarios you can do following:
SELECT LEFT(method,CHARINDEX('_',method)-1),
COUNT(*)
FROM tblTest
GROUP BY LEFT(method,CHARINDEX('_',method)-1)
Otherwise Stuart Moore's answer is correct one.
I have the below query. The problem is the last column productdesc is returning two records and the query fails because of distinct. Now i need to add one more column in where clause of the select query so that it returns one record. The issue is that the column i need
to add should not be a part of group by clause.
SELECT product_billing_id,
billing_ele,
SUM(round(summary_net_amt_excl_gst/100)) gross,
(SELECT DISTINCT description
FROM RES.tariff_nt
WHERE product_billing_id = aa.product_billing_id
AND billing_ele = aa.billing_ele) productdescr
FROM bil.bill_sum aa
WHERE file_id = 38613 --1=1
AND line_type = 'D'
AND (product_billing_id, billing_ele) IN (SELECT DISTINCT
product_billing_id,
billing_ele
FROM bil.bill_l2 )
AND trans_type_desc <> 'Change'
GROUP BY product_billing_id, billing_ele
I want to modify the select statement to the below way by adding a new filter to the where clause so that it returns one record .
(SELECT DISTINCT description
FROM RRES.tariff_nt
WHERE product_billing_id = aa.product_billing_id
AND billing_ele = aa.billing_ele
AND (rate_structure_start_date <= TO_DATE(aa.p_effective_date,'yyyymmdd')
AND rate_structure_end_date > TO_DATE(aa.p_effective_date,'yyyymmdd'))
) productdescr
The aa.p_effective_date should not be a part of GROUP BY clause. How can I do it? Oracle is the Database.
So there are multiple RES.tariff records for a given product_billing_id/billing_ele, differentiated by the start/end dates
You want the description for the record that encompasses the 'p_effective_date' from bil.bill_sum. The kicker is that you can't (or don't want to) include that in the group by. That suggests you've got multiple rows in bil.bill_sum with different effective dates.
The issue is what do you want to happen if you are summarising up those multiple rows with different dates. Which of those dates do you want to use as the one to get the description.
If it doesn't matter, simply use MIN(aa.p_effective_date), or MAX.
Have you looked into the Oracle analytical functions. This is good link Analytical Functions by Example
How can HQL be used to select specific objects that meet a certain criteria?
We've tried the following to generate a list of top ten subscribed RSS feeds (where SubscriptionCount is a derived property):
var topTen = UoW.Session.CreateQuery( #"SELECT distinct rss
FROM RssFeedSubscription rss
group by rss.FeedUrl
order by rss.SubscriptionCount DESC
")
.SetMaxResults(10)
.List<RssFeedSubscription>();
Where the intention is only to select the two unique feed URLs in the database, rather than the ten rows int the database instantiated as objects. The result of the above is:
Column 'RssSubscriptions.Id' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
ORDER BY items must appear in the select list if SELECT DISTINCT is specified.
It's possible just to thin out the results so that we take out the two unique feed URLs after we get the data back from the database, but there must be a way to do this at the DB level using HQL?
EDIT: We realise it's possible to do a Scalar query and then manually pull out values, but is there not a way of simply specifying a match criteria for objects pulled back?
If you change your HQL a bit to look like that:
var topTen = UoW.Session.CreateQuery( #"SELECT distinct rss.FeedUrl
FROM RssFeedSubscription rss
group by rss.FeedUrl
order by rss.SubscriptionCount DESC
")
.SetMaxResults(10)
.List();
the topTen variable will be an object[] with 2 elements in there being the 2 feed URLs.
You can have this returned as strongly typed collection if you use the SetResultTransformer() method of the IQuery interfase.
You need to perform a scalar query. Here is an example from the NHibernate docs:
IEnumerable results = sess.Enumerable(
"select cat.Color, min(cat.Birthdate), count(cat) from Cat cat " +
"group by cat.Color"
);
foreach ( object[] row in results )
{
Color type = (Color) row[0];
DateTime oldest = (DateTime) row[1];
int count = (int) row[2];
.....
}
It's the group by rss.FeedUrl that's causing you the problem. It doesn't look like you need it since you're selecting the entities themselves. Remove that and I think you'll be good.
EDIT - My apologies I didn't notice the part about the "derived property". By that I assume you mean it's not a Hibernate-mapped property and, thus doesn't actually have a column in the table? That would explain the second error message you received in your query. You may need to remove the "order by" clause as well and do your sorting in Java if that's the case.
Is it possible to run a query similar to this one in HQL without having to specify all of the column names.
select med, MAX(med.PrescriptionLines.Prescription.PrescriptionDate)
from Medication med
where med.Patient.PatientId = :patientId
group by med
This query expands out all of the properties of the Medication object in the select, but in the group by only expands med to be med.MedicationId. I don't want to have to specify all of the properties of the medication object in the group by clause. Is there a way to do it?
I've tried replacing the group by med with group by med.* or group by {med.*} but that doesn't work.
Any ideas?
It's not implemented. See:
https://nhibernate.jira.com/browse/NH-528
http://opensource.atlassian.com/projects/hibernate/browse/HHH-1615 (this issue is over three years old)