繁体   English   中英

Linq to SQL C#:日期之间的项目

[英]Linq to SQL C#: items between dates

我的SQL Server 2012中有2个表:

Errors (id, cityID, centerID, date)

InspectionVisits (id, cityID, centerID, datePerformed)

我试图获取errors inspection visits之间的errors数,以查看具有特定centerID的中心是否有所改善并构建图表。

到目前为止,这是我的代码,但是我找不到如何编写where子句来获取这些检查访问之间的错误数量的方法:

var errorsPerIV = from e in dc.Errors
                  where e.cityID == ctid && e.centerID == centerid 
                  group e by e.date.Date into g
                  join iv in dc.InspectionVisits on g.FirstOrDefault().cityID equals iv.cityID
                  where iv.centerID == g.FirstOrDefault().centerID
                  select new
                  {
                      Day = g.Key.Day + "/" +
                            g.Key.Month + "/" +
                            g.Key.Year,
                      Errors = g.Count()
                  };

示例案例诸如此类:在Inspection_Visit_1和Inspection_Visit_2之间出现5个错误,在Inspection_Visit_2和Inspection_Visit_3之间出现2个错误,以及在Inspection_Visit_3与今天之间出现1个错误。

编辑

如果我每天显示查询并仅在图表的x轴上标记检查访问次数,则可能会起作用。

我不确定是否有更好的方法,但是您可以执行以下操作

假设您有一个像

public class Summary
{
    public DateTime? PreviousInspection;
    public DateTime? NextInspection;
    public int Errors;
}

那么您可以通过查询以下信息来获取大部分信息

var errorsPerIV = (from e in dc.Errors
                      where e.cityID == ctid && e.centreID == centreid

                      // Find the date of the previous inspection (if any)
                      let previousInspection = (from i in dc.InspectionVisits where i.cityID == e.cityID && i.centreID == e.centreID && i.datePerformed <= e.date orderby i.datePerformed descending select i.datePerformed).FirstOrDefault()

                       // Find the date of the next inspection (if any)
                      let nextInspection     = (from i in dc.InspectionVisits where i.cityID == e.cityID && i.centreID == e.centreID && i.datePerformed >  e.date orderby i.datePerformed ascending  select i.datePerformed).FirstOrDefault()

                      group e by new { previousInspection , nextInspection } into results

                      orderby results.Key.previousInspection 
                      select new Summary
                      {
                          PreviousInspection = results.Key.previousInspection,
                          NextInspection     = results.Key.nextInspection ,
                          Errors             = results.Count()
                      })
                      .ToList();

但是,如果两次访问之间没有错误,则这些访问将不会出现在您的列表中,因此您需要查找所有访问,并查看是否丢失,例如

var inspectionsDates = (from i in InspectionVisits where i.cityID == ctid && i.centreID == centreid orderby i.datePerformed select i.datePerformed).ToList();

    for(int i=0; i< inspectionsDates.Count-1; i++)
    {
        if (!errorsPerIV.Any(a=>a.PreviousInspection == inspectionsDates[i]))
        {
            errorsPerIV.Add(new Summary() { PreviousInspection = inspectionsDates[i], NextInspection = inspectionsDates[i + 1], Errors = 0});
        }
    }

我认为这在客户端最容易处理。

首先,您要获取有趣的InspectionVisits并按日期对其进行排序,然后转换为Enumerable以将其拉到客户端:

var orderedIVs = InspectionVisits.Where(iv => iv.cityID == ctid && iv.centerID == centerid).Select(iv => iv.dateperformed).OrderBy(ivdp => ivdp).AsEnumerable();

现在使用沿Enumerable处理的扩展方法以计算运行值(之所以称为Scan ,是因为它是根据APL Scan运算符建模的,就像返回所有中间值的Aggregate一样):

// TKey combineFn(T prev, T cur)
// TKey lastKeyFn(T cur)
public static IEnumerable<TResult> Scan<T, TResult>(this IEnumerable<T> src, Func<T, T, TResult> combineFn, Func<T, TResult> lastKeyFn) {
    using (var srce = src.GetEnumerator()) {
        if (srce.MoveNext()) {
            var prev = srce.Current;

            while (srce.MoveNext()) {
                yield return combineFn(prev, srce.Current);
                prev = srce.Current;
            }
            yield return lastKeyFn(prev);
        }
    }
}

您可以计算检查访问的时间段:

var IVPeriods = orderedIVs.Scan((prev, cur) => new { Begin = prev, End = cur }, cur => new { Begin = cur, End = DateTime.Now });

最后,使用句点,您可以计算在每个句点之间发生的Errors

var errorsPerIV = IVPeriods.Select(ivp => new { Day = ivp.Begin.Date, Count = Errors.Where(e => ivp.Begin <= e.date && e.date <= ivp.End).Count() });

如果要在服务器端进行此处理,则必须将InspectionVisits表自身连接起来,以便可以创建期间。 我尚未使用SQL Server对此进行测试:

var orderedIVs = InspectionVisits.Where(iv => iv.cityID == ctid && iv.centerID == centerid).Select(iv => iv.dateperformed).OrderBy(ivdp => ivdp);

var IVPeriods = (from ivb in orderedIVs
                from ive in orderedIVs
                where ivb < ive
                group ive by ivb into iveg
                 select new { Begin = iveg.Key, End = iveg.OrderBy(iv => iv).First() })
                .Concat((from ivb in orderedIVs orderby ivb descending select new { Begin = ivb, End = DateTime.Now }).Take(1));

var errorsPerIV = IVPeriods.Select(ivp => new { Day = ivp.Begin.Date, Count = Errors.Where(e => ivp.Begin <= e.date && e.date <= ivp.End).Count() });

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM