在DB中,我有一个BookingRooms集合,其中包含Checkin和Checkout日期,请说:
ID |签到|结帐
1 | 2017/01/01 | 2017年3月1日
2 | 29/01/2017 | 2017年3月2日
2 | 2017/02/04 | 2017年5月2日
(格式为dd / MM / yyyy)
现在我想统计每个可衡量月份的预订数量,结果如下:
ID |区域|夜
1 | 01/2017 | 5
2 | 02/2017 | 3
var result = (from boo in context.BookingRooms
group boo by new { boo.CheckIn.Year, boo.CheckIn.Month } into book
orderby book.Key.Year descending, book.Key.Month descending
select new NightsPerMonth
{
Area = book.Key.Month + " / " + book.Key.Year,
Nights = ??
}).ToList();
这就是我到目前为止所遇到的问题,但问题是,如果我通过办理登机手续将其分组,那些在前几个月登记入住的人将不会加入团队,如果我能成功分组我不知道如何通过DbFunctions计算当前分组月份的夜晚(避免在前一个月或下个月计算夜晚,即使Checkout或Checkin在当月之外),因此LINQ to SQL不会失败。
任何建议的答案
答案 0 :(得分:1)
我认为你的要求与linq查询相当复杂。 我建议采用两种方法来解决它。
方法1: 这是我的sql查询获取欲望结果,你可以创建存储过程或函数来使用它。
DECLARE @SampleData AS TABLE (Id int IDENTITY (1,1), Checkin Date, Checkout date)
INSERT INTO @SampleData VALUES ('2017-01-01', '2017-01-03'), ('2017-01-29', '2017-02-03'), ('2017-02-04', '2017-02-05')
;WITH temps AS
(
SELECT CAST(MIN(sd.Checkin) AS Date) AS MinCheckDate, CAST(max(sd.Checkout) AS Date) as MaxCheckDate
FROM @SampleData sd
)
-- Calculate all months from min-checkin-date to max-checkout-date.
-- By Recursive function
,allMonth AS
(
SELECT datepart(month,t.MinCheckDate) AS [Month],
datepart(year, t.MinCheckDate) AS [Year],
datefromparts(datepart(year, t.MinCheckDate) , datepart(month, t.MinCheckDate) ,1) AS StartMonthDate ,
EOMONTH(datefromparts(datepart(year, t.MinCheckDate) , datepart(month, t.MinCheckDate) ,1)) AS EndMonthDate
FROM temps t
UNION ALL
SELECT datepart(month,dateadd(month, 1, am.StartMonthDate)) AS [Month],
datepart(year, dateadd(month, 1, am.StartMonthDate)) AS [Year],
datefromparts(datepart(year, dateadd(month, 1, am.StartMonthDate)) , datepart(month, dateadd(month, 1, am.StartMonthDate)) ,1) AS StartMonthDate ,
EOMONTH(datefromparts(datepart(year, dateadd(month, 1, am.StartMonthDate)) , datepart(month, dateadd(month, 1, am.StartMonthDate)) ,1)) AS EndMonthDate
FROM allMonth am
CROSS JOIN temps t
WHERE dateadd(month, 1, am.StartMonthDate) <= t.MaxCheckDate
)
SELECT CONCAT(am.[Month],'/',am.[Year]) AS Area,
SUM(
DATEDIFF(day,
CAST(IIF( am.StartMonthDate <= sd.Checkin, sd.Checkin, am.StartMonthDate) AS DATE),
CAST(IIF( am.EndMonthDate < sd.Checkout , dateadd(dd, 1,am.EndMonthDate), sd.Checkout) AS date) -- if Checkout > End of month, then End of month will be calculate as a night
) ) AS Nights
FROM allMonth am
LEFT JOIN @SampleData sd ON am.StartMonthDate BETWEEN sd.Checkin AND sd.Checkout OR am.EndMonthDate BETWEEN sd.Checkin AND sd.Checkout
OR sd.Checkin BETWEEN am.StartMonthDate AND am.EndMonthDate OR sd.Checkout BETWEEN am.StartMonthDate AND am.EndMonthDate
GROUP BY am.[Month],am.[Year]
OPTION (MAXRECURSION 0)
演示链接:Rextester
方法2:
您可以从BookingRooms表加载所有数据并在C#上计算夜晚:
var lstBookRooms = (from boo in context.BookingRooms
select new BookingRooms
{
Id = boo.Id,
Checkin = boo.CheckIn,
Checkout = boo.CheckOut
}).ToList();
var lstNightsPerMonth = GetNightsPerMonth(lstBookRooms);
类
public class BookingRooms
{
public int Id { get; set; }
public DateTime Checkin { get; set; }
public DateTime Checkout { get; set; }
}
public class NightsPerMonth
{
public string Area
{
get
{
return string.Format("{0}/{1}", Month, Year);
}
}
public int Month { get; set; }
public int Year { get; set; }
public int Nights { get; set; }
}
和功能
public List<NightsPerMonth> GetNightsPerMonth(List<BookingRooms> lstBookRooms)
{
if (lstBookRooms == null || lstBookRooms.Count == 0) return null;
var result = new List<NightsPerMonth>();
var minCheckin = lstBookRooms.Min(x => x.Checkin);
var maxCheckout = lstBookRooms.Max(x => x.Checkout);
var currentMonth = minCheckin;
while (currentMonth <= maxCheckout)
{
result.Add(new NightsPerMonth
{
Month = currentMonth.Month,
Year = currentMonth.Year,
Nights = GetNumberNightsOfMonth(currentMonth, lstBookRooms)
});
currentMonth = currentMonth.AddMonths(1);
}
return result;
}
private int GetNumberNightsOfMonth(DateTime currentMonth, List<BookingRooms> lstBookRooms)
{
var startDateOfMonth = new DateTime(currentMonth.Year, currentMonth.Month, 1);
var endDateOfMonth = startDateOfMonth.AddMonths(1).AddDays(-1);
return lstBookRooms.Where(x => IsBookRoom(startDateOfMonth, endDateOfMonth, x.Checkin, x.Checkout))
.Sum(x => NumberNightsBookRoom(startDateOfMonth, endDateOfMonth, x.Checkin, x.Checkout));
}
private bool IsBookRoom(DateTime startDateOfMonth, DateTime endDateOfMonth, DateTime checkin, DateTime checkout)
{
if (startDateOfMonth >= checkin && startDateOfMonth <= checkout) return true;
if (endDateOfMonth >= checkin && endDateOfMonth <= checkout) return true;
if (checkin >= startDateOfMonth && checkin <= endDateOfMonth) return true;
if (checkout >= startDateOfMonth && checkout <= endDateOfMonth) return true;
return false;
}
private int NumberNightsBookRoom(DateTime startDateOfMonth, DateTime endDateOfMonth, DateTime checkin, DateTime checkout)
{
var startTimeSpan = startDateOfMonth <= checkin ? checkin : startDateOfMonth;
// if Checkout > End of month, then End of month will be calculate as a night
var endTimeSpan = endDateOfMonth < checkout ? endDateOfMonth.AddDays(1) : checkout;
return (endTimeSpan - startTimeSpan).Days;
}
希望它有所帮助......