我試圖弄清楚如何撰寫 LINQ / Entity Framework 查詢以回傳表中每個符號可用的最新資料。
我的資料庫表如下所示:
ID symbol price_date price
------------------------------------
1 AAPL 2022-02-28 174.50
2 MSFT 2022-02-28 307.20
3 AAPL 2021-03-01 172.23
4 MSFT 2021-03-01 304.15
不過,并非每個符號每天都有記錄。ID 密鑰是連續的,可以安全使用,因為給定符號的最高 ID 將包含最新資料。
如果我正在撰寫 SQL 查詢,則以下內容將回傳我要查找的內容:
select prices.*
from prices
where id in (select max(id) from prices group by symbol)
在 Linq 中,我無法將其轉換為單個查詢。到目前為止,我將其分為兩個查詢:
var maxIds = from pp in ctx.Prices
group pp by pp.Symbol
into maxIdBySymbol
select maxIdBySymbol.Max(pp => pp.Id);
var latestPrices = ctx.Prices.Where(it => maxIds.Contains(it.Id)).ToList();
有沒有辦法讓這個在 LINQ 中成為一個單一的查詢?
謝謝
uj5u.com熱心網友回復:
添加:建議的解決方案有效,但效率較低
有關更多資訊,請參閱末尾的添加。
原始解決方案
因此,您將首先創建記錄組,其中每個組僅包含一個特定符號的記錄。因此,您將擁有一組包含符號 AAPL 的記錄,一組包含符號 MSFT 的記錄等。
我正在嘗試...查詢...表中每個符號可用的最新資料。
因此,一旦獲得了組,您就可以在組中選擇一個元素。根據您的要求,您選擇最新的元素,它是具有最高值的元素PriceDate。正如您所說,您還可以將具有最高值的元素用于 property ID。就我個人而言,我不會這樣做,因為如果在很遠的將來您的 ID 不再按升序排列,例如因為您在輸入錯誤后添加了編輯 PriceDate 的功能。
為此,我將使用具有引數 resultSelector 的 Queryable.GroupBy 的多載。使用 resultSelector 選擇您想要的每個組的一個元素。
var newestRecordPerSymbol = dbContext.PriceRecords
// make groups of priceRecords with same value for property Symbol
.GroupBy( priceRecord => priceRecord.Symbol,
// parameter resultSelector: for every symbol and all priceRecords
// that have this symbol, take the newest one
// = order by descending PriceDate and take the first one
(symbol, priceRecordsWithThisSymbol) => priceRecordsWithThisSymbol
.OrderByDescending(priceRecord => priceRecord.PriceDate)
.FirstOrDefault();
換句話說:從 PriceRecords 表中,將具有相同屬性 Symbol 值的 PriceRecords 組。從 Symbol 和具有此符號的 PriceRecords 的每個組合中,按屬性 PriceDate 的降序排列所有 PriceRecords,并僅保留第一個。
每個組至少有一個元素,因此您可以使用First以及FirstOrDefault. 某些版本的 EntityFramework 或 DBMS 在使用 First 時存在問題。如果遇到此問題,請使用 FirstOrDefault。
如果你還想拿 ID 最高的那一個:
.OrderByDescending(priceRecord => priceRecord.ID)
.FirstOrDefault(),
為什么這個解決方案效率較低。
在原始解決方案中,對組中的所有記錄進行排序,并且只取第一個。如果只取第一個元素,那么對第二個、第三個等元素進行排序有點浪費。
在原始 SQL 中,您將看到如下代碼:
select maxIdBySymbol.Max(pp => pp.Id);
So, not all elements are sorted. The sequence is enumerated only once, and the largest one is returned. This is way more effcient then sorting elements that you won't use anyway.
To create code like this, we need to change parameter resultSelector of the GroupBy. Let is use a method like Max(propertySelector), or one of the overloads of Queryable.Aggregate. Something like this:
// parameter resultSelector: keep the record with the largest ID
(symbol, priceRecordsWithThisSymbol) => priceRecordsWithThisSymbol
.Max(record => record.Id);
Alas, although the guys from entity framework did a tremendous job, this overload of the Max method is not supported, so are none of the Aggregate methods. See List of Supported and Unsupported Linq methods
uj5u.com熱心網友回復:
您可以Where與not Any結合使用:
ctx.Prices.Where(prices1 => !ctx.Prices.Any(prices2 => (prices2.Id > prices1.Id) && (prices1.symbol.Equals(prices2.symbol))))
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/454024.html
上一篇:字串串列中的簡單LINQ
