Convert SUM / CASE WHEN / GROUP BY SQL query into LINQ - c#

I am having a VERY hard time converting my simple SQL query to LINQ...
SELECT Id
,Location
,SUM( CASE
WHEN TransactionType = 'Out' THEN [Quantity] * -1
ELSE Quantity
END) AS StockQuantity
FROM Transactions
WHERE Id = 123
GROUP BY Id, Location
here is my best WRONG attempt...
var result = db.Transactions
.Where(r => r.Id == 123)
.GroupBy(r => r.Id, r => r.Location)
.Select(group => new
{
Id = r.Id,
Location = r.Location,
Quantity = sum(r.TransactionType == 2 ? r.Quantity * -1 : r.Quantity),
});
Thanks in advance

You are not using your grouped values. Your query should be like:
var result = db.Transactions
.Where(r => r.Id == 123)
.GroupBy(r => new { r.Id, r.Location} )
.Select(grp => new
{
Id = grp.Key.Id,
Location = grp.Key.Location,
Quantity = grp.Sum(t=> t.TransactionType == 2 ? t.Quantity * -1 : t.Quantity),
});
I would also use a different variable name than group in projection (Select) since it is a contextual keywords (with query expression)

Related

How to Convert SQL query to LINQ (to get last record each bookingStatus)

Need some help translating below query to LINQ.
;With BookingWithLastStatus
as
(
Select *, Rnk = ROW_NUMBER() over (partition by BookingId order by Id desc)
from BookingStatus
)
Select *
from BookingWithLastStatus
where Rnk=1 AND StatusId = 3
I've done LINQ below but it is not getting the correct records.
var BookStatus = from p in _context.Set<BookingStatus>()
where p.StatusId == 3
group p by p.BookingId into opt
select new {
BookingId = opt.Key,
Id = opt.Max(x => x.Id)
};
The SQL query is getting 1 record only which is correct and my LINQ is getting multiple records.
UPDATE:
I did like this:
Get all the BookingStatus first
var GetAllBookStatus = await _context.Set<BookingStatus>()
.ToListAsync();
Then do the filtering based from the SQL Query I need.
var FilteredBookStatus = GetAllBookStatus
.OrderByDescending( x => x.Id )
.GroupBy(person => person.BookingId)
.Select( group => new { Group = group, Count = group.Count() } )
.SelectMany( groupWithCount =>
groupWithCount.Group.Select( b => b)
.Zip(
Enumerable.Range( 1, groupWithCount.Count ),
( b, i ) => new {
b.Id,
b.BookingId,
b.BookingMWABId,
b.BookStatus,
b.CreatedBy,
b.CreatedDate,
b.Destination,
b.InternalStatus,
b.LineNum,
b.ModifiedBy,
b.ModifiedDate,
b.Module,
b.ReasonCode,
b.ReceivedBy,
b.RefNo,
b.StatusId,
b.TimeStamp,
RowNumber = i }
)
)
.Where(a => a.StatusId == 3 && a.RowNumber == 1)
.ToList();
But I'm not so confident on Getting all records, as it will grow some time. Is there anything I can change from my code?
With EF core 6.x, you can do the following. It is not optimal case as in your SQL, but should work:
var BookStatus =
from p in _context.Set<BookingStatus>()
group p by p.BookingId into g
select g.OrderByDescending(x => x.Id).First();
BookStatus = BookStatus.Where(p => p.StatusId == 3);
Or another variant
var BookStatus = _context.Set<BookingStatus>().AsQueryable();
BookStatus =
from d in BookStatus.Select(d => new { d.BookingId }).Distinct()
from p in BookStatus
.Where(p => p.BookingId == d.BookingId)
.OrderByDescending(p => p.Id)
.Take(1)
select p;
BookStatus = BookStatus.Where(p => p.StatusId == 3);

LINQ Query Multiple Group and count of latest record - Oracle DB

