Reputation: 290
I have a grails domain class which looks something like this :
class Answer {
String response
Integer score
Date created = new Date()
}
how can i make a query that returns me the average score for each day of the week ? , like this :
average for Mondays = 25
average for Tuesdays = 20
....
average for sundays = 10
Upvotes: 0
Views: 488
Reputation: 50245
This is addition to @lucke84's answer, a small modification to his approach (in case my edit to his answer was missed)
def summation = [
'monday': [],
'tuesday': [],
'wednesday': [],
'thursday': [],
'friday': [],
'saturday': [],
'sunday': []
]
def answers = Answer.list()
answers.each {
def dateCreated = it.created[Calendar.DAY_OF_WEEK]
switch (dateCreated) {
case Calendar.MONDAY:
summation.monday << it.score
break
case Calendar.TUESDAY:
summation.tuesday << it.score
break
case Calendar.WEDNESDAY:
summation.wednesday << it.score
break
case Calendar.THURSDAY:
summation.thursday << it.score
break
case Calendar.FRIDAY:
summation.friday << it.score
break
case Calendar.SATURDAY:
summation.saturday << it.score
break
case Calendar.SUNDAY:
summation.sunday << it.score
break
}
}
def averages = [:]
averages.monday = (summation['monday'].sum())?.divide(summation['monday'].size())
//So on and So forth.
Keep a note that .list()
would bring back all the rows from Answer
which might affect performance. In that case you can use findAll
and pass in pagination
parameters according to your need.
Upvotes: 1
Reputation: 1512
To get sunday's avg, first get date of sunday. and then use criteria query to find avg. See example below:
dateOfSunday = ..
def c = Answer.createCriteria()
def avgScore = c.get {
projections {
avg "score"
}
lt("created",dateOfSunday.plus(1) )
gt("created",dateOfSunday.minus(1) )
}
Hope you got the idea...
EDIT:
Ok, If you want all sunday's avg, then you can use formula in your domain class, like:
class Answer {
String response
Integer score
Date created = new Date()
static mapping = {
dayOfWeek formula: 'DAYOFWEEK(created)'
}
}
And then query would be:
def c = Answer.createCriteria()
def avgScore = c.get {
projections {
avg "score"
}
eq("dayOfWeek ",7)
}
EDIT:
@dmahapatro, Thanks for pointing it out.
All avg scores also can be get using single db hit. See below:
def results = Answer.createCriteria().list() {
projections {
groupProperty('dayOfWeek')
avg "score"
}
}
Though it involves less code, but it has a drawback, it is using db function which will make the query slow. You can use the suggestion by dmahapatro.
Upvotes: 2
Reputation: 4636
I'm not really sure I've got your question and your domain model, but maybe this draft could be helpful.
def summations = [
'monday': [],
'tuesday': [],
'wednesday': [],
'thursday': [],
'friday': [],
'saturday': [],
'sunday': []
]
def answers = Answer.list()
answers.each {
def dateCreated = it.created[Calendar.DAY_OF_WEEK]
switch (dateCreated) {
case Calendar.MONDAY:
summations['monday'] << it.score
break
case Calendar.TUESDAY:
summations['tuesday'] << it.score
break
case Calendar.WEDNESDAY:
summations['wednesday'] << it.score
break
case Calendar.THURSDAY:
summations['thursday'] << it.score
break
case Calendar.FRIDAY:
summations['friday'] << it.score
break
case Calendar.SATURDAY:
summations['saturday'] << it.score
break
case Calendar.SUNDAY:
summations['sunday'] << it.score
break
}
}
// you can now do the average for every list in the map (sum of elements divided by number of item)
EDIT: This is from @dmahapatro:
def averages = [:]
averages.monday = (summations['monday'].sum())?.divide(summations['monday'].size())
// So on and So forth.
Upvotes: 1