SQL to LINQ Converter - c#

I have a SQL and having a hard time to convert it to LINQ. Are there any other tools that can convert SQL to LINQ? I heard Linqer and tried it but it doesn't allow you to query on the Junction/Join Table of a Many-to-Many relationship tables. In any case here's the SQL that I need to convert to LINQ or even lambda.
SELECT A.*
FROM
( SELECT TOP 10 T2.ID,
T2.Name,
SUM(T1.Column1 + T1.Column2 + T1.Column3) AS Total
FROM POS.dbo.Table1 T1
INNER JOIN POS.dbo.Table2 T2 on T2.ID = T1.ID
WHERE T2.ID IN
(
SELECT ID FROM POS.dbo.Table3 WHERE [Id] = 1
)
AND [Date] BETWEEN '2011-11-09 00:00:00' AND '2011-11-09 23:59:59'
GROUP BY T2.ID, T2.Name
ORDER BY Total DESC
) A
ORDER BY Name ASC
Here is my first attempt:
var query = db.Table1
.Include(e => e.Table2)
.Where(x => x.Date >= '2011-11-09 00:00:00'
&& x.DateCreated <= '2011-11-09 23:59:59')
.Where(y => y.Table2.Table3.Any(u => u.Id == 1))
.Take(10);

One of the things I like most about Linq is that it will combine queries together, so I break a complicated query into subqueries and let Linq recombine them all.
Using that basis, does something like this work.
DateTime startDate = new DateTime(2011,11,9);
DateTime endDate = new DateTime(2011,11,9,23,59,59);
var table3Ids = (from r in Pos.dbo.Table3 where id = 1 select r.id) ;
var query1 =
(
from t1 in Pos.dbo.Table1
where t1.Table2.Id == 1 && t1.Date >= startDate && t1.Date <= endDate
where table3Ids.Contains(t1.Table2.Id)
group t1 by new { t1.Table2.Id , t1.Table2.Name} into results
select new
{
results.Key.Id ,
results.Key.Name ,
Total = results.Sum(r=> (r.Column1 + r.Column2 + r.Column3))
}
);
var query2 = (from r in query1 orderby r.Total descending select r).Take(10);
var query3 = (from r in query2 orderby r.Name select r);
var list = query3.ToList();

Here's my shot - it's a bit hard without knowing the actual data structure or the expected results:
var query = db.Table1
.Join(db.Table2, table1 => table1.Id, table2 => table2.Id, (t1, t2) => new {
Id = t2.Id,
Name = t2.Name,
Total = (t1.Column1 + t1.Column2 + t1.Column3),
Date = t1.Date //you didn't use a table alias for this field, so I'm not sure which table it comes from
})
.Where(x => x.Date >= new DateTime(2011, 11, 9)
&& x.DateCreated <= new DateTime(2011, 11, 9, 23, 59, 59))
.Join(db.Table3, x => x.Id, table3 => table3.Id, (x, t3) => new {
Id = x.Id,
Name = x.Name,
x.Total
})
.Where(x => x.Id == 1)
.OrderByDescending(x => x.Total)
.ThenBy(x => x.Name)
.Take(10)
.ToList()
Because that might be the craziest Linq statement I've ever written, don't assume it'll work the first time, but it's at least a good starting point.

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);

Convert SQL query to LINQ with a group by

I have the below sql query that i am able to conert into LINQ
select count(*), BatchID
from TimeSheetHeader
group by BatchID having count(*) > 1
converts to
var duplicateBatchIDList = from c in _db.TimeSheetHeaders
group c by c.BatchID into grp
where grp.Count() > 1
select grp;
But now i am trying to throw an extra column that isnt included in the group by. I have the SQL query
select count(*), BatchID, TimeSheetCreationDate = min( TimeSheetCreationDate )
from TimeSheetHeader
where TimeSheetCreationDate >= CURRENT_TIMESTAMP
group by BatchID having count(*) > 1
But i am not sure how this convert over to LINQ
from c in _db.TimeSheetHeaders
where c.TimeSheetCreationDate >= CURRENT_TIMESTAMP
group c by c.BatchID into grp
where grp.Count() > 1
select new
{
BatchID = grp.Key,
Count = grp.Count(),
TimeSheetCreationDate = grp.Min(x => x.TimeSheetCreationDate)
}
Here you can find the lambda expression version of the query:
var result = TimeSheetHeader
.Where(t => t.TimeSheetCreationDate >= TIMESTAMP)
.GroupBy(t => t.BatchID)
.Where(g => g.Count() > 1)
.Select(g => new
{
Count = g.Count(),
BatchID = g.Key,
TimeSheetCreationDate = g.Min(x => x.TimeSheetCreationDate)
})
.ToList();
I slightly modified Magnus's answer
var duplicateBatchIDList = (from c in _db.TimeSheetHeaders
group c by c.BatchID into grp
where grp.Count() > 1
select new
{
BatchID = grp.FirstOrDefault().BatchID,
TimeSheetCreationDate = grp.Min(x => x.TimeSheetCreationDate)
}).Where(x => x.TimeSheetCreationDate <= DateTime.Now);

