I have a simple view:
CREATE VIEW [dbo].[ApplicationSummary]
AS
SELECT
CONVERT(VARCHAR(50), NEWID()) AS ID,
ISNULL(AVG(ApplicationTime), 0) AS 'AvgApplicationTime',
ISNULL(AVG(ResponseTime), 0) AS 'AvgResponseTime',
ISNULL(CAST(1.0 * COUNT(CASE WHEN [IsAccepted] = 1 THEN 1 END) / COUNT(*) AS float), 0) AS 'PctAccepted'
FROM
[Application]
WHERE
(IsValid = 1)
AND (CreatedOn < CAST(GETDATE() AS date)
AND CreatedOn >= CAST(GETDATE()-30 AS date))
The idea is that it outputs 3 variables. The first 2 are simple 'averages', whereas the last one, 'PctAccepted' outputs a ratio.
I'm testing a table containing 4 rows — 3 of them are set to IsAccepted = true, so the result is 0.75 (3/4), which converts to 75%.
I'm trying to remove the need for a view and replicate it using Linq over my Entity Framework class.
Here is the important stuff from the query:
var startDate = DateTime.Today;
var endDate = DateTime.Today.AddDays(-30);
var q = r.Find(x => x.IsValid &&
x.CreatedOn < startDate && x.CreatedOn >= endDate)
.GroupBy(x => x)
.Select(g => new
{
AvgApplicationTime = (int)g.Average(i => i.ApplicationTime),
AvgResponseTime = (int)g.Average(i => i.ResponseTime),
ApprovalRatio = g.Count(i => i.IsAccepted == true) / (double)g.Count()
}).First();
return new ApplicationStats(q.AvgApplicationTime, q.AvgResponseTime, q.ApprovalRatio);
So far, I have the two averages outputting correctly, but the ratio is returning 1 (or 100%).
Initially, I thought it may be a rounding issue but I've outputted the result of this line: g.Count(i => i.IsAccepted == true) and it incorrectly returns 1.
I may have grouping in the wrong place, but am currently struggling to make it work.
Any help appreciated.
Found the answer.
Changed .GroupBy(x => x) to .GroupBy(x => 1).
Also g.Count(i => i.IsAccepted == true) can be simplified to g.Count(i => i.IsAccepted)
Related
There is a table, where i store information about bookings.
It's a simple one. Has just few attr like: bookingId, personId, date and shouldBeConsidered
I want to retrieve for each person booked from som period of time for last 10 days and then to include property shouldBeConsidered.
For instance there were 100 bookings and 2 of those amount should be taken from db. And also, there can be person who booked 100 booking where is 0 shouldBeConsidered
I've code something like this:
var res = await this.context.Bookings
.Where(x => x.DateTime >= bookingsStartDateTime || x.ShouldBeConsidered)
.GroupBy(x => br.PId)
.Select(x => Dal
{
Id = br.Key,
TotalBookings = x.Count(),
BookingsIssues = x.Count(x => x.ShouldBeConsidered)
})
.ToListAsync();
But, unfortuanlly, it does not work properly. Sometimes, it could take a bit more issues and also count a bit more total.
You will need a bit more clear example with a few record scenarios followed by what you expect to have been returned and what you actually got returned. Your logic is going to give you all bookings where either the booking date >= that start date OR the ShouldBeConsidered flag is true. (regardless of date)
On a hunch I think you probably want to remove that || x.ShouldBeConsidered in that ultimately you'd be interested in the total # of bookings after the start date, and a separate count of the bookings after the start date with that flag set. the statement "and then to include property shouldBeConsidered" seems confusing. All properties of the booking are included/available for querying against:
var res = await this.context.Bookings
.Where(x => x.DateTime >= bookingsStartDateTime)
.GroupBy(x => br.PId)
.Select(x => Dal
{
Id = br.Key,
TotalBookings = x.Count(),
BookingsIssues = x.Count(x => x.ShouldBeConsidered)
}).ToListAsync();
I need to select count of row with a condition:
Query to collect the full count:
var searchs = searchQuery.SelectList
(list => list
.SelectGroup(order => order.Id).WithAlias(() => groupResult.GlobalId)
.SelectCount(() => _transaction.ReturnStatus).WithAlias(() => groupResult.DeclineCount)
)
I need count of transactions that equals 201. Something like this:
.SelectCount(() => _transaction.ReturnStatus == 201).WithAlias(() => groupResult.DeclineCount) //runtime error
Thanks in advance!
PS:
Original SQL Query:
SELECT TOP 100
globalOrd.ID AS GlobalId ,
SUM(CASE WHEN transact.returnStatus = 201 THEN 1
ELSE 0
END) AS DeclineCount
FROM Orders.Global globalOrd
INNER JOIN Orders.TransactionDetail transactDet ON globalOrd.ID = transactDet.DetailID
INNER JOIN Orders.[Transaction] transact ON transactDet.TransactionID = transact.ID
GROUP BY globalOrd.ID
If you don't need the total count in the same query you can simply add in the restriction before the SelectList:
var searchs = searchQuery.SelectList
(list => list
.Where(() => _transaction.ReturnStatus == 201)
.SelectGroup(order => order.Id).WithAlias(() => groupResult.GlobalId)
.SelectCount(() => _transaction.ReturnStatus).WithAlias(() => groupResult.DeclineCount)
)
If however, you want both the total and the restricted count, you would have to use a SqlProjection for the latter doing something like:
SUM(CASE {alias}.ReturnStatus WHEN 201 THEN 1 ELSE 0 END)
I'm using NHibernate to query a table that has tuples in the format: (String, Int?), where the integers can be null. So, I want to group my results by number and then sort alphabetically. I can easily do this after I get the query results, but I would like to get NHibernate to formulate a query that does it. Here's an example of the results I would like:
alpha, 1
delta, 4
golf, 3
hotel, 2
lima, 5
charlie, 0
theta, 0
beta, null
echo, null
The three groupings I'm looking for are: (int > 0), (int == 0), and (int = null). Here's the query I'm using:
var devices = session.QueryOver<Table>()
.OrderBy(item => item.Number).Desc
.OrderBy(item => item.Name).Asc
.List();
Currently, I'm sorting them after the query is done, as such:
List<Table> sortedDevices = devices.OrderBy(item => item.Name).Where(item => item.Number > 0).ToList();
sortedDevices = sortedDevices.Concat(devices.OrderBy(item => item.Name).Where(item => item.Number == 0).ToList()).ToList();
sortedDevices = sortedDevices.Concat(devices.OrderBy(item => item.Name).Where(item => item.Number == null).ToList()).ToList();
Is it possible to get NHibernate to group queries like this?
something along the lines:
session.QueryOver<User>()
.Select(Projections.Alias(Projections
.Conditional(Expression.Gt("Number", 0),
Projections.Constant(1),
Projections.Conditional(Expression.Eq("Number", 0),
Projections.Constant(0),
Projections.Constant(-1))),
"group"))
.OrderBy(Projections.Property("group")).Desc
.ThenBy(table => table.Name).Asc
.List();
I have an hql query string
from MyTable table
where table.StartTime + table.Duration >= : startTime
and table.MyId = : id
How can I write this without HQL in NHibernate (using criteria)?
This might be of interest regarding the DateTime + TimeSpan issue.
This will work in your case:
QueryOver:
int id = 1;
DateTime startTime = DateTime.Now.AddDays(5.0);
var vacations = session.QueryOver<Vacation>()
.Where(v => v.Employee.Id == id)
.And(v => v.StartDate > startTime
|| (v.StartDate == startTime.Date && v.Duration >= startTime.TimeOfDay))
.List();
ICriteria:
var vacationsCrit = session.CreateCriteria(typeof(Vacation))
.Add(Expression.Eq("Employee.Id", id))
.Add(Expression.Disjunction()
.Add(Expression.Gt("StartDate", startTime))
.Add(Expression.Conjunction()
.Add(Expression.Eq("StartDate", startTime.Date))
.Add(Expression.Ge("Duration", startTime.TimeOfDay))))
.List();
Both will output the exact same SQL. It should be mentioned that you cannot do something like this, as described in the link above:
var vacations = session.QueryOver<Vacation>()
.Where(v => v.Employee.Id == id)
.And(v => v.StartDate.Add(v.Duration) >= startTime) // <-- this will NOT work
.List();
Some LINQ queries still puzzle me.
for a table 'Hits' containing two columns, 'Page' and 'Date', I want to find the most Pages with the most rows in a defined slice of time.
In SQL I would use this:
SELECT TOP 10
[Page]
,COUNT([Page]) as Number
FROM dbo.[Hits]
WHERE [Date] >= CONVERT(datetime,'14 Jan 2009')
AND [Date] < CONVERT(datetime,'15 Jan 2009')
Group BY [Page]
Order by Number DESC
In LINQ I got no idea how to approach this, can anyone help me here? I tried to convert it using linqer, but it just shows an error for this expression.
Something like this should work:
(from p in DataContext.Hits
where (p.Date >= minDate) && (p.Date < maxDate)
group p by p.Page into g
select new { Page = g.Key, Number = g.Count() }).OrderByDescending(x => x.Number).Take(10);
var top10hits = objectContext.Hits
.Where(h => minDate <= h.Date && h.Date < maxDate)
.GroupBy(h => h.Page)
.Select(g => new { Page = g.Key, Number = g.Count() })
.OrderByDescending(x => x.Number)
.Take(10);