I tried to divided Linq queries into 3 (total, success, fail) but so far "Total" Linq query is working fine. Please help me to get "Success", "Fail" columns (it has mulitple statuses and we have to check the last column of each transaction and destination)
Note: you need to group by ProcessTime, TransactionId, Destination and check last column whether it is success or Fail then apply count (we are using oracle as backend)
LINQ for Total count
var query = (from filetrans in context.FILE_TRANSACTION
join route in context.FILE_ROUTE on filetrans.FILE_TRANID equals route.FILE_TRANID
where
filetrans.PROCESS_STRT_TIME >= fromDateFilter && filetrans.PROCESS_STRT_TIME <= toDateFilter
select new { PROCESS_STRT_TIME = DbFunctions.TruncateTime((DateTime)filetrans.PROCESS_STRT_TIME), filetrans.FILE_TRANID, route.DESTINATION }).
GroupBy(p => new { p.PROCESS_STRT_TIME, p.FILE_TRANID, p.DESTINATION });
var result = query.GroupBy(x => x.Key.PROCESS_STRT_TIME).Select(x => new { x.Key, Count = x.Count() }).ToDictionary(a => a.Key, a => a.Count);
Check this solution. If it gives wrong result, then I need more details.
var fileTransQuery =
from filetrans in context.AFRS_FILE_TRANSACTION
where accountIds.Contains(filetrans.ACNT_ID) &&
filetrans.PROCESS_STRT_TIME >= fromDateFilter && filetrans.PROCESS_STRT_TIME <= toDateFilter
select filetrans;
var routesQuery =
from filetrans in fileTransQuery
join route in context.AFRS_FILE_ROUTE on filetrans.FILE_TRANID equals route.FILE_TRANID
select route;
var lastRouteQuery =
from d in routesQuery.GroupBy(route => new { route.FILE_TRANID, route.DESTINATION })
.Select(g => new
{
g.Key.FILE_TRANID,
g.Key.DESTINATION,
ROUTE_ID = g.Max(x => x.ROUTE_ID)
})
from route in routesQuery
.Where(route => d.FILE_TRANID == route.FILE_TRANID && d.DESTINATION == route.DESTINATION && d.ROUTE_ID == route.ROUTE_ID)
select route;
var recordsQuery =
from filetrans in fileTransQuery
join route in lastRouteQuery on filetrans.FILE_TRANID equals route.FILE_TRANID
select new { filetrans.PROCESS_STRT_TIME, route.CRNT_ROUTE_FILE_STATUS_ID };
var result = recordsQuery
.GroupBy(p => DbFunctions.TruncateTime((DateTime)p.PROCESS_STRT_TIME))
.Select(g => new TrendData
{
TotalCount = g.Sum(x => x.CRNT_ROUTE_FILE_STATUS_ID != 7 && x.CRNT_ROUTE_FILE_STATUS_ID != 8 ? 1 : 0)
SucccessCount = g.Sum(x => x.CRNT_ROUTE_FILE_STATUS_ID == 7 ? 1 : 0),
FailCount = g.Sum(x => failureStatus.Contains(x.CRNT_ROUTE_FILE_STATUS_ID) ? 1 : 0),
Date = g.Min(x => x.PROCESS_STRT_TIME)
})
.OrderBy(x => x.Date)
.ToList();

Yet another “A query body must end with a select clause or a group clause”

This query does work, but I am trying to combine the two steps into one query.
var query1 = from b in db.GetTable<Boats>()
from o in db.GetTable<Offices>()
from u in db.GetTable<Users>()
.Where
(u =>
u.UserId == b.Handling_broker &&
o.Office == b.Handling_office &&
b.Status == 2 &&
officesToInclude.Contains(b.Handling_office)
)
select new
{
hOffice = o.Name,
bName = u.Name
};
var query2 = query1.GroupBy(t => new { office = t.hOffice, name = t.bName })
.Select(g => new { Office = g.Key.office, Name = g.Key.name, Count = g.Count() });
If I try to combine the two queries using the following query it gives me the “A query body must end with a select clause or a group clause” error.
var query1 = from b in db.GetTable<Boats>()
from o in db.GetTable<Offices>()
from u in db.GetTable<Users>()
.Where
(u =>
u.UserId == b.Handling_broker &&
o.Office == b.Handling_office &&
b.Status == 2 &&
officesToInclude.Contains(b.Handling_office)
)
.GroupBy(t => new { office = t.Office, name = t.Name })
.Select(g => new { Office = g.Key.office, Name = g.Key.name, Count = g.Count() });
I think I have to add a select something, but I can't figure out what.
Can anyone please help?
Your query must contain a select clause. The .Where(...).GroupBy(...).Select(...) are only on the db.GetTable<Users>(). Something like:
var query1 = from b in db.GetTable<Boats>()
from o in db.GetTable<Offices>()
from u in db.GetTable<Users>().Where(u => u.UserId == b.Handling_broker &&
o.Office == b.Handling_office &&
b.Status == 2 &&
officesToInclude.Contains(b.Handling_office))
.GroupBy(t => new { office = t.Office, name = t.Name })
.Select(g => new { Office = g.Key.office, Name = g.Key.name, Count = g.Count() })
select new { /* Desired properties */};
But I think you are looking for something like:
var result = from b in db.GetTable<Boats>()
from o in db.GetTable<Offices>()
from u in db.GetTable<Users>()
where u.UserId == b.Handling_broker &&
o.Office == b.Handling_office &&
b.Status == 2 &&
officesToInclude.Contains(b.Handling_office))
group 1 by new { t.Office, t.Name } into g
select new { Office = g.Key.Office, Name = g.Key.Name, Count = g.Count() };

