左外部日历表加入LINQ-to-SQL

时间:2012-12-05 15:37:04

标签: c# sql sql-server linq linq-to-sql

如何在LEFT OUTER JOINCalendar表中编写以下Sales SQL查询,以便在LINQ中按日,周或月对总计销售进行分组,以便它可以由LINQ-to-SQL实现?

SELECT c.CalendarDate, c.FirstDayOfWeek, c.FirstDayOfMonth,
       ISNULL(s.Total, 0) as Total
FROM Calendar as c
LEFT OUTER JOIN Sales as s
 on s.SaleDate >= c.CalendarDateTime and
    s.SaleDate < c.NextDayDateTime
WHERE s.SaleDate BETWEEN @since and @until

我设法在LINQ中使用内部联接,但是我需要一个外部联接来检索零销售的天数。这是我用于内连接的代码:

var sales = from s in db.Sales
            from c in db.Calendars
            where
                s.SaleDate >= c.CalendarDate && s.SaleDate < c.NextDayDateTime
                && s.SaleDate >= sinceDate && s.SaleDate < dateEnd
            select new
            {
                c.CalendarDate,
                c.FirstDateOfWeek,
                c.FirstDateOfMonth,
                s.Total
            };

然后,我可以按如下方式打开日期间隔和分组销售:

每日:

var groupedSales = sales.GroupBy(x => x.CalendarDate);

每周:

var groupedSales = sales.GroupBy(x => x.FirstDateOfWeek);

每月:

var groupedSales = sales.GroupBy(x => x.FirstDateOfMonth);

最后:

var salesReport = from g in groupedSales
                  orderby g.Key
                  select new {
                      Date = g.Key,
                      Total = g.Sum(x => x.Total)
                  };

或者,它也可以在检索非零日销售后,将零销售记录注入我的报告中。

1 个答案:

答案 0 :(得分:0)

这个怎么样?

var sales = from s in db.Sales
            from c in db.Calendars.DefaultIfEmpty()
            where
                s.SaleDate >= c.CalendarDate && s.SaleDate < c.NextDayDateTime
                && s.SaleDate >= sinceDate && s.SaleDate < dateEnd

修改 你可以创建这样的辅助类:

class CalendarSealesHelper
{
   public DateTime CalendarDate {get; set;}
   public DateTime NextDayDateTime {get; set;}
}

class CalendarSealesHelperComparer : IEqualityComparer<CalendarSealesHelper>
{
    public bool Equals(CalendarSealesHelper c1, CalendarSealesHelper c2)
    {
        if (c2.CalendarDate >= c1.CalendarDate 
               && c2.NextDayDateTime < c1.NextDayDateTime)
        {
            return true;
        }
        else
        {
            return false;
        }
    }


    public int GetHashCode(CalendarSealesHelper c)
    {
        int hCode = (int)c.CalendarDate.Ticks ^ (int)c.NextDayDateTime.Ticks;
        return hCode.GetHashCode();
    }
}

然后试试这个:

var query = db.Calendars.GroupJoin(
         db.Sales,
         c => new CalendarSealesHelper{c.CalendarDate, c.NextDayDateTime},
         s => new CalendarSealesHelper{s.SaleDate, s.SaleDate},
         (c, s) => new {Calendars = c, Sales = s},
         new CalendarSealesHelperComparer())
    .SelectMany(s => s.Sales.DefaultIfEmpty(),
            (c, s) => new {
                            CalendarDate = c.CalendarDate,
                            FirstDayOfWeek = c.FirstDayOfWeek,
                            FirstDayOfMonth = c.FirstDayOfMonth,
                            Total = s.Total,
                            SaleDate = s.SaleDate
                          })
    .Where(r => r.SaleDate >= sinceDate && r.SaleDate <= dateEnd);