2010-01-12 43 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