我有一个表格充满了行动。每个操作都由特定的用户在特定的日期时间完成。所以它有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