Need help in converting SQL query to LINQ - sql

I am new to the world of LINQ and hence I am stuck at converting one sql query to LINQ.
My SQL query is:
select COUNT(DISTINCT PAYER) as count,
PPD_COL FROM BL_REV
where BL_NO_UID = 1084
GROUP BY PPD_COL
The desired output is:
Count PPD_COL
12 P
20 C
I have written something like below in LINQ:
var PayerCount = from a in LstBlRev where a.DelFlg == "N"
group a by new { a.PpdCol} into grouping
select new
{
Count = grouping.First().PayerCustCode.Distinct().Count(),
PPdCol = (grouping.Key.PpdCol == "P") ? "Prepaid" : "Collect"
};
But it is not giving me the desired output. The count is returned same for PPD_COL value P & C. What am I missing here?

Change the groupby as following. in the group group only the property you need and then in thr by no need to create an anonymous object - just the one property you are grouping by.
var PayerCount = from a in LstBlRev
where a.DelFlg == "N"
group a.PayerCustCode by a.PpdCol into grouping
select new
{
Count = grouping.Distinct().Count(),
PPdCol = grouping.Key == "P" ? "Prepaid" : "Collect"
};

Related

Convert SQL to LINQ with group by

I'm stumped trying to convert the following sql to linq:
SELECT t.* FROM(SELECT mwfieldid,MAX([TimeStamp]) AS MaxValue, BatchDocumentID
FROM mw_BatchField
GROUP BY mwfieldid,BatchDocumentID) x
JOIN mw_BatchField t ON x.mwfieldid = t.mwfieldid
AND x.MaxValue = t.TimeStamp
and x.BatchDocumentID = t.BatchDocumentID
So far I had to convert it to a stored proc to get it to work. I'd rather know how to write this correctly in linq. I tried using a sql to linq converter (http://www.sqltolinq.com/) which produced this code that had errors in it: (Are these converters any good? It didn't seem to produce anything useful with a few tries.)
From x In (
(From mw_BatchFields In db.mw_BatchFields
Group mw_BatchFields By
mw_BatchFields.MWFieldID,
mw_BatchFields.BatchDocumentID
Into g = Group
Select
MWFieldID,
MaxValue = CType(g.Max(Function(p) p.TimeStamp),DateTime?),
BatchDocumentID)
)
Join t In db.mw_BatchFields
On New With { .MWFieldID = CInt(x.MWFieldID), .MaxValue = CDate(x.MaxValue), .BatchDocumentID = CInt(x.BatchDocumentID) }
Equals New With { .MWFieldID = t.MWFieldID, .MaxValue = t.TimeStamp, .BatchDocumentID = t.BatchDocumentID }
Select
BatchFieldID = t.BatchFieldID,
BatchDocumentID = t.BatchDocumentID,
MWFieldID = t.MWFieldID,
TimeStamp = t.TimeStamp,
value = t.value,
DictionaryValue = t.DictionaryValue,
AutoFilled = t.AutoFilled,
employeeID = t.employeeID
Seems like a lot of code for such a simple query, and it doesn't compile.
So for every combination of mwfieldid and BatchDocumentID you want all columns of the row with the highest TimeStamp? This is something which is much easier to express in LINQ than SQL so I'm not surprised that an automated converter is making a meal of it.
You should be able to do:
Mw_BatchFields.GroupBy(x => new { x.Mwfieldid, x.BatchDocumentId })
.SelectMany(x => x.Where(y => y.TimeStamp == x.Max(z => z.TimeStamp)))
This (like your SQL) will return multiple rows per grouping key if there is more than one row in the group that shares the same maximum TimeStamp. If you only want row per key, you could use:
Mw_BatchFields.GroupBy(x => new { x.Mwfieldid, x.BatchDocumentId })
.Select(x => x.OrderByDescending(y => y.TimeStamp).First())
Edit:
Sorry, just twigged that you're working in VB, not C#, so not quite what you were looking for, but if you can live with the lambda syntax style, I think the above can be translated as:
Mw_BatchFields.GroupBy(Function(x) New With {x.Mwfieldid, x.BatchDocumentId}).Select(Function(x) x.OrderByDescending(Function(y) y.TimeStamp).First())
and:
Mw_BatchFields.GroupBy(Function(x) New With {x.Mwfieldid, x.BatchDocumentId}).SelectMany(Function(x) x.Where(Function(y) y.TimeStamp = x.Max(Function(z) z.TimeStamp)))

