2010-01-12 74 views
1

我有一個表格充滿了行動。每個操作都由特定的用戶在特定的日期時間完成。所以它有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 

如果有人知道更簡單的東西(爲它的運動),我想知道,但我認爲這可能夠好了。

回答

1

大概有這一些錯誤,但我想你想要做一個加入到集合,然後使用「讓」給選擇集合的成員:

(
from u in db.Users 
join a in db.Actions on u.UserID equals a.UserID into allActions 
where allActions.Count() > 0 
let firstAction = allActions.OrderByDescending(a => a.ActionDate).First() 
orderby firstAction.ActionDate descending 
select (u,firstAction) 
).Take(10) 
+0

這工作,我很欣賞這非常多,但它最終會爲前10名列表執行一個查詢,然後再執行另外10個查詢(每個用戶都會將其列入列表中)。我通過在linqpad中執行SQL Profiler時驗證了這一點。 我希望我可以在單個查詢中做到這一切。它是儀表板的一部分,已經在做很多查詢。 – Chris 2010-01-12 22:33:31

+0

你是指子查詢還是單獨的查詢?請發佈我現在很好奇的SQL。 – 2010-01-12 23:12:09

+0

當我發佈該評論時,我確實是指單獨的查詢。但是在做了一些重構和進一步採用之後,這些查詢就消失了。也許這是我的錯誤?無論如何,該代碼張貼,以防您仍然好奇。 – Chris 2010-01-12 23:25:29

相關問題