get data from two tables with max date for row - c#

I would like to get the list from two table with the condition for the largest date:
table Subject:
{id = 1, name = 'Subject 1', status = true},
{id = 2, name = 'Subject 2', status = true},
{id = 3, name = 'Subject 3', status = true},
table Days:
{id = 1, idSubject = 1, name = 'test1', dateFrom = '2022-10-01', dateTo = '2022-10-10'},
{id = 2, idSubject = 1, name = 'test1', dateFrom = '2022-10-02', dateTo = '2022-12-01'},
{id = 3, idSubject = 1, name = 'test2', dateFrom = '2022-01-01', dateTo = '2022-05-10'},
{id = 4, idSubject = 1, name = 'test90', dateFrom = '2022-01-05', dateTo = '2022-12-06'},
{id = 5, idSubject = 2, name = 'ex1', dateFrom = '2022-10-01', dateTo = '2025-01-05'}...
I would like to have data for subject.name = 'Subject 1':
{id = 2, idSubject = 1, name = 'test1', dateFrom = '2022-10-02', dateTo = '2022-12-01'},
{id = 4, idSubject = 1, name = 'test90', dateFrom = '2022-01-05', dateTo = '2022-12-06'}
I tried like that:
select s.id, d.id, d.idSubject, s.name, d.name, d.date_from, d.date_to
from SUBJECT s
join(select max(date_to) date_to, max(date_from) date_from, id, idSubject, name from Days group by id, date_from, date_to) d on s.id = d.idSubject
where s.name = 'Subject 1'
order by d.date_to desc
but I get duplicate records

This should work:
with subject AS
(
SELECT 1 as id, 'Subject 1' as name, 'true' as status FROM dual UNION ALL
SELECT 2, 'Subject 2', 'true' FROM dual UNION ALL
SELECT 3, 'Subject 3', 'true' FROM dual
),
days AS
(
SELECT 1 as id, 1 as idsubject, 'test1' as name, TO_DATE('2022-10-01', 'YYYY-MM-DD') as datefrom, TO_DATE('2022-10-10','YYYY-MM-DD') as dateto FROM dual UNION ALL
SELECT 2, 1, 'test1' , TO_DATE('2022-10-02', 'YYYY-MM-DD'), TO_DATE('2022-12-01','YYYY-MM-DD') FROM dual UNION ALL
SELECT 3, 1, 'test2' , TO_DATE('2022-01-01', 'YYYY-MM-DD'), TO_DATE('2022-05-10','YYYY-MM-DD') FROM dual UNION ALL
SELECT 4, 1, 'test90', TO_DATE('2022-01-05', 'YYYY-MM-DD'), TO_DATE('2022-12-06','YYYY-MM-DD') FROM dual UNION ALL
SELECT 5, 2, 'ex1' , TO_DATE('2022-10-01', 'YYYY-MM-DD'), TO_DATE('2025-01-05','YYYY-MM-DD') FROM dual
)
SELECT ds.*
FROM days ds
INNER JOIN subject s ON ds.idsubject = s.id
WHERE s.id = 1
AND ds.datefrom IN (SELECT MAX(datefrom)
FROM days
WHERE idsubject = ds.idsubject)
AND ROWNUM = 1
UNION ALL
SELECT ds.*
FROM days ds
INNER JOIN subject s ON ds.idsubject = s.id
WHERE s.id = 1
AND ds.dateto IN (SELECT MAX(dateto)
FROM days
WHERE idsubject = ds.idsubject)
AND ROWNUM = 1;

Related

Linq not grouping

Given the data below, I am trying to write a LINQ statement that will group by ParentProductId, and select the maximum EndDate if there is more than one item in the group.
Since the data listed below has two items with the same ParentProductId, I would expect three records to be returned (and for the "2020" date to be used for the ParentProductId = 1 group, not "2019"). However, the LINQ statement that I have is still returning all four records. What am I doing wrong?
Data:
Subscription.Add(new Subscription() { CustomerId = 555, ParentProductId = 37 , EndDate= null});
Subscription.Add(new Subscription() { CustomerId = 555, ParentProductId = 38 , EndDate = null });
Subscription.Add(new Subscription() { CustomerId = 555, ParentProductId = 1 , EndDate = new DateTime(2019, 11, 28) });
Subscription.Add(new Subscription() { CustomerId = 555, ParentProductId = 1, EndDate = new DateTime(2020, 1, 28) });
LINQ Statement:
var IndividualSubscription = (from s in db.Subscriptions
join ptp in db.ProductToProducts on s.ProductToProductId equals ptp.ProductToProductId
join p in db.Products on ptp.ParentProductId equals p.ProductId
where SubscriptionIds.Contains(s.OriginalSubscriptionId)
&& s.CustomerId == CustomerId
group new {ptp.ParentProductId, s.EndDate }
by new
{
s.CustomerId,
ptp.ParentProductId,
p.Name,
s.EndDate,
} into grp
select new NCCN.Model.IndividualGroupSubscription
{
CustomerId = grp.Key.CustomerId,
ParentProductId = grp.Key.ParentProductId,
ParentProductName = grp.Key.Name,
EndDate = grp.Max(p => p.EndDate),
}).ToList();
You group for {ptp.ParentProductId, s.EndDate }.
Group only for ParentProductId, if you need 3 rows result.
var subscription = new List<Subscription>(){new Subscription() { CustomerId = 555, ParentProductId = 37 , EndDate= null}
,new Subscription() { CustomerId = 555, ParentProductId = 38 , EndDate = null }
,new Subscription() { CustomerId = 555, ParentProductId = 1 , EndDate = new DateTime(2019, 11, 28) }
,new Subscription() { CustomerId = 555, ParentProductId = 1, EndDate = new DateTime(2020, 1, 28) }
};
var query = subscription
.GroupBy(x=> x.ParentProductId)
.Select(x=> new {x.Key, EndDate = x.Max(s=>s.EndDate)});
Note sure why your linq is that overkill but following your written requirement and not your code what you need is a million times shorter than what you have wrote
// get grouped by product id
var result = Subscription.GroupBy(s => s.ParentProductId)
// select to output something for each group. What you want is
// order descending all elements and pick the first which is the highest
.Select(grp => grp.OrderByDescending(o => o.EndDate).FirstOrDefault())
// returned as a list
.ToList();

