I'm fetching rows from excel sheet in my application that holds attendance records from the bio metric machine. In order to get the best result i have to remove the redundant data. For that I have to manage check in and checkout timings at regular intervals. For instance, First check in time for entering, and then checkout time for lunch, then again check in for returning back, and last check out for going home. Meanwhile the rows in excel contains multiple check ins and check outs as the employee tends to do more that once for both.
I have managed to get records from excel and added to data table. Now for the sequence and sorting part I'm struggling to achieve my desired result. Below is my code.
protected void btnSaveAttendance_Click(object sender, EventArgs e)
{
try
{
if (FileUpload1.HasFile && Path.GetExtension(FileUpload1.FileName) == ".xls")
{
using (var excel = new OfficeOpenXml.ExcelPackage(FileUpload1.PostedFile.InputStream))
{
var tbl = new DataTable();
var ws = excel.Workbook.Worksheets.First();
var hasHeader = true; // adjust accordingly
// add DataColumns to DataTable
foreach (var firstRowCell in ws.Cells[1, 1, 1, ws.Dimension.End.Column])
tbl.Columns.Add(hasHeader ? firstRowCell.Text
: String.Format("Column {0}", firstRowCell.Start.Column));
// add DataRows to DataTable
int startRow = hasHeader ? 2 : 1;
for (int rowNum = startRow; rowNum <= ws.Dimension.End.Row; rowNum++)
{
var wsRow = ws.Cells[rowNum, 1, rowNum, ws.Dimension.End.Column];
DataRow row = tbl.NewRow();
foreach (var cell in wsRow)
row[cell.Start.Column - 1] = cell.Text;
tbl.Rows.Add(row);
}
var distinctNames = (from row in tbl.AsEnumerable()
select row.Field<string>("Employee Code")).Distinct();
DataRow[] dataRows = tbl.Select().OrderBy(u => u["Employee Code"]).ToArray();
var ss = dataRows.Where(p => p.Field<string>("Employee Code") == "55").ToArray();
}
}
}
catch (Exception ex) { }
}
The result i'm getting is:
Employee Code Employee Name Date Time In / Out
55 Alex 12/27/2018 8:59 IN
55 Alex 12/27/2018 8:59 IN
55 Alex 12/27/2018 13:00 OUT
55 Alex 12/27/2018 13:00 OUT
55 Alex 12/27/2018 13:48 IN
55 Alex 12/27/2018 13:49 IN
55 Alex 12/27/2018 18:08 OUT
And I want to have first In and then out and then in and then out. This would iterate four times to generate the result.
Expected result is:
Employee Code Employee Name Date Time In / Out
55 Alex 12/27/2018 8:59 IN
55 Alex 12/27/2018 13:00 OUT
55 Alex 12/27/2018 13:48 IN
55 Alex 12/27/2018 18:08 OUT
Can you try to do groupby in the result like below
ss=ss.GroupBy(x=>x.DateTime).ToArray();
Build a logic, if your result have 2 successive In/Out as a sample like below.
Here In I considered as field name
var tt;
for(int i=0;i<ss.Count();i++)
{
if(ss[i].In=="In" && (tt!=null || tt.LastOrDefault().In!="In"))
tt=ss[i];
else if(ss[i].In=="Out" && (tt!=null || tt.LastOrDefault().In!="Out"))
tt=ss[i];
}
I have two datatables and I need to compare one columns and delete some results .(One Columns=ID)
I use datatable 1 and datatable 2 linq expression.I want to database3.
Common area ise ID:83,21
datatable 1
StudentID ClassNumber No
83 65 1
21 28 15
35 56 87
datatable 2
StudentID BranchNumber
83 3
21 2
datatable 3
StudentID ClassNumber
83 65
21 28
I write this query
public static DataTable Student(Datatable ds,Datatable dc)
{
DataTable StudentDatabaseID1= new DataTable();
DataTable StudentDatabaseID2= new DataTable();
var result=from a in StudentDatabaseID1.AsEnumerable()
join b in StudentDatabaseID2.AsEnumerable()
on a.Field<int>("StudentID") equals b.Field<int>("StudentID")
select
{
StudentID=a.Field<int>("StudentID"),
ClassNumber=a.Field<int>("ClassNumber"),
}
}
I think that you haven't data in StudentDatabaseID1 and StudentDatabaseID2 because they are new variables, maybe you have to use Datatable ds,Datatable dc ???, check it, code works fine like next example:
CODE (this is for LinqPad but you can re-use in your code):
void Main()
{
// Build data
DataTable dt1 = new DataTable();
dt1.Clear();
dt1.Columns.Add("StudentId", typeof(Int32));
dt1.Columns.Add("ClassNumber", typeof(Int32));
dt1.Columns.Add("No", typeof(Int32));
DataRow row1 = dt1.NewRow();
row1["StudentId"] = 83;
row1["ClassNumber"] = 65;
row1["No"] = 1;
dt1.Rows.Add(row1);
row1 = dt1.NewRow();
row1["StudentId"] = 21;
row1["ClassNumber"] = 28;
row1["No"] = 15;
dt1.Rows.Add(row1);
row1 = dt1.NewRow();
row1["StudentId"] = 35;
row1["ClassNumber"] = 56;
row1["No"] = 87;
dt1.Rows.Add(row1);
DataTable dt2 = new DataTable();
dt2.Clear();
dt2.Columns.Add("StudentId", typeof(Int32));
dt2.Columns.Add("BranchNumber", typeof(Int32));
DataRow row2 = dt2.NewRow();
row2["StudentId"] = 83;
row2["BranchNumber"] = 3;
dt2.Rows.Add(row2);
row2 = dt2.NewRow();
row2["StudentId"] = 21;
row2["BranchNumber"] = 2;
dt2.Rows.Add(row2);
// Do query
var result =
from a in dt1.AsEnumerable()
join b in dt2.AsEnumerable() on a.Field<int>("StudentID") equals b.Field<int>("StudentID")
select new {
StudentID=a.Field<int>("StudentID"),
ClassNumber=a.Field<int>("ClassNumber"),
};
// Print result
result.Dump();
}
RESULT
I have a view with 2 columns, both type of String. One is always "08:00" and one depends on the user input. It could be 02:30 or 13:45, etc...
I want to convert all the column of 08:00's and all the other column of values, add them together and then divide the total...
Example:
Column 1 | Column 2
02:50 | 08:00
05:15 | 08:00
15:25 | 08:00
03:15 | 08:00
It would be something like:(~26)/(8*4)=~0.8%.
It's a timekeeping application. I have the normal-time of 8 hours and the time the employee worked, and I want to add a button that will calculate the ratio between the 2 columns.
Thank you,
Florin
This is the code I used to calculate the ration between 2 columns of strings:
var vec:NotesViewEntryCollection = viewSearch.getAllEntries();
var c = vec.getCount()
var data = #DbColumn(#DbName(),"vwSearch",4);
var totalH = 0;
var totalM = 0;
for(var i=0;i<c;i++){
var str = data[i].toString();
var a = str.split(":",2)[0];
var b = str.split(":",2)[1];
var hour = parseInt(a);
var minutes = parseInt(b);
totalH += hour;
totalM += minutes;
if(totalM >= 60)
{
totalH++;
totalM-=60;
}
}
var h_necesare = c*8;
getComponent("h_lucrate").setValue(totalH+" ore, si "+totalM+" minute.");
getComponent("h_necesare").setValue(h_necesare);
getComponent("raport").setValue(totalH-h_necesare);
I have 2 datatables in a dataset. One table has a list called CostTypes. Just an Id and Description field.
The other datatable is the master table and has many records and one of the columns is the cost type. There will be cost types that are not reference in this datatable. There is another column in this databale called cost.
What I am trying to do is get a summary by cost type with a total of the cost. But I want ALL cost types listed any values not in the master table will be zero.
CostType table
Id, Description
1,Marketing
2,Sales
3,Production
4,Service
Master table
Id, Cost, CostTypeId
1,10,1
2,120,1
3,40,3
So I would like to see a result in a datable (if possible) so I can bind to datagridview
Marketing 130
Sales 0
Production 40
Service 0
Thanks for the help everyone, this is what I came up from the answers - Can anyone suggest any improvements???
Also how can I convert the result in query1 into a datable???
var query1 =
from rowCT in costTypes.AsEnumerable()
from rowSTD in stdRates.AsEnumerable()
.Where( d => d.Field<int?>( "CostTypeId" ) == rowCT.Field<int?>( "CostTypeId" ) )
.DefaultIfEmpty()
group new { row0 = rowCT, row1 = rowSTD }
by rowCT.Field<string>( "Description" ) into g
select new
{
g.Key,
Cost = g.Sum( x => x.row1 == null ? 0 : x.row1.Field<decimal>( "Cost" ) ),
TotalCost = g.Sum( x => x.row1 == null ? 0 : x.row1.Field<decimal>( "TotalCost" ) ),
TotalHours = g.Sum( x => x.row1 == null ? 0 : x.row1.Field<decimal>( "TotalHours" ) ),
TotalLabourCost = g.Sum( x => x.row1 == null ? 0 : x.row1.Field<decimal>( "TotalLabourCost" ) )
}
;
Maybe something like this:
Test data:
DataTable dt=new DataTable();
dt.Columns.Add("Id",typeof(int));
dt.Columns.Add("Description",typeof(string));
dt.Rows.Add(1,"Marketing");
dt.Rows.Add(2,"Sales");
dt.Rows.Add(3,"Production");
dt.Rows.Add(4,"Service");
DataTable dt2=new DataTable();
dt2.Columns.Add("Id",typeof(int));
dt2.Columns.Add("Cost",typeof(int));
dt2.Columns.Add("CostTypeId",typeof(int));
dt2.Rows.Add(1,10,1);
dt2.Rows.Add(2,120,1);
dt2.Rows.Add(3,40,1);
Linq query
var query=(
from row in dt.AsEnumerable()
from row1 in dt2.AsEnumerable()
.Where (d =>d.Field<int>("Id")==row.Field<int>("Id") )
.DefaultIfEmpty()
group new{row,row1}
by row.Field<string>("Description") into g
select new
{
g.Key,
Cost=g.Sum (x =>x.row1==null?0:x.row1.Field<int>("Cost"))
}
);
Result
Key Cost
Marketing 10
Sales 120
Production 40
Service 0
You can use the Sum extension method to compute the cost. It will return 0 if the collection is empty which is exactly what you want:
var costTypes = new DataTable("CostTypes");
costTypes.Columns.Add("Id", typeof(Int32));
costTypes.Columns.Add("Description", typeof(String));
costTypes.Rows.Add(1, "Marketing");
costTypes.Rows.Add(2, "Sales");
costTypes.Rows.Add(3, "Production");
costTypes.Rows.Add(4, "Service");
var costEntries = new DataTable("CostEntries");
costEntries.Columns.Add("Id", typeof(Int32));
costEntries.Columns.Add("Cost", typeof(Int32));
costEntries.Columns.Add("CostTypeId", typeof(Int32));
costEntries.Rows.Add(1, 10, 1);
costEntries.Rows.Add(2, 120, 1);
costEntries.Rows.Add(3, 40, 3);
var costs = costTypes
.Rows
.Cast<DataRow>()
.Select(
dr => new {
Id = dr.Field<Int32>("Id"),
Description = dr.Field<String>("Description")
}
)
.Select(
ct => new {
ct.Description,
TotalCost = costEntries
.Rows
.Cast<DataRow>()
.Where(ce => ce.Field<Int32>("CostTypeId") == ct.Id)
.Sum(ce => ce.Field<Int32>("Cost"))
}
);
The result is:
Description|TotalCost
-----------+---------
Marketing | 130
Sales | 0
Production | 40
Service | 0
You can create a new DataSet quite simply:
var costsDataTable = new DataTable("Costs");
costsDataTable.Columns.Add("Description", typeof(String));
costsDataTable.Columns.Add("TotalCost", typeof(Int32));
foreach (var cost in costs)
costsDataTable.Rows.Add(cost.Description, cost.TotalCost);
If the linear search performed by the Where in the code above is a concern you can improve the performance by creating a lookup table in advance:
var costEntriesLookup = costEntries
.Rows
.Cast<DataRow>()
.Select(
ce => new {
Cost = ce.Field<Int32>("Cost"),
CostTypeId = ce.Field<Int32>("CostTypeId")
}
)
.ToLookup(ce => ce.CostTypeId, ce => ce.Cost);
var costs = costTypes
.Rows
.Cast<DataRow>()
.Select(
dr => new {
Id = dr.Field<Int32>("Id"),
Description = dr.Field<String>("Description")
}
)
.Select(
ct => new {
ct.Description,
TotalCost = costEntriesLookup.Contains(ct.Id)
? costEntriesLookup[ct.Id].Sum()
: 0
}
);
I came up with a simpler bit of linq than others seemed to use. Thanks to Martin Liversage for the code to create the input data.
var costTypes = new DataTable("CostTypes");
costTypes.Columns.Add("Id", typeof(Int32));
costTypes.Columns.Add("Description", typeof(String));
costTypes.Rows.Add(1, "Marketing");
costTypes.Rows.Add(2, "Sales");
costTypes.Rows.Add(3, "Production");
costTypes.Rows.Add(4, "Service");
var costEntries = new DataTable("CostEntries");
costEntries.Columns.Add("Id", typeof(Int32));
costEntries.Columns.Add("Cost", typeof(Int32));
costEntries.Columns.Add("CostTypeId", typeof(Int32));
costEntries.Rows.Add(1, 10, 1);
costEntries.Rows.Add(2, 120, 1);
costEntries.Rows.Add(3, 40, 3);
var cte = costTypes.Rows.Cast<DataRow>();
var cee = costEntries.Rows.Cast<DataRow>();
var output = cte.Select(
ct => new {
Description = ct["Description"],
Sum = cee.Where(ce=>ce["CostTypeId"].Equals(ct["Id"])).Sum(ce=>(int)ce["Cost"])
}
);
This may lose efficiency on larger tables since each cost type will search the cost entry table whereas using grouping I suspect you only need one pass over the table. Personally I'd prefer the (to my mind) simpler looking code. It will depend on your use case though.
I currently have a LINQ query:
public List<EventSchool> GetEventSchools(int eventID)
{
var eventSchools = db.EventSchools
.Include("Organisation")
.Where(e => e.EventID == eventID)
.ToList();
foreach (var ev in eventSchools)
{
if (db.EventSchoolKeyStages.Where(e => e.EventSchoolID == ev.EventSchoolID).Count() > 0)
{
int ks = db.EventSchoolKeyStages
.Where(e => ev.EventSchoolID == ev.EventSchoolID)
.Sum(e => e.Males + e.Females);
ev.StudentNumbers = ks;
}
}
return eventSchools;
}
When I inspect EventSchools, the student numbers for ALL items in the list shows as the first total.
For example, if I have 3 items in the list:
Item 1 - Males = 10, Females = 10
Item 2 - Males = 1, Females = 2
Item 3 - Males = 200, Females = 500
ALL items have a StudentNumbers of 20, rather than:
Item 1 - 20
Item 2 - 3
Item 3 - 700
Not sure what I'm doing wrong?
You have a typo here:
.Where(e => ev.EventSchoolID == ev.EventSchoolID)
This lambda will always be true. I suspect you meant
.Where(e => e.EventSchoolID == ev.EventSchoolID)
^^^
which is different in the indicated place.
You have an error in your query:
.Where(e => ev.EventSchoolID == ev.EventSchoolID)
Should be:
.Where(e => e.EventSchoolID == ev.EventSchoolID)