Rewriting this SQL in Lambda - using count and group by - c#

I'm stuck rewriting this SQL in Lambda:
SELECT TOP 1000 COUNT(LoginDateTime)
,[LoginDateTime]
,[Culture]
FROM [LearningApp].[dbo].[UserActivities]
group by LoginDateTime, Culture
Result:
+-----+---------------------------+----------+
| | LoginDateTime | Culture |
+-----+---------------------------+----------+
| 1 | 2016-07-14 12:21:23.307 | de |
| 4 | 2016-07-13 12:21:23.307 | en |
| 2 | 2016-07-14 12:21:23.307 | en |
+-----+---------------------------+----------+
And my code:
public List<UserActivityResponseContract> GetUserActivity()
{
var userActivityResponseContracts = new List<UserActivityResponseContract>();
var userActivitiesList = _baseCommands.GetAll<UserActivity>()
.Select(x => new
{
x.LoginDateTime,
x.Culture
})
.GroupBy(x => new { x.LoginDateTime, x.Culture});
foreach (var userActivity in userActivitiesList)
{
userActivityResponseContracts.Add(new UserActivityResponseContract
{
ActivityDate = userActivity.Key.LoginDateTime.ToShortDateString(),
NumberOfTimesLoggedIn = userActivity.Count(),
Culture = userActivity.Key.Culture
});
}
return userActivityResponseContracts;
}
It doesn't seem very difficult but I am a bit stuck.

Method Syntax:
var result = _baseCommands.GetAll<UserActivity>()
.GroupBy(x => new { x.LoginDateTime, x.Culture})
.Select (x => new UserActivityResponseContract
{
ActivityDate = x.Key.LoginDateTime.ToShortDateString(),
Culture = x.Key.Culture,
NumberOfTimesLoggedIn = x.Count()
})
.Take(1000).ToList();
You can also use an overload of GroupBy that enables you to pass the select function as a second parameter
Query Syntax:
var result = (from x in _baseCommands.GetAll<UserActivity>()
group x by new { x.LoginDateTime, x.Culture} into g
select new UserActivityResponseContract
{
ActivityDate = g.Key.LoginDateTime.ToShortDateString(),
Culture = g.Key.Culture,
NumberOfTimesLoggedIn = g.Count()
}).Take(1000).ToList();
To GroupBy just the Date part of this DateTime do: x.LoginDateTime.Date

Related

Linq to sql query check for equality of tuples

How write linq to sql query to retrieve records from table below that (B ,C) be in list c.
Table is in database.
var c = new List<(int,int)>{(1,4), (3,6)};
+---+---+---+
| A | B | C |
+---+---+---+
| a | 1 | 4 |
| b | 2 | 5 |
| c | 3 | 6 |
+---+---+---+
Query should return a and c.
If you are talking about tuples being "fully"(all elements are sequentially equal) equal then you can just use contains:
var c = new List<(int,int)>{(1,3), (3,6)};
var table = new List<(int,int)>{(1,3), (2,5), (3,6)};
var res = table
.Where(i => c.Contains(i))
.ToList();
Equality and tuples
If #Caius Jard's assumption is right then just change .Where(i => c.Contains(i)) to .Where(i => !c.Contains(i))
I am not sure how your logic is but i think you are trying to do something like this,
Let's assume your table model looks like below,
public class MyTable {
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
public MyTable(string a, string b, string c) {
A = a;
B = b;
C = c;
}
}
And let's fill the data you have shared and query,
var c = new List<(int, int)> { (1, 4), (3, 6) };
List<MyTable> myTables = new List<MyTable>();
myTables.Add(new MyTable("a", "1", "4"));
myTables.Add(new MyTable("b", "2", "5"));
myTables.Add(new MyTable("c", "3", "6"));
var res = myTables.Where(x => c.Any(y => y.Item1.ToString() == x.B && y.Item2.ToString() == x.C)).Select(x => x.A);
Console.WriteLine(string.Join(" ", res));
Console.ReadKey();
This will print:
a c

