I have two tables
TblEmployee
attendance_id employee_id Scan_type Date_and_time
1 1 IN 15-Jan-19 8:00:00 AM
2 1 IN 15-Jan-19 8:00:02 AM
3 2 IN 15-Jan-19 8:05:01 AM
4 2 OUT 15-Jan-19 4:00:00 PM
5 1 IN 16-Jan-19 8:05:30 AM
AttendanceTable
emp_id emp_name
1 Salman
2 Tahir
3 Jameel
I want to display monthly record data of all employees with in and out times. In time will be the first time with "iN" and out time will be the last time with "OUT". Employee may forget to sign-in or sign-out so in that case the field will remain blank or show "absent".
I am trying to do like this but don't know what to do next
var InList = from a in _context.TblEmployee
from e in _context.AttendanceTable.Where(x =>
a.EmpId == x.EmployeeId)
.Where(x => x.ScanType == "IN")
.OrderBy (x => x.DateAndTime)
.DefaultIfEmpty()
select new
{
AttDate = e.DateAndTime.Date,
Emp_name = a.EmployeeName,
Emp_Id = e.EmployeeId
};
var OutList = from a in _context.TblEmployee
from e in _context.AttendanceTable.Where(x =>
a.EmpId == x.EmployeeId)
.Where(x => x.ScanType == "OUT")
.OrderBy (x => x.DateAndTime)
.DefaultIfEmpty()
select new
{
AttDate = e.DateAndTime.Date,
Emp_name = a.EmployeeName,
Emp_Id = e.EmployeeId
};
Related
I try to get a list from a datatable by a linq syntax with having clause.
But I don't get what I want.
Here's the SQL syntax :
SELECT ID_BEN,
GAR1,
FIRST(FIRST_NAME) FIRST_NAME,
FIRST(LAST_NAME) LAST_NAME,
FIRST(ADR1) ADR1,
FIRST(ADR2) ADR2,
FIRST(ZIP_CODE) ZIP_CODE,
FIRST(CITY) CITY,
SUM(AMOUNT) SUM_AMOUNT,
SUM(CASE WHEN STATUS_TAB <> 'OK' THEN 1 ELSE 0 END) NUM_STATUS_TAB
FROM T_AMOUNT
WHERE STATUS_ENR = 'OK' AND STATE_ENR = '1'
GROUP BY ID_BEN, GAR1
HAVING SUM(CASE WHEN STATUS_TAB <> 'OK' THEN 1 ELSE 0 END) = 0
Here is my linq syntax :
var oLstReglementGrp = objDataSet.T_AMOUNT
.AsEnumerable()
.Select(sel => new
{
ID_BEN = sel.ID_BEN,
GAR1 = sel.GAR1,
LI_NOM = sel.First().FIRST_NAME,
LI_ADR1 = sel.First().LAST_NAME,
LI_ADR2 = sel.First().ADR1,
LI_ADR3 = sel.First().ADR2,
LI_ADR4 = sel.First().ZIP_CODE,
CD_PST = sel.First().CITY
})
.Where(x => x.STATUS_ENR == "OK"
&& x.STATE_ENR == "1")
.GroupBy(row => new { ID_BEN = (long?)row.ID_BEN, GAR1 = row.GAR1 },
(g, r) => new
{
NUM_STATUS_TAB = r.Sum(s => s.STATUS_TAB != "OK" ? 1 : 0),
SUM_AMOUNT = r.Sum(s => (decimal?)s.AMOUNT)
})
.Where(p => p.NUM_STATUS_TAB == 0)
.ToList();
Here are the SQL results :
FIRST_NAME LAST_NAME ADR1 ZIP_CODE CITY SUM_AMOUNT NUM_STATUS_TAB
Jack Palance 3 bd One 1234 New York 12000 0
John Wayne 4 ave 2 4567 Los Angeles 5500 0
Jimmy Page 5 street 2 2345 Chicago 450 0
And in my list from the linq :
SUM_AMOUNT NUM_STATUS_TAB
12000 0
5500 0
450 0
Do you have an idea ?
When writing LinQ you should no try to translate to SQL query like you would read it.
LinQ syntax is closer to SQL Execution order. In this way Linq is more "Logical".
SQL execution order is the following:
FROM and JOINs
WHERE
GROUP BY
HAVING
SELECT
objDataSet
// 1. FROM and JOINs
.T_AMOUNT
//2. WHERE
.Where(x => x.STATUS_ENR == "OK" && x.STATE_ENR == "1")
//3. GROUP BY
.GroupBy(row => new { ID_BEN = (long?)row.ID_BEN, GAR1 = row.GAR1 })
//5. SELECT
.Select(sel => new
{
ID_BEN = sel.Key.ID_BEN,
GAR1 = sel.Key.GAR1,
LI_NOM = sel.First().FIRST_NAME,
LI_ADR1 = sel.First().LAST_NAME,
LI_ADR2 = sel.First().ADR1,
LI_ADR3 = sel.First().ADR2,
LI_ADR4 = sel.First().ZIP_CODE,
CD_PST = sel.First().CITY,
NUM_STATUS_TAB = sel.Sum(s => s.STATUS_TAB != "OK" ? 1 : 0),
SUM_AMOUNT = sel.Sum(s => (decimal?)s.AMOUNT)
})
//4. HAVING
.Where(p => p.NUM_STATUS_TAB == 0)
.ToList();
Step 4 and 5 have been swap because we are filtering on a field that is not present in the groupby, so we need the select in order to have it avaidable.
At Step 3. GROUP BY, notice the overload used. Order by has 9 overload, MS Docs.
I will advice on using the simple one till you get familiar with it
Hi I have some two tables,
Product:
ProductID | IssueDate | Amount
1 2017-06-01 1000
2 2017-06-01 1000
3 2017-06-02 500
and Credit:
ProductID | Amount
1 500
1 500
2 1000
3 500
if I use query like this from SQL Server:
SELECT p.IssueDate, SUM(p.Amount), SUM(p.Total)
FROM (SELECT p.IssueDate, SUM(p.Amount) AS Amount,
(SELECT TOP 1 SUM(c.Amount) FROM Credit c WHERE p.Id = c.ProductId) AS Total from Product p
GROUP BY p.IssueDate, p.Id) p
GROUP BY p.IssueDate
I get this result:
IssueDate | Amount | Total
2017-06-01 2000 2000
2017-06-02 500 500
In C# Linq I can get this data by two queries like this:
var data = from p in Products.Collection
select new
{
Product = p,
Credits = Credit.Collection.Where(c => c.ProductID == p.ID).Sum(c => c.Amount)
};
var result = from d in data
group d by new
{
IssueDate = d.Product.IssueDate
} into gr
select new
{
IssueDate = gr.Key.IssueDate,
Credits = gr.Sum(s => s.Credits),
Total = gr.Sum(s => s.Product.Amount)
};
var test = result.ToList();
Does anyone know a better (simpler) solution to get this result? Maybe in one query?
How about:
Products.Collection.GroupBy(x => x.IssueDate)
.Select(x => new
{
IssueDate = x.Key,
Amount = x.Sum(p => p.Amount),
Total = Credit.Collection.Where(c => x.Any(p => p.ProductID == c.ProductID)).Sum(c => c.Amount)
}).ToList();
I have a table that allocates a Truck to a User, using their Identities to link each allocation to their respective entities. Only the last allocation for a Truck/User can be selected. I used the following LINQ to get the values I need
var query = (from ta in TruckAllocations
where ta.Truck.Name != null || !ta.Truck.Name.Contains(string.Empty)
group ta by ta.UserId into grp
let MaxDate = grp.Max(g => g.CreatedOn)
from g in grp
where g.CreatedOn == MaxDate
select new { Key = g.TruckAllocationId, Truck = g.TruckId, User = g.UserId, Date = g.CreatedOn });
The problem I'm having is that two User's that are allocated to the same truck are in the result of the query, and I just want the last on assigned. Example of result
47 26 224 2014-03-28 10:47 AM
48 3 149 2014-03-31 10:25 AM
1048 2 575 2014-04-04 1:14 PM
1049 23 575 2014-04-09 9:15 AM
1050 56 322 2014-04-09 2:27 PM
As you can see User [2 and 23] are assigned the same Truck [575]
the result that I want would be this:
47 26 224 2014-03-28 10:47 AM
48 3 149 2014-03-31 10:25 AM
1049 23 575 2014-04-09 9:15 AM
1050 56 322 2014-04-09 2:27 PM
Where record 1048, doesn't show because he was not the last User assigned to the Truck.
Is there a way to get a Distinct on the pair where each value in the pair has to be unique
UPDATE
I also tried
var query = (from ta in TruckAllocations
where ta.Truck.Name != null || !ta.Truck.Name.Contains(string.Empty)
group ta by ta.TruckId into grp
let MaxDate = grp.Max(g => g.CreatedOn)
from g in grp
where g.CreatedOn == MaxDate
select new { Key = g.TruckAllocationId, Truck = g.TruckId, User = g.UserId, Date = g.CreatedOn });
Result is:
6 54 3 2014-03-04 7:03 PM
8 63 4 2014-03-13 12:36 PM
10 626 4 2014-03-13 2:10 PM
13 12 4 2014-03-20 4:18 PM
21 8 3 2014-03-20 6:21 PM
42 10 3 2014-03-21 1:09 PM
43 3 26 2014-03-26 5:35 PM
44 32 1 2014-03-27 8:53 AM
47 224 26 2014-03-28 10:47 AM
48 149 3 2014-03-31 10:25 AM
1049 575 23 2014-04-09 9:15 AM
1050 322 56 2014-04-09 2:27 PM
It does give me only one Truck/User for the Truck as the record [1048] is not returned, but now I have Use 4,3, 26 assigned to multiple trucks, when they can only be assigned one
And grouping with TruckId and UserId will add the Truck assigned to two Users, to the one grouped by TruckId.
var query = (from ta in TruckAllocations
where ta.Truck.Name != null || !ta.Truck.Name.Contains(string.Empty)
group ta by new {ta.TruckId, ta.UserId} into grp
let MaxDate = grp.Max(g => g.CreatedOn)
from g in grp
where g.CreatedOn == MaxDate
select new { Key = g.TruckAllocationId, Truck = g.TruckId, User = g.UserId, Date = g.CreatedOn });
** UPDATE2 **
The solution that got me what I wanted was to query the table grouped by UserId (1st query in question), then query the table grouped by the TruckId (2nd query in question). Then query both results to get matches on truck and user like this:
var assigned = (from t1 in query1
from t2 in query2
where t1.Truck == t2.Truck && t1.User == t2.User
select new {t1.Key, t1.Truck, t1.User, t1.Date}).ToList();
Would like to know if there was a better way to do it though.
You could do something like that (group, order by descending on the wanted element).
More used to fluent syntax, so...
var result = TruckAllocations
.Where(ta => ta.Truck.Name != null && ta.Truck.Name != string.Empty)
.GroupBy(ta => ta.UserId)
//take the first element of each group, which will be the one with the max CreatedOn date
.Select(g=> g.OrderByDescending(m => m.CreatedOn).First())
.Select(m => new {
Key = m.TruckAllocationId,
Truck = m.TruckId,
User = m.UserId,
Date = m.CreatedOn
});
EDIT
You may do this in one or two steps.
CAUTION : If all trucks used by a given user have been used later by another User => this User won't appear in list.
2 steps version
var lastDateByTruck = TruckAllocations
.Where(ta => ta.Truck.Name != null && ta.Truck.Name != string.Empty)
.GroupBy(m => m.TruckId)
.Select(m => new
{
TruckId = m.Key,
CreatedOn = m.Max(x => x.CreatedOn)
});
var result = from allocation in TruckAllocations
join lastUsage in lastDateByTruck on new
{
allocation.TruckId,
allocation.CreatedOn
} equals new
{
lastUsage.TruckId,
lastUsage.CreatedOn
}
group allocation by allocation.UserId
into g
select new
{
UserId = g.Key,
TruckId = g.First().TruckId,
CreatedOn = g.First().CreatedOn
};
All in one with fluent syntax :
var lastDateByTruck = TruckAllocations
.Where(ta => ta.Truck.Name != null && ta.Truck.Name != string.Empty)
.GroupBy(m => m.TruckId)
.Select(m => new
{
TruckId = m.Key,
CreatedOn = m.Max(x => x.CreatedOn)
})
.Join(TruckAllocations, x => new{x.TruckId, x.CreatedOn}, y => new{y.TruckId, y.CreatedOn}, (x, y) => y)
.GroupBy(m => m.UserId)
.Select(g => new
{
UserId = g.Key,
TruckId = g.First().TruckId,
CreatedOn = g.First().CreatedOn
});
I have 4 column, facilities0id, name, date, Quantity. I have few problem here
How to use orderby based on the quantity. I wan to find top 3 row. Anyone can help, thanks
DataClassesDataContext db = new DataClassesDataContext();
var query = from p in db.Facilities
join v in db.Reservations on p.facilities_id equals v.facilities_id
join c in db.Reservation_Details on v.reservation_id equals
c.resevation_id
where SqlMethods.Like(c.date, "%" + DropDownList1.Text + "%")
select new
{
p.facilities_id,
p.name,
c.date,
Quantity = p.Reservations.Count()
};
GridView1.DataSource = query.GroupBy(x => x.facilities_id)
.Select(g => g.First())
.ToList();
GridView1.DataBind();
int totalRowsCount = GridView1.Rows.Count;
Label2.Text = DateTime.Now.ToShortDateString();
Label3.Text = totalRowsCount.ToString() + " record(s)";
Label4.Text = DropDownList1.Text;
Data in my database
facilities_id name date Quantity
F001 cc 12-12-2014 3
F002 vv 12-12-2014 2
F003 gg 12-12-2014 1
F004 bb 12-12-2014 5
Here is my expected output
facilities_id name date Quantity
F004 bb 12-12-2014 5
F001 cc 12-12-2014 3
F002 vv 12-12-2014 2
Use OrderByDescending to sort your records by Quantity in descending order,then Take first 3 records:
query.GroupBy(x => x.facilities_id)
.Select(g => g.First())
.OrderByDescending(x => x.Quantity)
.Take(3)
.ToList();
Use For Descending "OrderByDescending"
.OrderByDescending(x => x.Quantity);
Use For Ascending "OrderBy"
OrderBy(x => x.Quantity);
you need to first use order by descending for column quantity and then take first three rows
I'm using the following LINQ to select data from a table:
(from m in entity.Results
where m.Group == 0 ||
m.Group == 1
orderby m.Points descending
select m);
This gives me a result of all Users who are in Group 1 or 2. With that i can display the points they have. But this shows me the points they have in Group 1 and Group 2 separately.
How can i group them and display the total points they have? So instead of this (What i have now):
user1 - group1 - 10
user1 - group2 - 7
user2 - group1 - 7
user2 - group2 - 5
I want this:
user1 - total: 17
user2 - total: 12
How do i have to adjust my query to get a result set like that?
You need to group the users, then use Sum to calculate the TotalPoints:
from m in entity.Results
where m.Group == 0 || m.Group == 1
group m by m.User into g
let TotalPoints = g.Sum(m => m.Points)
orderby TotalPoints descending
select new { User = g.Key, Username = g.Key.Username, TotalPoints };
entity.Results
.Where(m => m.Group == 0 || m.Group == 1)
.GroupBy(m => m.UserID)
.Select(m => new { User = m.Key, TotalPoints = m.Sum(v => v.Points) })
.OrderByDescending(m => m.TotalPoints);
Hi Vivendi use this(Please edit according to your requirement)
var q = (from h in entity.Results
group h by new { h.UserID} into hh
select new {
hh.Key.UserID,
Score = hh.Sum(s => s.Points )
}).OrderByDescending(i => i.Points);
Output
total: 17
total: 12
Another example with more than one sum and a join
from e in _context.LearnResults
join c in _context.Country on e.CountryId equals c.CountryId
where c.DomainId.Equals("xx")
group e by e.Country.Name into newCountry
let Approved = newCountry.Sum(e => e.Approved)
let Total = newCountry.Sum(e => e.Total)
select new LearnResults() { CountryName = newCountry.Key, Approved= Approved, Total=Total };