只选择时间间隔内的第一条记录
本文关键字:一条 记录 选择 时间 | 更新日期: 2023-09-27 18:15:44
我有以下表格
CREATE TABLE [dbo].[DeviceLogs](
[DeviceLogId] [int] IDENTITY(1,1) NOT NULL,
[UserId] [nvarchar](50) NULL,
[LogDate] [datetime2](0) NULL,
)
GO
数据样本
1 1 2013-05-29 11:05:15 //accepted (its the first occurance for userid 1)
2 1 2013-05-29 11:05:20 //discarded (within 5 mins from 1st record)
3 1 2013-05-29 11:07:56 //discarded (within 5 mins from 1st record)
4 1 2013-05-29 11:11:15 //accepted (after 5 mins from 1st occurance)
5 2 2013-05-29 11:06:05 //accepted (its the first occurance for userid 2)
6 2 2013-05-29 11:07:18 //discarded (within 5 mins from 1st record)
7 2 2013-05-29 11:09:38 //discarded (within 5 mins from 1st record)
8 2 2013-05-29 11:12:15 //accepted (after 5 mins from 1st occurance)
我想只选择从以前选择的记录5分钟后发生的记录,并包括数据集中的第一个记录
期望输出
1 1 2013-05-29 11:05:15
4 1 2013-05-29 11:11:15
5 2 2013-05-29 11:06:05
8 2 2013-05-29 11:12:15
我正在尝试GroupBy,但没有给出日期
db.DeviceLogs.GroupBy(g=>new {g.LogDate.Year,
g.LogDate.Month,
g.LogDate.Day,
g.LogDate.Hour,
g.LogDate.Minutes,
g.UserID})
.Select(s=>new {UserID=s.Key.UserID, s.???});
提前感谢。
var result =
from log in db.DeviceLogs
let byId =
db.DeviceLogs.Where(item => item.UserId == log.UserId)
let first =
byId.First(item => item.LogDate == byId.Min(min => min.LogDate))
where
log.Equals(first) || (log.LogDate - first.LogDate).Minutes > 5
select log;
好吧。
var firstDates = db.DeviceLogs.GroupBy(d => d.UserId).ToDictionary(
g => g.Key,
g => g.OrderBy(d => d.LogDate).First().LogDate);
db.DeviceLogs.GroupBy(g => new
{
v = Math.Floor(SqlMethods.DateDiffMinute(firstDates[d.UserId], g.LogDate) / 5),
u = g.UserID
}).Select(s => s.OrderBy(s => s.LogDate).First());
我不确定你可以使用linq到SQL在一个查询中做到这一点。如果分钟数超过32位整数的最大值,则可能存在问题。
我不确定您是否可以使用单个LINQ语句完成此操作,因为您需要记住生成的最后一条记录的DateTime。你可以像这样使用迭代器块:
private static readonly TimeSpan MinimumTimeSpan = new TimeSpan(0,5,0);
IEnumerable<Record> getSparseRecords(IEnumerable<Record> allRecords)
{
DateTime previous = DateTime.MinValue;
foreach(var record in allRecords)
{
TimeSpan dif = record.DateTime - previous;
if (dif >= MinimumTimeSpan)
{
previous = record.DateTime;
yield return record;
}
}
}
Record将是表示单个记录的类,其中包含DateTime
类型的DateTime属性(参见这里)。如果您的LogDate
属性是不同的类型,您可能需要更改代码。
这就是我的解决方案
class Program
{
static void Main(string[] args)
{
List<DeviceLog> list = new List<DeviceLog>
{
new DeviceLog() { Id = 1, UserId = 1, LogDate = DateTime.Parse("2013-05-29 11:05:15") },
new DeviceLog() { Id = 2, UserId = 1, LogDate = DateTime.Parse("2013-05-29 11:05:20") },
new DeviceLog() { Id = 3, UserId = 1, LogDate = DateTime.Parse("2013-05-29 11:07:56") },
new DeviceLog() { Id = 4, UserId = 1, LogDate = DateTime.Parse("2013-05-29 11:11:15") },
new DeviceLog() { Id = 5, UserId = 2, LogDate = DateTime.Parse("2013-05-29 11:06:05") },
new DeviceLog() { Id = 6, UserId = 2, LogDate = DateTime.Parse("2013-05-29 11:07:18") },
new DeviceLog() { Id = 7, UserId = 2, LogDate = DateTime.Parse("2013-05-29 11:09:38") },
new DeviceLog() { Id = 8, UserId = 2, LogDate = DateTime.Parse("2013-05-29 11:12:15") },
};
list = list.Where(l => (l.Id == list.Where(g => g.UserId == l.UserId).Min(h => h.Id))
|| (l.LogDate - list.Where(g => g.UserId == l.UserId).OrderBy(m => m.Id).First().LogDate).Minutes > 5 ).ToList();
}
}
class DeviceLog
{
public int Id { get; set; }
public int UserId { get; set; }
public DateTime LogDate { get; set; }
}
我可以建议你一个SQL解决方案:
SELECT [DeviceLogId],[UserId],[LogDate] FROM (
SELECT *,
(SELECT top 1 [LogDate] FROM DeviceLogs t2
WHERE datediff(minute,t2.logDate,t1.logDate)>5
ORDER BY [LogDate] DESC) prev,
(SELECT TOP 1 [Logdate] FROM DeviceLogs t3
WHERE t3.[LogDate]=
(SELECT MIN([LogDate])
FROM DeviceLogs t4
WHERE t4.[UserId]=t1.[UserId])) first
FROM DeviceLogs t1 ) tres
WHERE prev IS NOT NULL OR first=logdate
参见提琴手http://sqlfiddle.com/#!6/fa74e/50