Select TOP 1 for each FK in list using Entity Framework

I have a large table where I'm trying to select the top 1 row for each FK in a list.
My table is laid out as:
ChangeId | AssetId | Timestamp
1 1 123
2 2 999
3 1 3478
4 3 344
5 2 1092
Where ChangeId is my PK, AssetId is my FK and Timestamp is the value I'm trying to select.
If I try the following:
var results =
from Asset in _context.Asset
join change in _context.Change on Asset.AssetId equals change.AssetId into potentialChange
from actualChange in potentialChange.OrderByDescending(y => y.ChangeId).Take(1)
select
{
AssetId,
Timestamp
}
Where my expected result would be:
[
{
AssetId: 1,
Timestamp: 3478
},
{
AssetId: 2,
Timestamp: 1092
},
{
AssetId: 3,
Timestamp: 344
}
]
This query flags up the The LINQ expression could not be translated and will be evaluated locally. which is not suitable for a production rollout.
Running a foreach loop and selecting each item out 1 by 1 works, not it's not a performant solution.
Is there a suitable way to achieve the above?
Try to group it by AssetId and take max from each group
var results =
from Asset in _context.Asset
join change in _context.Change on Asset.AssetId equals change.AssetId into potentialChange
group potentialChange by potentialCharge.AssetId into g
select
{
g.Key,
g.Max().Timestamp
}
Use Group By as follows:
List<MyTable> data = new List<MyTable>()
{
new MyTable(){ChangeId = 1, AssetId = 1, Timestamp = 123},
new MyTable(){ChangeId = 2, AssetId = 2, Timestamp = 999},
new MyTable(){ChangeId = 3, AssetId = 1, Timestamp = 123},
new MyTable(){ChangeId = 5, AssetId = 3, Timestamp = 123},
new MyTable(){ChangeId = 5, AssetId = 2, Timestamp = 123},
};
var expectedData = data.OrderByDescending(d => d.Timestamp).GroupBy(d => d.AssetId).Select(g => new
{
AssetId = g.Key,
TimeStamp = g.First().Timestamp
}).ToList();
This will give your expected result.
Try using .First() instead of .Take(1)
LINQ How to take one record and skip rest c#

EF for Top 10 most popular locations c# [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I have a table tbLocations with the following columns:
int id {PRIMARY_KEY, AUTO_INCREMENT}
int userid {Foreign key with table_users}
varchar(200) location
In this table I have the following rows:
1, 1, New York
2, 1, California
3, 1, Seattle
4, 1, New York
5, 2, Seattle
6, 2, Ontario
7, 3, Chicago
8, 4, Las Vegas
9, 5, New York
I want to create a c# linq query that gets me the top 10 locations, in my case I should get
New York 2
Seattle 2
The issue here is that a location can be duplicate for a user i.e. New York is duplicate for userid 1 so I don't want such duplication to affect the final report.
Like in the final report I have New York =2 and not =3
How can I do this in LINQ?
I really have no idea where to start, I tried by grouping by but that didn't work
Start with this query:
select top 10 count(*) cnt, [location] from
(
select count(*) as dupl, userid, [location]
from tbLocations
group by userid, [location]
) as test
group by [location]
order by cnt desc
This gives these results:
cnt location
2 New York
2 Seattle
1 Ontario
1 California
1 Chicago
1 Las Vegas
Here is my solution:
var locations = new List<Location>
{
new Location{ Id = 1, UserId = 1, Name = "New York" },
new Location{ Id = 2, UserId = 1, Name = "California" },
new Location{ Id = 3, UserId = 1, Name = "Seattle" },
new Location{ Id = 4, UserId = 1, Name = "New York" },
new Location{ Id = 5, UserId = 2, Name = "Seattle" },
new Location{ Id = 6, UserId = 2, Name = "Ontario" },
new Location{ Id = 7, UserId = 3, Name = "Chicago" },
new Location{ Id = 8, UserId = 4, Name = "Las Vegas" },
new Location{ Id = 9, UserId = 5, Name = "New York" },
};
var topLocations = locations
.GroupBy(location => new { location.UserId, location.Name })
.Select(group => group.First())
.GroupBy(location => location.Name)
.Select(group => new { group.Key, Count = group.Count() })
.OrderByDescending(location => location.Count)
.Take(2);
foreach (var item in topLocations)
{
Console.WriteLine($"{item.Key} {item.Count}");
}