how to group data in Linq with date

Im using Linq and having 2 tables which store the record as following
OrderMasterTable
Order_ID |Place_Date |ExpectedDelivery_Date |IsDelivered
==========|=============|=======================|============
1 |1993-02-19 | 1993-02-20 00:01:00 | True
2 |1993-02-20 | 1993-02-20 00:01:00 | True
3 |1993-02-21 | 1993-02-22 00:01:00 | True
4 |1993-02-22 | 1993-02-23 00:01:00 | False
OrderAssignTable
Order_ID |Delivered_By |Delivery_Date
==========|=============|=======================
1 |User123 | 1993-02-20 00:01:00
2 |UserXyz | 1993-02-20 00:01:01
3 |User345 | 1993-02-24 00:01:00
I want to group output data by delivered date in such a way that it appears in a following way:
Date: 1993-02-20,
OnTime: 1,
Delayed:1
Date: 1993-02-22,
OnTime :1,
Delayed: 0
* OnTime if deliveryDateTime is <= ExpectedTime
* Date is deliveryDate
pls,help me out
you can try this.
var query = from assign in OrderAssignTable
join master in OrderMasterTable on assign.Order_ID equals master.Order_ID
where master.IsDelivered == true
group new { assign, master } by assign.Delivery_Date.Date into g
select new
{
Date = g.Key,
OnTime = g.Count(i => i.assign.Delivery_Date <= i.master.ExpectedDelivery_Date),
Delayed = g.Count(i => i.assign.Delivery_Date > i.master.ExpectedDelivery_Date)
};
That should do:
var result = Orders
.Join(Assigns, o => o.OrderId, a => a.OrderId, (o, a) => new {Order = o, Assign = a})
.GroupBy(o => o.Order.ExpectedDeliveryDate.Date)
.Select(g => new
{
Date = g.Key,
OnTime = g.Count(o => o.Assign.DeliveryDate <= o.Order.ExpectedDeliveryDate),
Delayed = g.Count(o => o.Assign.DeliveryDate > o.Order.ExpectedDeliveryDate)
})
.ToArray();

How group List by key and transform the result