IQueryable LINQ ordering and grouping

I have the following (incorrect) LINQ function (updated):
public IQueryable<ClassUsageReport> GetClassUsage()
{
//Class Code, Title, Usage, FiscalYear
var queryable = (from agencyplan in _agencyPlansList
join classSchedule2012 in _classSchedule2012List
on agencyplan.Id equals classSchedule2012.AgencyPlanId
join classes in _classesList
on classSchedule2012.Class.Id equals classes.Id
orderby agencyplan.PlanYear.FiscalYear descending, classes.ClassCode.Count() descending
group agencyplan by new
{
agencyplan.PlanYear.FiscalYear,
classes.ClassCode,
classes.Title
} into gcs
select new ClassUsageReport
{
ClassCode = gcs.Key.ClassCode,
Title = gcs.Key.Title,
Usage = gcs.Key.ClassCode.Count(),
FiscalYear = gcs.Key.FiscalYear
}
);
return queryable.AsQueryable();
}
I am having trouble with the Group By and Order By clauses. Also with the COUNT().
I have written the correct SQL statement, that produces the results as needed (and expected):
select py.fiscalyear, c.classcode, c.title, count(c.classcode) as usage from classschedule2012 cs
inner join classes c on cs.class_id = c.id
inner join agencyplans ap on cs.agencyplanid = ap.Id
inner join planyears py on ap.planyear_id = py.id
group by py.fiscalyear, c.classcode, c.title
order by py.fiscalyear desc, usage desc
What am I doing wrong with the grouping and ordering in my LINQ statement? I would like it to include "usage" like my SQL has. How can I get count to properly reflect the true count? As the query is at the moment, it only returns "9" in every row. This does not match my SQL, as the real results should be "55, 44, 14, 13" etc....
EDIT: 11/14/2013
Here is the final result:
public IQueryable<ClassUsageReport> GetClassUsage()
{
//Class Code, Title, Usage, FiscalYear
var queryable = (from agencyplan in _agencyPlansList
join classSchedule2012 in _classSchedule2012List
on agencyplan.Id equals classSchedule2012.AgencyPlanId
join classes in _classesList
on classSchedule2012.Class.Id equals classes.Id
where classes.Active = true
orderby agencyplan.PlanYear.FiscalYear descending
group agencyplan by new
{
agencyplan.PlanYear.FiscalYear,
classes.ClassCode,
classes.Title
} into gcs
select new ClassUsageReport
{
ClassCode = gcs.Key.ClassCode,
Title = gcs.Key.Title,
Usage = gcs.Count(),
FiscalYear = gcs.Key.FiscalYear
}
);
return queryable.AsQueryable().OrderByDescending(x => x.FiscalYear).ThenByDescending(x => x.Usage);
}
Once you group, you only have access to the columns you've grouped by and aggregate data of the other columns (like SUM or COUNT). In your query's select portion, you need to use g. instead of classes..
Try using g.Key in the select statement.

linq group by multipe aggregates