Linq to select objects with unique Id and greatest date?

I have a list of objects that look like this:
public class A
{
public int Id {get; set;}
public DateTime Date {get;set;}
public int TypeId {get; set;}
public int Version {get; set;}
}
My data looks like this:
Id Date TypeId Version
1 10/3/18 1 1
2 10/3/18 1 2
3 10/4/18 1 1
4 10/4/18 2 1
How can I make a linq query to return these 2 in a list where it gets the item with the greatest date where the version # is 1 and also uses the TypeId to return more items?
Id Date TypeId Version
3 10/4/18 1 1
4 10/4/18 2 1
This is what I have tried but my code only returns one item because of my FirstOrDefault function.
var q = from n in A.All.Where(x => x.Version == 1)
group n by n.TypeId into g
select g.OrderByDescending(t => t.Date).FirstOrDefault();
You need to group by typeId and then in each group order elements by date. Then you can pick first element in each group. Try this code:
var input = new[]
{
new A {Id = 1, Date = new DateTime(2018, 10, 3), TypeId = 1, Version = 1},
new A {Id = 2, Date = new DateTime(2018, 10, 3), TypeId = 1, Version = 2},
new A {Id = 3, Date = new DateTime(2018, 10, 4), TypeId = 1, Version = 1},
new A {Id = 4, Date = new DateTime(2018, 10, 4), TypeId = 2, Version = 1},
};
var result = input.Where(a => a.Version == 1)
.GroupBy(a => a.TypeId)
.Select(g => g.OrderByDescending(x => x.Date).First())
.ToArray();

How to split array to many arrays where id same linq

I have array:
OrderProduct[] OrderProductsOrder = new OrderProduct[] {
new OrderProduct { OrderID = 1, ProductID = 2, OrderCustomerID = 1 },
new OrderProduct { OrderID = 2, ProductID = 1, OrderCustomerID = 1 },
new OrderProduct { OrderID = 1, ProductID = 3, OrderCustomerID = 1 },
new OrderProduct { OrderID = 2, ProductID = 1, OrderCustomerID = 2 },
new OrderProduct { OrderID = 1, ProductID = 2, OrderCustomerID = 3 },
new OrderProduct { OrderID = 2, ProductID = 1, OrderCustomerID = 3 }};
How to split this array to three arrays, order by CustomerID, using linq.
Result should be this three arrays:
OrderProduct[] Customer1Order = new OrderProduct[] {
new OrderProduct { OrderID = 1, ProductID = 2, OrderCustomerID = 1 },
new OrderProduct { OrderID = 2, ProductID = 1, OrderCustomerID = 1 },
new OrderProduct { OrderID = 1, ProductID = 3, OrderCustomerID = 1 }};
OrderProduct[] Customer2Order = new OrderProduct[]
{new OrderProduct { OrderID = 2, ProductID = 1, OrderCustomerID = 2 }};
OrderProduct[] Customer3Order = new OrderProduct[] {
new OrderProduct { OrderID = 1, ProductID = 2, OrderCustomerID = 3 },
new OrderProduct { OrderID = 2, ProductID = 1, OrderCustomerID = 3 }};
Edited, removed the GroupBy() suggestion as it was redundant (courtesy of Innat3)
No reason to use GroupBy() at all, just use Where.
OrderProduct[] Customer1Order = OrderProductsOrder.Where(o => o.OrderCustomerID == 1).ToArray();
OrderProduct[] Customer2Order = OrderProductsOrder.Where(o => o.OrderCustomerID == 2).ToArray();
OrderProduct[] Customer3Order = OrderProductsOrder.Where(o => o.OrderCustomerID == 3).ToArray();
Start by grouping the entries by OrderCustomerID, and constructing an array from each group. After that, add groups to a dictionary:
var byCustId = OrderProductsOrder
.GroupBy(p => p.OrderCustomerID)
.ToDictionary(g => g.Key, g => g.ToArray());
Now you can grab individual arrays with TryGetValue or operator []:
OrderProduct[] customer2Order;
if (byCustId.TryGetValue(2, out customer2Order) {
... // Use customer2Order array
}

Categories