Convert SUM / CASE WHEN / GROUP BY SQL query into LINQ

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)

How to convert SQL query to LINQ with Orderby, Groupby

I am writing to write this SQL query in linq, but didnt work..
select [ProcessTime], Count([ID]) as 'amount of processes'
from [DB].[dbo].[TableX]
where [ID] in ('ServerX', 'ServerY') and [Type] ='Complete'
group by [ProcessTime]
order by [ProcessTime]
I would like to achieve this linq & what I have tried , I split the query into two, one for process time group by clause and another to count the ID's
var query1 = (from a in this.db.Processes
where (a.ID =='ServerX' || a.ID =='ServerY') && a.Type =='Complete'
group a by a.ProcessTime into b
//here I dont know where to place orderby
select b);
var query2 = (from a in this.db.Processes
where (a.ID =='ServerX' || a.ID =='ServerY') && a.Type =='Complete'
orderby a.ProcessTime
select a).Count();
is this the right way to split the query into two and then later combine them ?
Try this:
var serverNames = new string[]{"ServerX", "ServerY"};
var result = db.Processes
.Where(p => serverNames.Contains(p.ID) && p.Type == "Complete")
.GroupBy(p => p.ProcessTime)
.Select(g => new
{
ProcessTime = g.Key,
AmountOfProcesses = g.Count()
})
.OrderBy(x => x.ProcessTime);
You can do all this in one query:
var query1 = (from a in this.db.Processes
where (a.ID == "ServerX" || a.ID == "ServerY") && a.Type == "Complete"
group a by a.ProcessTime into b
orderby b.Key
select new {ProcessTime = b.Key, Count = b.Count()});

Grouping 2 Tables, Counting Values And Then Saving The Results In A Dictionary

So I have an SQL statement looks like this
SELECT T1.NAME, COUNT(T2.VALUE) AS numInstances
FROM TABLE2 T2 LEFT OUTER JOIN
TABLE1 T1 on T2.NAME_ID = T1.NAME_ID
WHERE (T2.DATE BETWEEN to_date('01-Aug-2011', 'dd-mon-yyyy')
AND to_date('31-Aug-2011' , 'dd-mon-yyyy')) AND T2.VALUE = 1))
GROUP BY T1.NAME
This statement looks for when names to match in the 2 tables and then find all '1' values (these relate to something like sick day, worked, day off, ect) in the month of august and then count how many of each I have. This SQL statement works great but I'm using MVC .NET in C# and need this to be a LINQ statement that generates a Dictionary.
So i would like the Dictionary to look something like,
NAME VALUECOUNT
John 8
Joe 1
Eric 0
I've tried
Dictionary<string,int> results =
(from t2 in db.table2.Where(t2 => m.Value == 1)
from t1 in db.table1
where(t2.DATE >= new DateTime(2011,8,1) && t2.DATE <= new DateTme(2011,8,31)
orderby t1.NAME
group new{T2, T1} by new {t2.VALUE, t1.NAME} into g
select new {
new KeyValuePair<string,int>(
g.Key.NAME,
(int)g.sum(g => g.Key.Value))
}).AsEnumerable().ToDictionary();
Ideas?
using(DbEntities db = new DbEntities())
{
var fromDate = new DateTime(2011,8,1);
var toDate = new DateTime(2011,8,31);
var dictionary =
(from t1 in db.TABLE1
join t2 in db.TABLE2.Where(x => x.VALUE == 1 && x.DATE >= fromDate && x.DATE <= toDate)
on t1.NAME_ID equals t2.NAME_ID into t2_j
from t2s in t2_j.DefaultIfEmpty()
group t2s by t1.NAME into grouped
select new { Name = grouped.Key, Count = grouped.Sum(x => x.VALUE) }).
Where(x => x.Count.HasValue).
ToDictionary(o => o.Name,o => o.Count);
return dictionary;
}

Categories