Im new to Linq and Im sure that I have gone about this in a convoluted manner. Im trying to do something like this SQL in Linq:
SELECT DISTINCT
count(vendor) as vendorCount,
reqDate,
status,
openDate,
item,
poDate,
count(responseDate) as responseCount
FROM
myTable
GROUP BY
reqDate, status, openDate, item, poDate
HAVING
reqDate > openDate
Here is what I have so far.
var groupQuery = (from table in dt.AsEnumerable()
group table by new
{
vendor = table["vendor"], reqdate = table.Field<DateTime>("ReqDate"), status = table["status"],
open = table["openDate"],
item = table["item"),
podate = table.Field<DateTime>("PODate"), responsedate = table.Field<DateTime>("responseDate"),
}
into groupedTable
where Having(groupedTable.Key.reqdate, groupedTable.Key.openDate) == 1
select new
{
x = groupedTable.Key,
y = groupedTable.Count()
}).Distinct();
foreach (var req in groupQuery)
{
Console.WriteLine("cols: {0} count: {1} ",
req.x, req.y);
}
The Having() is a function that takes two datetime parameters and returns a 1 if the reqDate is greater than the openDate. It compiles and runs, but it obviously does not give me the results I want. Is this possible using Linq? I want to push this data to an excel spreadsheet so Im hoping to create a datatable from this linq query. Would I be better off just creating a dataview from my datatable and not mess with Linq?
The SQL code is grouping by only some of the fields, while your LINQ statement is grouping by all of the fields, so the only items that would get grouped would be duplicates. If you group by only the fields that the SQL query groups by, you should get the correct answer. Your Having() method words fine, but is not necessary and is less readable.
var groupQuery = (from table in dt.AsEnumerable()
group table by new
{
reqdate = table.Field<DateTime>("ReqDate"),
status = table["status"],
open = table["openDate"],
item = table["item"),
podate = table.Field<DateTime>("PODate")
}
into groupedTable
where groupedTable.Key.reqdate > groupedTable.Key.openDate
select new
{
x = groupedTable.Key,
VenderCount = groupedTable.Select(t => t["vendor"])
.Distinct()
.Count(),
ResponseCount = groupedTable.Select(t => t.Field<DateTime>("responseDate"))
.Distinct()
.Count()
}).Distinct();

Entity Framework and dynamic order by statements

I have been struggling to get this working. I wish to have an EF statement take in a column to order by. My original statement was this:
var Query = from P in DbContext.People
where P.BusinessUnits.Any(BU =>BU.BusinessUnitID == businessUnitId)
orderby P.LastName
select P;
And I changed this to the following:
var Query = from P in DbContext.People
where P.BusinessUnits.Any(BU =>BU.BusinessUnitID == businessUnitId)
orderby sortField
select P;
Where sortField is the column we wish to sort on, and is a string i.e. LastName. However, it does not appear to work, it does no sorting, and the outputted SQL string is completely wrong. Anyone got this working before?
you could try passing in an expression to your method with the following type:
Expression<Func<Person, object>> expr = p => p.LastName;
and then using linq extensions instead of linq expressions...
var Query =
DbContext.People
.Where(P => P.BusinessUnits.Any(BU =>BU.BusinessUnitID == businessUnitId))
.OrderBy(expr)
.ToList();
Your sort does not work because you are sorting on a string literal. It is not illegal, but it is not particularly useful either. You need to provide a sorting field through the API of IQueryable<T>, for example, like this:
var q = from P in DbContext.People
where P.BusinessUnits.Any(BU =>BU.BusinessUnitID == businessUnitId)
orderby P.LastName
select P;
if ("sortField".Equals("FirstName"))
q = q.OrderBy(p => p.FirstName);
else if ("sortField".Equals("LastName"))
q = q.OrderBy(p => p.LastName);
else if ("sortField".Equals("Dob"))
q = q.OrderBy(p => p.Dob);

Linq to SQL Case WHEN in VB.NET?

How do I do a Case WHEN in Linq to SQL (vb.net please).
In SQL it would be like this:
SELECT
CASE
WHEN condition THEN trueresult
[...n]
[ELSE elseresult]
END
How would I do this in Linq to SQL?
var data = from d in db.tb select new {
CaseResult = If (d.Col1 = “Case1”, "Case 1 Rised", If (d.Col1 = “Case2”, "Case 2 Rised", "Unknown Case"))
};
Check This Out
var data = from d in db.tb select new {
CaseResult = (
d.Col1 == “Case1” ? "Case 1 Rised" :
d.Col1 == “Case2” ? "Case 2 Rised" :
"Unknown Case")
};
Please Note that [ ? Symbol = then] , [ : Symbol = Or].
I haven't tried this but you may be able to do something like:
Dim query = From tbl In db.Table _
Select result =_
If(tbl.Col1 < tbl.Col2,"Less than",_
If(tbl.Col1 = tbl.Col2,"Equal to","Greater than"))
You would just need to keep nesting the If functions to handle all of your cases.
You can find more examples of various queries at http://msdn.microsoft.com/en-us/library/bb386913.aspx