【问题标题】:Left Outer Calendar Table Join with LINQ-to-SQL使用 LINQ-to-SQL 连接左外日历表
【发布时间】:2012-12-05 15:37:03
【问题描述】:

如何针对我的 CalendarSales 表编写以下 LEFT OUTER JOIN 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

我设法让 inner join 在 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)
                  };

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

【问题讨论】:

  • 您的 SQL 语句不会运行 LEFT OUTER JOIN,因为您在 WHERE 语句中使用 Sales 表而不是进行 NULL 检查。
  • @cjk,已修复。感谢您指出这一点(我的结局就是这样)。也许如果我添加一个??对于我的 LINQ 查询,它会推断出左外连接?

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


【解决方案1】:

这个怎么样?

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); 

【讨论】:

  • db.Calendar.DefaultIfEmpty() 为带有ON 1=1 的日历生成LEFT OUTER JOIN,但不幸的是不在日期范围内。尝试切换它并同时打开它,但都不起作用。
  • 谢谢哈姆雷特。不幸的是,GroupJoin 抛出 NotSupportedException:“用于查询运算符 'GroupJoin' 的重载不受支持。”我认为不可能将自定义比较器具体化为 SQL。
  • 我相信,这是可能的。你能通过脚本(用过的表)给我提供任何测试数据和数据库方案吗?
猜你喜欢
  • 2013-06-13
  • 1970-01-01
  • 2011-10-14
  • 1970-01-01
  • 2013-09-09
  • 2010-09-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多