Trying to do what a SQL query (SELECT DISTINCT (first,second),third FROM table) would do but I am doing it with LINQ and a datatable.
EDIT
SQL should look like a Mysql
select first, second, third
FROM table
group by first, second
DataTable secondTable = new DataTable();
secondTable.Columns.Add("name", typeof(string));
secondTable.Columns.Add("date", typeof(string));
secondTable.Columns.Add("clockIn", typeof(string));
secondTable.Columns.Add("clockOut", typeof(string));
var t4 = (from a in firstTable.AsEnumerable()
select new
{
name = a.Field<string>("name"),
date = a.Field<string>("date"),
clockIn = a.Field<string>("clockIn"),
clockOut = a.Field<string>("clockOut")
}).Distinct();
var t5 = (from a in firstTable.AsEnumerable()
select new
{
name = a.Field<string>("name"),
date = a.Field<string>("date")
}).Distinct();
var t6 = (from d in t5
join a in t4
on new
{
d.name,
d.date
}
equals new
{
a.name,
a.date
}
select secondTable.LoadDataRow(
new object[]
{
d.name,d.date,a.clockIn,a.clockOut
}, false)).ToList();
ViewBag.Data = secondTable;
What this code is doing is, it is joining t4 and t5 in t6 with no exclusions. While what I desire is all rows from t4 that are present in t5 should join with t6 on the basis on (name, date) AND all rows from t5that don't exist in t4 should be excluded. Can anyone please help?
From your comments, you may just group by the desired fields, and take any of the grouped result.
You may order by clockin or clockout to get a less "random" result.
var t6 = firstTable.AsEnumerable()
.GroupBy(a => new {
name = a.Field<string>("name"),
date = a.Field<string>("date")
}
)
.Select(g => g.First())
//or Select(g => g.OrderBy(a => a.Field<string>("clockIn")).First()
.ToList();
Related
I'm trying to rewrite sql query to linq but can't do it myself.
The most problem for me is to get I,II and III aggregated values.
Sql query:
select o.Name,t.TypeID, SUM(e.I),SUM(e.II),SUM(e.III) from Expenditure e
join Finance f on f.FinanceId = e.FinanceId
join FinanceYear fy on fy.FinanceYearId = f.FinanceYearId and fy.StatusId = 1
join Project p on p.ProjectId = fy.ProjectId
join Organization o on o.OrganizationId = p.OrganizationId
join Type t on t.TypeID = p.TypeID
where fy.Year = 2018
group by o.Name,s.TypeID
and what I have done so far is:
var x = (from e in _db.Expenditures
join f in _db.Finances on e.FinanceId equals f.FinanceId
join fy in _db.FinanceYears on f.FinanceYearId equals fy.FinanceYearId and fy.StatusId = 1 // this does not work, cant join on multiple conditions?
join p in _db.Projects on fy.ProjectId equals p.ProjectId
join o in _db.Organizations on p.OrganizationId equals o.OrganizationId
join s in _db.Types on p.TypeId equals s.TypeId
group new { o, s } by new { o.OrganizationId, s.TypeId }
into grp
select new AggModel
{
OrganizationId = grp.Key.OrganizationId,
TypeId = grp.Key.TypeId,
I = ?,
II = ?,
III = ?,
}
);
Try something like this:
group new { e, o, s } by new { o.OrganizationId, s.TypeId }
into grp
select new AggModel
{
OrganizationId = grp.Key.OrganizationId,
TypeId = grp.Key.TypeId,
I = grp.Sum(a => a.e.I),
II = grp.Sum(a => a.e.II),
III = grp.Sum(a => a.e.III),
}
You'll need to adjust the right side of the lambda to navigate to the correct property.
You Need to use the Group by for aggregation methods.
Check the below link for more Knowledge.
How to use aggregate functions in linq with joins?
I have been searching high and low for this to no avail. I have two DataTables that I want to join without creating a new resultant table as I simply need to update some rows in one of the tables to be displayed in a grid view, similar to the below code, but with a join:
sage_invoices.Select("CCE2 IS NULL")
.ToList<DataRow>()
.ForEach(row =>
{
row["Error"] = 1;
row["ErrorMessage"] = "Missing Region Code (Dimension 2 - CCE2)";
});
Everything I've found produces a new output datatable, similar to the below code:
var collection = from t1 in dt1.AsEnumerable()
join t2 in dt2.AsEnumerable()
on t1["id"] equals t2["id"]
select new { T1 = t1, T2 = t2 };
What I can't find is how to join two DataTables using .Join:
sage_invoices.Select()
.Join(<What Goes here?>)
.ToList<DataRow>()
.ForEach(row =>
{
row["Error"] = 1;
row["ErrorMessage"] = "ITMREF is not a Sage Product Code";
});
If anyone could point me in the right direction, I would be most grateful.
Thanks
Gareth
I typically accomplish this by building an anonymous object that contains a reference to my source and destination objects through a Join or GroupJoin, then looping over the result of the Join to update my destination object. See the example below.
Take a look at the documentation on Join and GroupJoin. Join is great for a 1-1 match, while GroupJoin is a 0-* match (like a SQL left join). The arguments to Join and GroupJoin allow you to specify a selector function for each IEnumerable followed by a selector function for the output object. Note that t1 and t2 below refer to table1 and table2.
using System;
using System.Data;
using System.Linq;
public class Program
{
public static void Main()
{
var table1 = GetEmptyTable();
table1.Rows.Add(1, "Old Value", false);
table1.Rows.Add(2, "Untouched Value", false);
var table2 = GetEmptyTable();
table2.Rows.Add(1, "New Value", false);
table2.Rows.Add(3, "Unused Value", false);
Console.WriteLine("Before...");
Console.WriteLine(PrintTable(table1));
var matched = table1.Select()
.Join(table2.Select(), t1 => (int)t1["A"], t2 => (int)t2["A"], (t1, t2)
=> new
{
DestinationRow = t1,
SourceRow = t2
});
foreach (var match in matched)
{
match.DestinationRow["B"] = match.SourceRow["B"];
match.DestinationRow["C"] = true;
}
Console.WriteLine("After...");
Console.WriteLine(PrintTable(table1));
}
private static DataTable GetEmptyTable()
{
var table = new DataTable();
table.Columns.Add("A", typeof(int));
table.Columns.Add("B", typeof(string));
table.Columns.Add("C", typeof(bool));
return table;
}
private static string PrintTable(DataTable table)
{
return string.Join(Environment.NewLine, table.Select().Select(x => "[" +
string.Join(", ", x.ItemArray) + "]"));
}
}
I need to write following T-SQL in LINQ:
SELECT T1.ID, T2.Name
FROM T1
LEFT JOIN T2 ON (T1.ID = I2.ID1 OR T1.ID = T2.ID2)
An OR-join would look like this in LINQ:
T1.Join(T2, t1=>new{}, t2=>new{}, (t1,t2)=>new{ID=t1.Id, t2=t2}).Where(o=>o.Id == o.t2.Id1 || o.Id==o.t2.Id2);
But that query is an INNER JOIN, not a LEFT JOIN.
Some kind of LEFT JOIN would look like this:
T1.GroupJoin(T2, t1 => t1.Id, t2 => t2.Id1, (t1, t2) => new { Id = t1.Id, Name1 = t2.Select(t => t.Name) }).DefaultIfEmpty()
.GroupJoin(T2, o => o.Id, t2 => t2.Id2, (i, j) => new { Id = i.Id, Name1 = i.Name1, Name2 = j.Select(t => t.Name) }).DefaultIfEmpty();
This query produces correct results, but makes 2 joins instead of 1. Or is it really equivalent to original T-SQL?
Does anybody know how to rewrite this query better?
This answer from a similar question gives us an easy way to write LEFT JOINs:
https://stackoverflow.com/a/4739738/1869660
var query = from t1 in T1
from t2 in T2.Where(tt2 => (t1.ID == tt2.ID1) || (t1.ID = tt2.ID2))
.DefaultIfEmpty()
select new { t1.ID, t2.Name }
To solve this with single linq, try using cross join
var results = (from a in test1
from b in test2
where a.ID == b.ID1 || a.ID == b.ID2
select new {x = a.ID, y = b.Name});
var LeftJoin = from emp in ListOfEmployees
join dept in ListOfDepartment
on emp.DeptID equals dept.ID into JoinedEmpDept
from dept in JoinedEmpDept.DefaultIfEmpty()
select new
{
EmployeeName = emp.Name,
DepartmentName = dept != null ? dept.Name : null
};
I have a search that looks for two things. Items and Contacts. They each have their own table with their own unique attributes. I am able to successfully search each independent of eachother and return the results to two list views. But is it ugly and paging has become a issue so I have to convert these two tables into a like result that I can display as a search result. These results have no relationship directly with eachother.
The group t3 by new is throwing me off. Do I have to group them to have it become a like result? The results currently get displayed in a ListView using for example <%#Eval("ItemName") %>
ItemContext db = new ItemContext(); //DB connection (Item,Contact)
var q = (from t1 in db.Item
join t2 in db.Categories on t1.CategoryID equals t2.CategoryID
join t7 in db.Divisions on t1.DivisionID equals t7.DivisionID
from t3 in db.Contacts
join t4 in db.Categories on t3.CategoryID equals t4.CategoryID
join t5 in db.Divisions on t3.DivisionID equals t5.DivisionID
join t6 in db.ContactTitle on t3.ContactTitlesID equals t6.ContactTitlesID
where
(DDLInt == 1 || t3.DivisionID == DDLInt) &&
//Contains
(
t3.ContactName.Contains(keyword) ||
t3.ContactEmail.Contains(keyword) ||
t3.ContactOPhone.Contains(keyword) ||
t3.ContactID.Equals(searchID)
)
group t3 by new
{
t3.ContactID,
t3.ContactName,
t3.ContactOPhone,
t3.ContactCell,
t3.ContactEmail,
t3.DivisionID,
t3.CategoryID,
t4.CategoryName,
t5.DivisionName,
t6.ContactTitlesName
}
into i
select new
{
i.Key.ContactID,
i.Key.ContactName,
i.Key.ContactOPhone,
i.Key.ContactEmail,
i.Key.ContactCell,
i.Key.CategoryName,
i.Key.DivisionName,
i.Key.CategoryID,
i.Key.DivisionID,
i.Key.ContactTitlesName
});
return q.ToList<dynamic>();
}
Use Union():
var contacts = from c in db.Contacts
select new {
Id = c.ContactID,
Name = c.ContactName,
Phone = c.ContactOPhone,
...
CategoryName = c.Category.CategoryName,
DivisionName = c.Division.DivisionName,
ContactTitlesName = c.ContactTitle.ContactTitlesName
}
var items = from t1 in db.Item
select new {
Id = t1.ItemID,
Name = t1.ItemName,
Phone = t1.??, // string.Empty?
... // more properties corresponding
// with the ones above
CategoryName = t1.Category.CategoryName,
DivisionName = t1.Division.DivisionName,
ContactTitlesName = string.Empty
}
var all = contacts.Union(items);
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;
}