Linq query with Contains having null value

var qry = from _Cr in _er.Courses
from _R in _er.ResultsHeaders
where _R.Studentid == studentid
&& !_Cr.CourseID.Contains( _R.CourseID )
select new Obj_getCourses
{
Courseid = _Cr.CourseID,
CourseName = _Cr.CourseName
};
_er.CoursesTable have 4 values in it and _er.ResultsHeader table is empty. I was expecting 4 values from query but the query is not returning any Value. This is the query I am trying to write in LINQ.
Select * \
from Courses \
where courseid not in (Select courseid from ResultsHeader where studentid = 123);
Help require.
Thanks in advance
This should give you your desired results. I have written it in C# statement style so hopefully that having it is LINQ style was not a pre-requisite...
var qry = _er.Courses
.Where( c => !c.CourseID.Contains(_er.ResultsHeader
.Where( r => r.StudentID == 123)
.Select(r => r.CourseID)
)
.Select(c => new Obj_getCourses
{
Courseid = c.CourseID,
Coursename = c.CourseName
});
To get SQL you posted, you should try following query:
var qry = from _Cr in _er.Courses
where !_er.ResultsHeader.Where(r => r.StudentId == studentId)
.Select(r => r.CourseID)
.Contains(_Cr.CourseID)
select new Obj_getCourses
{
Courseid = _Cr.CourseID,
CourseName = _Cr.CourseName
};

Need help for a more beautiful LINQ to SQL query

Following is a T_SQL query for AdventureWorks database:
SELECT Name
FROM Production.Product
WHERE ListPrice >= ANY
(SELECT MAX (ListPrice)
FROM Production.Product
GROUP BY ProductSubcategoryID)
I try writing a LINQ query for this:
var groupMaxPricesquery2 = from product in dc.Products
group product by product.ProductSubcategoryID into productGroup
select productGroup.Max(eachProductInGroup => eachProductInGroup.ListPrice);
var query = from product in dc.Products
where groupMaxPricesquery2.Any(listPrice => listPrice <= product.ListPrice)
select product.Name;
How can I make it more beautiful (i.e. combining those queries together, or a more efficient approach)?
Thank you very much
Give either of these a try:
var query = from product in dc.Products
let groupMaxPricesQuery = dc.Products.GroupBy(p => p.ProductSubcategoryID)
.Select(g => g.Max(item => item.ListPrice))
where groupMaxPricesQuery.Any(listPrice => listPrice <= product.ListPrice)
select product.Name;
// or
var query = dc.Products
.Select(product => new {
Product = product,
GroupedMaxPrices = dc.Products.GroupBy(p => p.ProductSubcategoryID)
.Select(g => g.Max(item => item.ListPrice))
})
.Where(item => item.GroupedMaxPrices.Any(listPrice => listPrice <= item.Product.ListPrice))
.Select(item => item.Product.Name);
Maybe I'm missing something with the grouping, but I don't see why it is necessary.
var maxListPrice = dc.Products.Max(p => p.ListPrice);
var query = dc.Products.Where(p => p.ListPrice >= maxListPrice).Select(n => n.Name);

Categories