我有一個表格充滿了行動。每個操作都由特定的用戶在特定的日期時間完成。所以它有4個字段:Id,UserId,ActionId和ActionDate。如何在T-SQL或Linq to Sql的相關實體列表中選擇其類型的最新實體?
起初,我只是報告的前10最近的操作是這樣的:
(from a in db.Action
orderby a.ActionDate descending
select a).Take(10);
說起來很簡單,它的作品。但是這份報告沒有我想象的那麼有用。這是因爲某些用戶可能會連續採取10個動作,並佔據整個前10名單。所以我想報告爲最近活躍的前10名用戶中的每一個採取的最近一次採取的行動。
從這個問題的另一個問題,我得到了大部分的方式。它看起來像我需要「組」功能。如果我這樣做:
from a in db.Action
orderby a.ActionDate descending
group a by a.UserId into g
select g;
而且在linqpad運行它,我得到一個IOrderedQueryable<IGrouping<Int32,Action>>
結果其中一組爲每個用戶設置。但是,它顯示了每個用戶採取的所有操作,並且結果集是分層的,我希望它是平坦的。
所以,如果我的動作表看起來像這樣
Id UserId ActionId ActionDate
1 1 1 2010/01/09
2 1 63 2010/01/10
3 2 1 2010/01/03
4 2 7 2010/01/06
5 3 11 2010/01/07
我想查詢返回的記錄2,5和4的順序。這爲每個用戶顯示了該用戶所採取的最新操作,並且所有報告的操作都是按順序排列的,而最新的操作是按順序排列的。所以我想看看:
Id UserId ActionId ActionDate
2 1 63 2010/01/10
5 3 11 2010/01/07
4 2 7 2010/01/06
編輯:
我有一個艱難的時間在T-SQL表達這一點,也是如此。該查詢得到我的用戶和他們的最後一個動作日期:
select
a.UserId,
max(a.ActionDate) as LastAction
from
Action as a
group by
a.UserId
order by
LastAction desc
但是我怎麼訪問連接到最大ActionDate被發現的記錄等信息?
EDIT2:我一直在重構和Action現在叫做Read,但其他一切都是一樣的。我已經採用了弗蘭克的解決方案,它如下:
(from u in db.User
join r in db.Read on u.Id equals r.UserId into allRead
where allRead.Count() > 0
let lastRead = allRead.OrderByDescending(r => r.ReadDate).First()
orderby lastRead.ReadDate descending
select new ReadSummary
{
Id = u.Id,
UserId = u.Id,
UserNameFirstLast = u.NameFirstLast,
ProductId = lastRead.ProductId,
ProductName = lastRead.Product.Name,
SegmentCode = lastRead.SegmentCode,
SectionCode = lastRead.SectionCode,
ReadDate = lastRead.ReadDate
}).Take(10);
這變成如下:
exec sp_executesql N'SELECT TOP (10) [t12].[Id], [t12].[ExternalId], [t12].[FirstName], [t12].[LastName], [t12].[Email], [t12].[DateCreated], [t12].[DateLastModified], [t12].[DateLastLogin], [t12].[value] AS [ProductId], [t12].[value2] AS [ProductName], [t12].[value3] AS [SegmentCode], [t12].[value4] AS [SectionCode], [t12].[value5] AS [ReadDate2]
FROM (
SELECT [t0].[Id], [t0].[ExternalId], [t0].[FirstName], [t0].[LastName], [t0].[Email], [t0].[DateCreated], [t0].[DateLastModified], [t0].[DateLastLogin], (
SELECT [t2].[ProductId]
FROM (
SELECT TOP (1) [t1].[ProductId]
FROM [dbo].[Read] AS [t1]
WHERE [t0].[Id] = [t1].[UserId]
ORDER BY [t1].[ReadDate] DESC
) AS [t2]
) AS [value], (
SELECT [t5].[Name]
FROM (
SELECT TOP (1) [t3].[ProductId]
FROM [dbo].[Read] AS [t3]
WHERE [t0].[Id] = [t3].[UserId]
ORDER BY [t3].[ReadDate] DESC
) AS [t4]
INNER JOIN [dbo].[Product] AS [t5] ON [t5].[Id] = [t4].[ProductId]
) AS [value2], (
SELECT [t7].[SegmentCode]
FROM (
SELECT TOP (1) [t6].[SegmentCode]
FROM [dbo].[Read] AS [t6]
WHERE [t0].[Id] = [t6].[UserId]
ORDER BY [t6].[ReadDate] DESC
) AS [t7]
) AS [value3], (
SELECT [t9].[SectionCode]
FROM (
SELECT TOP (1) [t8].[SectionCode]
FROM [dbo].[Read] AS [t8]
WHERE [t0].[Id] = [t8].[UserId]
ORDER BY [t8].[ReadDate] DESC
) AS [t9]
) AS [value4], (
SELECT [t11].[ReadDate]
FROM (
SELECT TOP (1) [t10].[ReadDate]
FROM [dbo].[Read] AS [t10]
WHERE [t0].[Id] = [t10].[UserId]
ORDER BY [t10].[ReadDate] DESC
) AS [t11]
) AS [value5]
FROM [dbo].[User] AS [t0]
) AS [t12]
WHERE ((
SELECT COUNT(*)
FROM [dbo].[Read] AS [t13]
WHERE [t12].[Id] = [t13].[UserId]
)) > @p0
ORDER BY (
SELECT [t15].[ReadDate]
FROM (
SELECT TOP (1) [t14].[ReadDate]
FROM [dbo].[Read] AS [t14]
WHERE [t12].[Id] = [t14].[UserId]
ORDER BY [t14].[ReadDate] DESC
) AS [t15]
) DESC',N'@p0 int',@p0=0
如果有人知道更簡單的東西(爲它的運動),我想知道,但我認爲這可能夠好了。
這工作,我很欣賞這非常多,但它最終會爲前10名列表執行一個查詢,然後再執行另外10個查詢(每個用戶都會將其列入列表中)。我通過在linqpad中執行SQL Profiler時驗證了這一點。 我希望我可以在單個查詢中做到這一切。它是儀表板的一部分,已經在做很多查詢。 – Chris 2010-01-12 22:33:31
你是指子查詢還是單獨的查詢?請發佈我現在很好奇的SQL。 – 2010-01-12 23:12:09
當我發佈該評論時,我確實是指單獨的查詢。但是在做了一些重構和進一步採用之後,這些查詢就消失了。也許這是我的錯誤?無論如何,該代碼張貼,以防您仍然好奇。 – Chris 2010-01-12 23:25:29