I have the following list and I need to transform it to get this result
original list
+----+--------------------+
| key| email |
+====+====================+
| 1 | one#gmail.com |
| 2 | two#gmail.com |
| 1 | three#gmail.com |
| 1 | four#gmail.com |
| 2 | five#gmail.com |
| 2 | six#gmail.com |
+----+----------------+-----
New list the mails concatenated with ;
+----+---------------------------------------------------+
| key| email |
+====+===================================================+
| 1 | one#gmail.com;three#gmail.com;four#gmail.com |
| 2 | two#gmail.com;five#gmail.com;six#gmail.com |
+----+---------------------------------------------------+
How can i accomplish this task with c# Linq? thanks
Try in this way:
x.GroupBy(t => new {t.Id})
.Select(t => new {
Id = t.Key.Id,
email = String.Join(", ", t.Select(p => p.Email).ToArray())
}
Supposing that you have a class similar to this:
public class myEmails
{
public int Key { get; set; }
public string Email { get; set; }
}
and a List<myEmails> that could be like this:
List<myEmails> emails = new List<myEmails>();
You could GroupBy the Key value and then Join all strings (Emails) related to that Key, creating a new Dictionary<int, string> that contains all the Emails grouped by the given Key:
var emailsDictionary = emails
.GroupBy(eml => eml.Key)
.ToDictionary(grp => grp.Key, grp => string.Join(" ", grp.Select(eml => eml.Email)));
Test the result with:
emailsDictionary.ToList().ForEach(dict => Console.WriteLine($"{dict.Key}: {dict.Value}"));
It should give you:
1: one#gmail.com three#gmail.com four#gmail.com
2: two#gmail.com five#gmail.com six#gmail.com
As a note, if you're interested, you could also use Aggregate instead of Join, so this:
grp => string.Join(" ", grp.Select(eml => eml.Email))
could also be expressed as:
grp => grp.Aggregate("", (s, eml) => (eml.Email + " " + s))

How to find the min dates from the list of items?

I have a table structure like this
id | itemId | date |
1 | a1 | 6/14/2015
2 | a1 | 3/14/2015
3 | a1 | 2/14/2015
4 | b1 | 6/14/2015
5 | c1 | 6/14/2015
From this table structure I am trying to get all the distinct items that has min date. for e.g. I am trying to get id = 3,4 and 5.
I have tried following code but I couldn't
var items = (from i in _db.Items
//where min(i.date) // doesn't seem right
group i by i.itemID
into d select new
{
iId = d.Key,
}).Distinct();
Given your sample data, I would do this:
var query =
from i in _db.Items
group i by i.itemId into gis
let lookup = gis.ToLookup(x => x.date, x => x.id)
from x in lookup[gis.Min(y => y.date)]
select x;
var items = from i in _db.Items
group i.date by i.itemID
into d select new {
iId = d.Key, iDate = d.Min()
};

GROUP BY in datatable on two columns with sum of third column using LINQ

I am searching for a LINQ query for which input and output datatables are as below -
Name Code count
-------------------------
User1 q1 2
user1 q2 2
user2 q2 1
user2 q3 3
user1 q1 2
Name Code Count
-----------------------
User1 | q1 | 4
User1 | q2 | 2
User1 | q3 | 0
User2 | q1 | 0
User2 | q2 | 1
User2 | q3 | 3
i.e. I want sum of count for distinct set of codes for each Name, in result table, it showing (user1, q3,0) because there is no record of q3 for user1 in input datatable, Please help in this regard, Thanks again
This should work:
var query = table.AsEnumerable()
.GroupBy(row => new { Name = row.Field<string>("Name"), Code = row.Field<string>("Code") });
var table2 = table.Clone(); // empty table with same schema
foreach (var x in query)
{
string name = x.Key.Name;
string code = x.Key.Code;
int count = x.Sum(r => r.Field<int>("Count"));
table2.Rows.Add(x.Key.Name, x.Key.Code, count);
}
Edit: if you instead want to modify the original table and sum the count per each name-code group, use this approach which uses a Dictionary as lookup:
var nameCodeCountLookup = table.AsEnumerable()
.GroupBy(row => new { Name = row.Field<string>("Name"), Code = row.Field<string>("Code") })
.ToDictionary(ncGrp => ncGrp.Key, ncGrp => ncGrp.Sum(r => r.Field<int>("Count")));
foreach (DataRow row in table.Rows)
{
string Name = row.Field<string>("Name");
string Code = row.Field<string>("Code");
row.SetField("Count", nameCodeCountLookup[new { Name, Code }]);
}
However, i don't know why your result table contains this row:
User1 | q3 | 0
There is no name-code combination User1+q3 in the original table.
I think here is what you looking for:
var result =
new DataTable().Rows.Cast<DataRow>()
.Select(p => new {User = p[0], Q = p[1], Value = (double) p[2]})
.GroupBy(p => new {p.User, p.Q})
.Select(p => new {User = p.Key.User, Q = p.Key.Q, Total = p.Sum(x => x.Value)})
.ToList();
Or almost same, but you can do it too:
var result =
new DataTable().Rows.Cast<DataRow>()
.Select(p => new
{
User = p.Field<string>("column1Name"),
Q = p.Field<string>("column2Name"),
Value = p.Field<double>("column3Name")
})
.GroupBy(p => new {p.User, p.Q})
.Select(p => new {User = p.Key.User, Q = p.Key.Q, Total = p.Sum(x => x.Value)})
.ToList();

Categories

Resources